Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
 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);
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
        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);
            }
        }
Esempio n. 6
0
        public static int Next(this AbstractString str, int offset)
        {
            var ch = str[offset];

            if (char.IsHighSurrogate(ch))
            {
                return(offset + 2);
            }
            else
            {
                return(offset + 1);
            }
        }
Esempio n. 7
0
        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());
            }
        }
Esempio n. 8
0
 public static CodepointEnumerable Codepoints(this AbstractString str, int startOffset = 0)
 {
     return(new CodepointEnumerable(str, startOffset));
 }
Esempio n. 9
0
        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));
            }
        }
Esempio n. 10
0
        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
            });
        }
Esempio n. 11
0
 public ControlBuilder <StaticText> Text(AbstractString text, AbstractTooltipContent tooltip = default, ControlFlags?layoutFlags = null)
 {
     return(this.Text <StaticText>(text, tooltip, layoutFlags));
 }
Esempio n. 12
0
        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
                       ));
        }