public static IAsyncResult SetTextBlockWithKey(TextBlock control, string key, string defaultText) { if (control == null || key == null) { throw new ArgumentNullException(); } textControls[control.GetHashCode()] = key; return(GetTextAsync(key, defaultText, (s) => { lock (textControls) { if (textControls[control.GetHashCode()] == key) { control.Text = s; } } })); }
public TextExtents MeasureText(ref TextBlock block, TextQuality quality) { // First, check if we have cached this text block. Do not use block_cache.TryGetValue, to avoid thrashing // the user's TextBlockExtents struct. int hashcode = block.GetHashCode(); if (block_cache.ContainsKey(hashcode)) return block_cache[hashcode]; // If this block is not cached, we have to measure it and (potentially) place it in the cache. TextExtents extents = MeasureTextExtents(ref block, quality); if ((block.Options & TextPrinterOptions.NoCache) == 0) block_cache.Add(hashcode, extents); return extents; }
public void Print(ref TextBlock block, Color color, IGlyphRasterizer rasterizer) { GL.PushAttrib(AttribMask.CurrentBit | AttribMask.TextureBit | AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.DepthBufferBit); GL.Enable(EnableCap.Texture2D); GL.Enable(EnableCap.Blend); SetBlendFunction(); GL.Disable(EnableCap.DepthTest); GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)All.Modulate); GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvColor, new Color4(0, 0, 0, 0)); GL.Disable(EnableCap.TextureGenQ); GL.Disable(EnableCap.TextureGenR); GL.Disable(EnableCap.TextureGenS); GL.Disable(EnableCap.TextureGenT); RectangleF position; SetColor(color); int block_hash = block.GetHashCode(); if (block_cache.ContainsKey(block_hash)) { GL.CallList(block_cache[block_hash]); } else { using (TextExtents extents = rasterizer.MeasureText(ref block)) { // Build layout int current = 0; foreach (Glyph glyph in block) { // Do not render whitespace characters or characters outside the clip rectangle. if (glyph.IsWhiteSpace || extents[current].Width == 0 || extents[current].Height == 0) { current++; continue; } else if (!Cache.Contains(glyph)) Cache.Add(glyph, rasterizer, TextQuality); CachedGlyphInfo info = Cache[glyph]; position = extents[current++]; // Use the real glyph width instead of the measured one (we want to achieve pixel perfect output). position.Size = info.Rectangle.Size; if (!active_lists.ContainsKey(info.Texture)) { if (inactive_lists.Count > 0) { List<Vector2> list = inactive_lists.Dequeue(); list.Clear(); active_lists.Add(info.Texture, list); } else { active_lists.Add(info.Texture, new List<Vector2>()); } } { // Interleaved array: Vertex, TexCoord, Vertex, ... List<Vector2> current_list = active_lists[info.Texture]; current_list.Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Top)); current_list.Add(new Vector2(position.Left, position.Top)); current_list.Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Bottom)); current_list.Add(new Vector2(position.Left, position.Bottom)); current_list.Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom)); current_list.Add(new Vector2(position.Right, position.Bottom)); current_list.Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Bottom)); current_list.Add(new Vector2(position.Right, position.Bottom)); current_list.Add(new Vector2(info.RectangleNormalized.Right, info.RectangleNormalized.Top)); current_list.Add(new Vector2(position.Right, position.Top)); current_list.Add(new Vector2(info.RectangleNormalized.Left, info.RectangleNormalized.Top)); current_list.Add(new Vector2(position.Left, position.Top)); } } } // Render int display_list = 0; if ((block.Options & TextPrinterOptions.NoCache) == 0) { display_list = GL.GenLists(1); // Mesa Indirect gerates an InvalidOperation error right after // GL.EndList() when using ListMode.CompileAndExecute. // Using ListMode.Compile as a workaround. GL.NewList(display_list, ListMode.Compile); } foreach (Texture2D key in active_lists.Keys) { List<Vector2> list = active_lists[key]; key.Bind(); GL.Begin(BeginMode.Triangles); for (int i = 0; i < list.Count; i += 2) { GL.TexCoord2(list[i]); GL.Vertex2(list[i + 1]); } GL.End(); } if ((block.Options & TextPrinterOptions.NoCache) == 0) { GL.EndList(); block_cache.Add(block_hash, display_list); GL.CallList(display_list); } // Clean layout foreach (List<Vector2> list in active_lists.Values) { //list.Clear(); inactive_lists.Enqueue(list); } active_lists.Clear(); } GL.PopAttrib(); }