public ControlBuilder <StaticText> Label(AbstractString text, AbstractTooltipContent tooltip = default, ControlFlags?layoutFlags = null) { var result = this.Text <StaticText>(text, tooltip, layoutFlags); WaitingForFocusBeneficiary = result.Control; return(result); }
public ControlBuilder <TControl> Text <TControl> (AbstractString text, AbstractTooltipContent tooltip = default, ControlFlags?layoutFlags = null) where TControl : Control, new() { var result = New <TControl>(layoutFlags); result.SetText(text); if (tooltip != default) { result.SetTooltip(tooltip); } return(result); }
private MarkedStringAction ProcessMarkedString(ref AbstractString text, string id, ref RichTextLayoutState state, ref StringLayoutEngine layoutEngine) { if (text.TextEquals("quick")) { layoutEngine.overrideColor = Color.GreenYellow; text = "slow"; } else if (text.TextEquals("rich substring")) { text = "<$[scale:2.0]b$[scale:1.66]i$[scale:1.33]g$[scale:1.0] rich substring>"; return(MarkedStringAction.RichText); } return(default);
public static uint?NthCodepoint(AbstractString str, int codepointIndex, int relativeToCharacterIndex = 0) { foreach (var cp in str.Codepoints(relativeToCharacterIndex)) { if (codepointIndex == 0) { return(cp.Codepoint); } codepointIndex--; } return(null); }
public static int Previous(this AbstractString str, int offset) { var ch = str[offset - 1]; if (char.IsLowSurrogate(ch)) { return(offset - 2); } else { return(offset - 1); } }
public static int Next(this AbstractString str, int offset) { var ch = str[offset]; if (char.IsHighSurrogate(ch)) { return(offset + 2); } else { return(offset + 1); } }
public static StringLayout LayoutString( this SpriteFont font, AbstractString text, ArraySegment <BitmapDrawCall>?buffer = null, Vector2?position = null, Color?color = null, float scale = 1, DrawCallSortKey sortKey = default(DrawCallSortKey), int characterSkipCount = 0, int?characterLimit = null, float xOffsetOfFirstLine = 0, float?lineBreakAtX = null, GlyphPixelAlignment alignToPixels = default(GlyphPixelAlignment), Dictionary <char, KerningAdjustment> kerningAdjustments = null, bool wordWrap = false, char wrapCharacter = '\0' ) { var state = new StringLayoutEngine { position = position, color = color, scale = scale, sortKey = sortKey, characterSkipCount = characterSkipCount, characterLimit = characterLimit, xOffsetOfFirstLine = xOffsetOfFirstLine, lineBreakAtX = lineBreakAtX, alignToPixels = alignToPixels, characterWrap = lineBreakAtX.HasValue, wordWrap = wordWrap, wrapCharacter = wrapCharacter, buffer = buffer.GetValueOrDefault(default(ArraySegment <BitmapDrawCall>)) }; var gs = new SpriteFontGlyphSource(font); state.Initialize(); using (state) { var segment = state.AppendText( gs, text, kerningAdjustments ); return(state.Finish()); } }
public static CodepointEnumerable Codepoints(this AbstractString str, int startOffset = 0) { return(new CodepointEnumerable(str, startOffset)); }
public static Pair <int> FindWordBoundary(AbstractString str, int?searchFromCodepointIndex = null, int?searchFromCharacterIndex = null) { int firstWhitespaceCharacter = -1, lastWhitespaceCharacter = -1, firstWordCharacter = -1, lastWordCharacter = -1; if ((searchFromCharacterIndex == null) && (searchFromCodepointIndex == null)) { throw new ArgumentException("Either a starting codepoint index or character index must be provided"); } bool searchStartedInWhiteSpace = false, inWord = false; foreach (var cp in str.Codepoints()) { bool transitioned = false; var isWhiteSpace = IsWhiteSpace(cp.Codepoint); if ( (cp.CodepointIndex == searchFromCodepointIndex) || (cp.CharacterIndex == searchFromCharacterIndex) ) { searchStartedInWhiteSpace = isWhiteSpace; } if (isWhiteSpace) { if (inWord || firstWhitespaceCharacter < 0) { transitioned = inWord; inWord = false; firstWhitespaceCharacter = cp.CharacterIndex; } lastWhitespaceCharacter = cp.CharacterIndex; } else { if (!inWord || firstWordCharacter < 0) { transitioned = !inWord; inWord = true; firstWordCharacter = cp.CharacterIndex; } lastWordCharacter = cp.CharacterIndex; } if (transitioned && ( (searchFromCodepointIndex.HasValue && (cp.CodepointIndex > searchFromCodepointIndex)) || (searchFromCharacterIndex.HasValue && (cp.CharacterIndex > searchFromCharacterIndex)) ) ) { break; } } if (searchStartedInWhiteSpace) { return(new Pair <int>(firstWhitespaceCharacter, lastWhitespaceCharacter + 1)); } else { if ((lastWordCharacter > 0) && char.IsHighSurrogate(str[lastWordCharacter])) { lastWordCharacter++; } return(new Pair <int>(firstWordCharacter, lastWordCharacter + 1)); } }
private void RasterizeAcceleratorOverlay( UIOperationContext context, ref ImperativeRenderer labelRenderer, ref ImperativeRenderer targetRenderer, Control control, AbstractString label, bool showFocused = false, Control forControl = null ) { if (control == null) { return; } if (!showFocused && (control == Focused) && !label.IsNull && (label.Length > 0)) { return; } if (label.Length <= 0) { return; } var box = control.GetRect(); if ((box.Width <= 1) || (box.Height <= 1)) { return; } var decorator = Decorations.AcceleratorTarget; var settings = new Decorations.DecorationSettings { Box = box, ContentBox = box }; decorator.Rasterize(ref context, ref targetRenderer, settings); var outlinePadding = 1f; decorator = Decorations.AcceleratorLabel; Color?textColor = null; decorator.GetTextSettings(ref context, default(ControlStates), out Material material, ref textColor, out _); var layout = decorator.GlyphSource.LayoutString(label, buffer: AcceleratorOverlayBuffer); var textScale = 1f; if (layout.Size.X > (box.Width - decorator.Padding.X)) { textScale = Math.Max(0.25f, (box.Width - decorator.Padding.X) / layout.Size.X); } var scaledSize = layout.Size * textScale; var labelTraits = new DenseList <string> { "above" }; var labelPosition = box.Position - new Vector2(0, scaledSize.Y + decorator.Padding.Y + outlinePadding); if (labelPosition.Y <= 0) { labelTraits[0] = "inside"; labelPosition = box.Position; } labelPosition.X = Arithmetic.Clamp(labelPosition.X, 0, CanvasSize.X - scaledSize.X); labelPosition.Y = Math.Max(0, labelPosition.Y); var labelBox = new RectF( labelPosition, scaledSize + decorator.Padding.Size ); if (IsObstructedByAnyPreviousBox(ref labelBox, forControl)) { labelBox.Left = box.Extent.X - labelBox.Width; } if (IsObstructedByAnyPreviousBox(ref labelBox, forControl)) { labelTraits[0] = "below"; labelBox.Left = labelPosition.X; labelBox.Top = box.Extent.Y + 1; // FIXME: Why the +1? } while (IsObstructedByAnyPreviousBox(ref labelBox, forControl)) { labelTraits[0] = "stacked"; labelBox.Left = box.Left; labelBox.Width = box.Width; labelBox.Top = labelBox.Extent.Y + 0.5f; } // HACK var labelContentBox = new RectF( labelBox.Position + new Vector2(decorator.Padding.Left, decorator.Padding.Top), scaledSize ); settings = new Decorations.DecorationSettings { Box = labelBox, ContentBox = box, Traits = labelTraits }; decorator.Rasterize(ref context, ref labelRenderer, settings); labelRenderer.DrawMultiple(layout.DrawCalls, offset: labelContentBox.Position.Floor(), scale: new Vector2(textScale), layer: 1); RasterizedOverlayBoxes.Add(new RasterizedOverlayBox { Control = forControl, ControlBox = box, LabelBox = labelBox }); }
public ControlBuilder <StaticText> Text(AbstractString text, AbstractTooltipContent tooltip = default, ControlFlags?layoutFlags = null) { return(this.Text <StaticText>(text, tooltip, layoutFlags)); }
public static StringLayout LayoutString( this SpriteFont font, AbstractString text, ArraySegment <BitmapDrawCall>?buffer = null, Vector2?position = null, Color?color = null, float scale = 1, float sortKey = 0, int characterSkipCount = 0, int characterLimit = int.MaxValue, float xOffsetOfFirstLine = 0, float?lineBreakAtX = null, bool alignToPixels = false, Dictionary <char, KerningAdjustment> kerningAdjustments = null ) { if (text.IsNull) { throw new ArgumentNullException("text"); } ArraySegment <BitmapDrawCall> _buffer; if (buffer.HasValue) { _buffer = buffer.Value; } else { _buffer = new ArraySegment <BitmapDrawCall>(new BitmapDrawCall[text.Length]); } if (_buffer.Count < text.Length) { throw new ArgumentException("buffer too small", "buffer"); } if (kerningAdjustments == null) { kerningAdjustments = StringLayout.GetDefaultKerningAdjustments(font); } var spacing = font.Spacing; var lineSpacing = font.LineSpacing; var glyphSource = font.GetGlyphSource(); var actualPosition = position.GetValueOrDefault(Vector2.Zero); var characterOffset = new Vector2(xOffsetOfFirstLine, 0); var totalSize = Vector2.Zero; Bounds firstCharacterBounds = default(Bounds), lastCharacterBounds = default(Bounds); var drawCall = new BitmapDrawCall( glyphSource.Texture, default(Vector2), default(Bounds), color.GetValueOrDefault(Color.White), scale ); drawCall.SortKey = sortKey; float rectScaleX = 1f / glyphSource.Texture.Width; float rectScaleY = 1f / glyphSource.Texture.Height; int bufferWritePosition = _buffer.Offset; int drawCallsWritten = 0; bool firstCharacterEver = true; bool firstCharacterOfLine = true; for (int i = 0, l = text.Length; i < l; i++) { var ch = text[i]; var lineBreak = false; if (ch == '\r') { if (((i + 1) < l) && (text[i + 1] == '\n')) { i += 1; } lineBreak = true; } else if (ch == '\n') { lineBreak = true; } bool deadGlyph; Glyph glyph; deadGlyph = !glyphSource.GetGlyph(ch, out glyph); KerningAdjustment kerningAdjustment; if ((kerningAdjustments != null) && kerningAdjustments.TryGetValue(ch, out kerningAdjustment)) { glyph.LeftSideBearing += kerningAdjustment.LeftSideBearing; glyph.Width += kerningAdjustment.Width; glyph.RightSideBearing += kerningAdjustment.RightSideBearing; } if (!deadGlyph) { var x = characterOffset.X + glyph.LeftSideBearing + glyph.RightSideBearing + glyph.Width + spacing; if (x >= lineBreakAtX) { lineBreak = true; } } if (lineBreak) { characterOffset.X = 0; characterOffset.Y += lineSpacing; firstCharacterOfLine = true; } if (deadGlyph) { characterSkipCount--; characterLimit--; continue; } characterOffset.X += spacing; lastCharacterBounds = Bounds.FromPositionAndSize( characterOffset, new Vector2( glyph.LeftSideBearing + glyph.Width + glyph.RightSideBearing, font.LineSpacing ) ); if (firstCharacterEver) { firstCharacterBounds = lastCharacterBounds; firstCharacterEver = false; } characterOffset.X += glyph.LeftSideBearing; if (firstCharacterOfLine) { characterOffset.X = Math.Max(characterOffset.X, 0); firstCharacterOfLine = false; } if (characterSkipCount <= 0) { if (characterLimit <= 0) { break; } var glyphPosition = new Vector2( actualPosition.X + (glyph.Cropping.X + characterOffset.X) * scale, actualPosition.Y + (glyph.Cropping.Y + characterOffset.Y) * scale ); drawCall.TextureRegion = glyphSource.Texture.BoundsFromRectangle(ref glyph.BoundsInTexture); if (alignToPixels) { drawCall.Position = glyphPosition.Floor(); } else { drawCall.Position = glyphPosition; } _buffer.Array[bufferWritePosition] = drawCall; bufferWritePosition += 1; drawCallsWritten += 1; characterLimit--; } else { characterSkipCount--; } characterOffset.X += (glyph.Width + glyph.RightSideBearing); totalSize.X = Math.Max(totalSize.X, characterOffset.X); totalSize.Y = Math.Max(totalSize.Y, characterOffset.Y + font.LineSpacing); } var segment = new ArraySegment <BitmapDrawCall>( _buffer.Array, _buffer.Offset, drawCallsWritten ); if (segment.Count > text.Length) { throw new InvalidDataException(); } return(new StringLayout( position.GetValueOrDefault(), totalSize, font.LineSpacing, firstCharacterBounds, lastCharacterBounds, segment )); }