Exemplo n.º 1
0
        public static float XOffsetForGlyphIndex <TFont, TGlyph>
            (this AttributedGlyphRun <TFont, TGlyph> line, TypesettingContext <TFont, TGlyph> context, int index)
            where TFont : IFont <TGlyph>
        {
            if (index < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(index), index, "The index is negative.");
            }
            int   i        = 0;
            float x        = 0;
            var   advances =
                context.GlyphBoundsProvider.GetAdvancesForGlyphs(line.Font, line.Glyphs, line.Length).Advances;

            foreach (var(advance, kernAfter) in
                     advances.Zip(line.GlyphInfos.Select(g => g.KernAfterGlyph), ValueTuple.Create))
            {
                if (i++ >= index)
                {
                    return(x);
                }
                else
                {
                    x += advance + kernAfter;
                }
            }
            throw new ArgumentOutOfRangeException(nameof(index), index, "The index is beyond the end of the string.");
        }
Exemplo n.º 2
0
        public static MathListIndex?IndexForPoint <TFont, TGlyph>
            (this TextLineDisplay <TFont, TGlyph> self, TypesettingContext <TFont, TGlyph> context, PointF point)
            where TFont : IFont <TGlyph>
        {
            // Convert the point to the reference of the CTLine
            var relativePoint   = new PointF(point.X - self.Position.X, point.Y - self.Position.Y);
            var runsAndIndicies =
                self.Runs
                .Select(run => (run, run.Run.GlyphIndexForXOffset(context, relativePoint.Plus(run.Position).X)))
                .Where(x => x.Item2.HasValue)
                .ToArray();

            if (runsAndIndicies.Length == 0)
            {
                return(null);
            }
            var(r, nindex) = runsAndIndicies.Single();
            var index   = nindex.GetValueOrDefault();
            var diffLng = r.Run.Length != r.Range.Length;

            if (index < 0 || (!diffLng && index > self.Range.Length) || (diffLng && index > r.Run.Length))
            {
                throw new InvalidCodePathException
                          ($"Returned index out of range: {index}, range ({self.Range.Location}, {self.Range.Length})");
            }
            return(diffLng
        ? index > r.Run.Length / 2
          ? MathListIndex.Level0Index(self.Range.End)
          : MathListIndex.Level0Index(self.Range.Location)
        : MathListIndex.Level0Index(self.Range.Location + index));
        }
Exemplo n.º 3
0
   public static MathListIndex IndexForPoint <TFont, TGlyph>(
       this IGlyphDisplay <TFont, TGlyph> self,
       TypesettingContext <TFont, TGlyph> _,
       PointF point) where TFont : IFont <TGlyph> =>
   point.X > self.Position.X + self.Width / 2
 ? MathListIndex.Level0Index(self.Range.End)
   : MathListIndex.Level0Index(self.Range.Location);
Exemplo n.º 4
0
 public AppleMathView(TypesettingContext <TFont, TGlyph> typesettingContext, float fontSize)
 {
     Layer.GeometryFlipped = true;
     BackgroundColor       = NColor.FromRGB(0.9f, 0.9f, 0.9f);
     TextColor             = NColor.Black;
     FontSize            = fontSize;
     _typesettingContext = typesettingContext;
 }
Exemplo n.º 5
0
 public TextLineDisplay(
     AttributedString <TFont, TGlyph> text, Range range,
     TypesettingContext <TFont, TGlyph> context, IReadOnlyList <MathAtom> atoms, PointF position) : this(
         text.Runs.Select(run =>
                          new TextRunDisplay <TFont, TGlyph>(run, new Range(range.Location, run.Length), context)
                          ).ToList(), atoms, position)
 {
 }
Exemplo n.º 6
0
   public static PointF?PointForIndex <TFont, TGlyph>(
       this IGlyphDisplay <TFont, TGlyph> self,
       TypesettingContext <TFont, TGlyph> _,
       MathListIndex index) where TFont : IFont <TGlyph> =>
   index.SubIndexType != MathListSubIndexType.None
 ? throw new ArgumentException
             ("The subindex must be none to get the closest point for it.", nameof(index))
         : index.AtomIndex == self.Range.End
         // draw a caret after the glyph
 ? self.Position.Plus(new PointF(self.DisplayBounds().Right, 0))
         // draw a caret before the glyph
         : self.Position;
Exemplo n.º 7
0
 public MathKeyboard(TypesettingContext <TFont, TGlyph> context, TFont font, double blinkMilliseconds = DefaultBlinkMilliseconds)
 {
     Context             = context;
     Font                = font;
     blinkTimer          = new Timer(blinkMilliseconds);
     blinkTimer.Elapsed += (sender, e) => {
         if (!(MathList.AtomAt(_insertionIndex) is Atoms.Placeholder) || LaTeXSettings.PlaceholderBlinks)
         {
             InsertionPositionHighlighted = !InsertionPositionHighlighted;
         }
     };
     blinkTimer.Start();
 }
Exemplo n.º 8
0
   public static MathListIndex IndexForPoint <TFont, TGlyph>(
       this LargeOpLimitsDisplay <TFont, TGlyph> self,
       TypesettingContext <TFont, TGlyph> context,
       PointF point) where TFont : IFont <TGlyph> =>
   // We can be before or after the large operator
   point.X <self.Position.X - PixelDelta
            // We are before the large operator, so
            ?MathListIndex.Level0Index(self.Range.Location)
            : point.X> self.Position.X + self.Width + PixelDelta
   // We are after the large operator
 ? MathListIndex.Level0Index(self.Range.End)
   : self.UpperLimit is
   {
Exemplo n.º 9
0
        public TextRunDisplay(
            AttributedGlyphRun <TFont, TGlyph> run,
            Range range,
            TypesettingContext <TFont, TGlyph> context)
        {
            var font = run.Font;

            Run   = run;
            Range = range;

            Width = context.GlyphBoundsProvider.GetTypographicWidth(font, run);
            _ComputeAscentDescent(context, font);
        }
Exemplo n.º 10
0
   public static MathListIndex IndexForPoint <TFont, TGlyph>(
       this InnerDisplay <TFont, TGlyph> self,
       TypesettingContext <TFont, TGlyph> context,
       PointF point) where TFont : IFont <TGlyph> =>
   // We can be before or after the inner
   point.X <self.Position.X + (self.Left?.Width / 2 ?? 0)
            //We are before the inner, so
 ? MathListIndex.Level0Index(self.Range.Location)
            : point.X> self.Position.X + self.Width - (self.Right?.Width / 2 ?? 0)
   //We are after the inner
 ? MathListIndex.Level0Index(self.Range.End)
   : MathListIndex.IndexAtLocation(self.Range.Location,
                                   MathListSubIndexType.Inner, self.Inner.IndexForPoint(context, point));
Exemplo n.º 11
0
        public TextRunDisplay(
            AttributedGlyphRun <TFont, TGlyph> run,
            Range range,
            TypesettingContext <TFont, TGlyph> context)
        {
            var font = run.Font;

            Run   = run;
            Range = range;
            Width = context.GlyphBoundsProvider.GetTypographicWidth(font, run);
            // Compute ascent and descent
            var rects =
                context.GlyphBoundsProvider.GetBoundingRectsForGlyphs(font, Run.Glyphs, Run.GlyphInfos.Count);

            Ascent  = rects.IsEmpty() ? 0 : rects.Max(rect => rect.Bottom); // Convert to non-flipped naming here,
            Descent = rects.IsEmpty() ? 0 : rects.Max(rect => - rect.Y);
        }
Exemplo n.º 12
0
   public static MathListIndex IndexForPoint <TFont, TGlyph>(
       this RadicalDisplay <TFont, TGlyph> self,
       TypesettingContext <TFont, TGlyph> context,
       PointF point) where TFont : IFont <TGlyph> =>
   // We can be before or after the radical
   point.X <self.Position.X - PixelDelta
            //We are before the radical, so
            ?MathListIndex.Level0Index(self.Range.Location)
            : point.X> self.Position.X + self.Width + PixelDelta
   //We are after the radical
 ? MathListIndex.Level0Index(self.Range.End)
   //We can be either near the degree or the radicand
   : DistanceFromPointToRect(point, self.Degree != null ? new RectangleF(self.Degree.Position, self.Degree.DisplayBounds().Size) : default)
   < DistanceFromPointToRect(point, new RectangleF(self.Radicand.Position, self.Radicand.DisplayBounds().Size))
 ? self.Degree != null
   ? MathListIndex.IndexAtLocation(self.Range.Location, MathListSubIndexType.Degree, self.Degree.IndexForPoint(context, point))
   : MathListIndex.Level0Index(self.Range.Location)
   : MathListIndex.IndexAtLocation(self.Range.Location, MathListSubIndexType.Radicand, self.Radicand.IndexForPoint(context, point));
Exemplo n.º 13
0
        private void _ComputeAscentDescent(TypesettingContext <TFont, TGlyph> context, TFont font)
        {
            var   rects   = context.GlyphBoundsProvider.GetBoundingRectsForGlyphs(font, Run.Glyphs.AsForEach(), Run.GlyphInfos.Count);
            var   tops    = rects.Select(rect => rect.Bottom); // Convert to non-flipped naming here,
            var   bottoms = rects.Select(rect => rect.Y);
            float ascent  = 0;
            float descent = 0;

            foreach (var top in tops)
            {
                ascent = Math.Max(ascent, top);
            }
            foreach (var bottom in bottoms)
            {
                descent = Math.Max(descent, -bottom);
            }
            Ascent  = ascent;
            Descent = descent;
        }
Exemplo n.º 14
0
   public static MathListIndex IndexForPoint <TFont, TGlyph>(
       this FractionDisplay <TFont, TGlyph> self,
       TypesettingContext <TFont, TGlyph> context,
       PointF point) where TFont : IFont <TGlyph> =>
   // We can be before or after the fraction
   point.X <self.Position.X - PixelDelta
            //We are before the fraction, so
            ?MathListIndex.Level0Index(self.Range.Location)
            : point.X> self.Position.X + self.Width + PixelDelta
   //We are after the fraction
 ? MathListIndex.Level0Index(self.Range.End)
   : point.Y > self.LinePosition + PixelDelta
 ? MathListIndex.IndexAtLocation(self.Range.Location,
                                 MathListSubIndexType.Numerator, self.Numerator.IndexForPoint(context, point))
   : point.Y <self.LinePosition - PixelDelta
              ?MathListIndex.IndexAtLocation(self.Range.Location,
                                             MathListSubIndexType.Denominator, self.Denominator.IndexForPoint(context, point))
              : point.X> self.Position.X + self.Width / 2
 ? MathListIndex.Level0Index(self.Range.End)
   : MathListIndex.Level0Index(self.Range.Location);
Exemplo n.º 15
0
        public MathKeyboard(TypesettingContext <TFont, TGlyph> context, TFont font, double blinkMilliseconds = DefaultBlinkMilliseconds)
        {
            Context             = context;
            Font                = font;
            blinkTimer          = new Timer(blinkMilliseconds);
            blinkTimer.Elapsed += (sender, e) => {
                switch (CaretState)
                {
                case MathKeyboardCaretState.Shown:
                case MathKeyboardCaretState.ShownThroughPlaceholder:
                    CaretState = MathKeyboardCaretState.TemporarilyHidden;
                    break;

                case MathKeyboardCaretState.TemporarilyHidden:
                    CaretState = MathKeyboardCaretState.Shown;
                    break;
                }
            };
            blinkTimer.Start();
        }
Exemplo n.º 16
0
        public static TextLineDisplay <TFont, TGlyph> Create <TFont, TGlyph>(
            AttributedString <TFont, TGlyph> text,
            Range range,
            TypesettingContext <TFont, TGlyph> context,
            IEnumerable <IMathAtom> atoms
            )
            where TFont : MathFont <TGlyph>
        {
            int index = range.Location;
            List <TextRunDisplay <TFont, TGlyph> > textRuns = new List <TextRunDisplay <TFont, TGlyph> >();

            foreach (var run in text.Runs)
            {
                var innerRange = new Range(index, run.Length);
                var textRun    = new TextRunDisplay <TFont, TGlyph>(
                    run,
                    innerRange,
                    context
                    );
                textRuns.Add(textRun);
            }
            return(new TextLineDisplay <TFont, TGlyph>(textRuns, atoms));
        }
Exemplo n.º 17
0
        public static int?GlyphIndexForXOffset <TFont, TGlyph>
            (this AttributedGlyphRun <TFont, TGlyph> line, TypesettingContext <TFont, TGlyph> context, float offset)
            where TFont : IFont <TGlyph>
        {
            if (offset < 0)
            {
                return(0);      // Move cursor to index 0
            }
            if (line.Placeholder)
            {
                return(0);
            }
            int   i        = 0;
            float x        = 0;
            var   advances =
                context.GlyphBoundsProvider.GetAdvancesForGlyphs(line.Font, line.Glyphs, line.Length).Advances;

            foreach (var(advance, kernAfter) in
                     advances.Zip(line.GlyphInfos.Select(g => g.KernAfterGlyph), ValueTuple.Create))
            {
                if (x <= offset && offset < advance + x)
                {
                    return(Math.Abs(offset - x) < Math.Abs(advance + x - offset) ? i : i + 1);
                }
                else
                {
                    x += advance + kernAfter;
                    i++;
                    if (offset < x) // If the point is in the kern after this, then the index is the one after this
                    {
                        return(i);
                    }
                }
            }
            return(i);
        }
Exemplo n.º 18
0
        public static PointF?PointForIndex <TFont, TGlyph>(this ListDisplay <TFont, TGlyph> self, TypesettingContext <TFont, TGlyph> context, MathListIndex index) where TFont : IFont <TGlyph>
        {
            if (index is null)
            {
                return(null);
            }

            PointF?position;

            if (index.AtomIndex == self.Range.End)
            {
                // Special case the edge of the range
                position = new PointF(self.Width, 0);
            }
            else if (self.Range.Contains(index.AtomIndex) && self.SubDisplayForIndex(index) is IDisplay <TFont, TGlyph> display)
            {
                switch (index.SubIndexType)
                {
                case MathListSubIndexType.BetweenBaseAndScripts:
                    var nucleusPosition = index.AtomIndex + index.SubIndex.AtomIndex;
                    position = display.PointForIndex(context, MathListIndex.Level0Index(nucleusPosition));
                    break;

                case MathListSubIndexType.None:
                    position = display.PointForIndex(context, index);
                    break;

                default:
                    // Recurse
                    position = display.PointForIndex(context, index.SubIndex);
                    break;
                }
            }
            else
            {
                // Outside the range
                return(null);
            }
            if (position is PointF found)
            {
                // Convert bounds from our coordinate system before returning
                found.X += self.Position.X;
                found.Y += self.Position.Y;
                return(found);
            }
            else
            {
                // We didn't find the position
                return(null);
            }
        }
Exemplo n.º 19
0
 public MathKeyboard(TypesettingContext <TFont, TGlyph> context) => Context = context;
 public static PointF?PointForIndex <TFont, TGlyph>(this FractionDisplay <TFont, TGlyph> self, TypesettingContext <TFont, TGlyph> context, MathListIndex index) where TFont : IFont <TGlyph>
 {
     if (index.SubIndexType != MathListSubIndexType.None)
     {
         throw Arg("The subindex must be none to get the closest point for it.", nameof(index));
     }
     // draw a caret after the fraction
     return(new PointF(self.DisplayBounds.Right, self.Position.Y));
 }
Exemplo n.º 21
0
        public static PointF?PointForIndex <TFont, TGlyph>(this RadicalDisplay <TFont, TGlyph> self, TypesettingContext <TFont, TGlyph> context, MathListIndex index) where TFont : IFont <TGlyph>
        {
            if (index.SubIndexType != MathListSubIndexType.None)
            {
                throw Arg("The subindex must be none to get the closest point for it.", nameof(index));
            }

            if (index.AtomIndex == self.Range.End)
            {
                // draw a caret after the radical
                return(self.Position.Plus(new PointF(self.DisplayBounds.Right, 0)));
            }
            // draw a caret before the radical
            return(self.Position);
        }
Exemplo n.º 22
0
        public static MathListIndex?IndexForPoint <TFont, TGlyph>
            (this ListDisplay <TFont, TGlyph> self, TypesettingContext <TFont, TGlyph> context, PointF point)
            where TFont : IFont <TGlyph>
        {
            // The origin of for the subelements of a MathList is the current position,
            // so translate the current point to our origin.
            var translatedPoint = new PointF(point.X - self.Position.X, point.Y - self.Position.Y);

            IDisplay <TFont, TGlyph>?closest = null;
            var   xbounds     = new List <IDisplay <TFont, TGlyph> >();
            float minDistance = float.MaxValue;

            foreach (var display in self.Displays)
            {
                var bounds     = display.DisplayBounds();
                var rect       = new RectangleF(display.Position, bounds.Size);
                var maxBoundsX = rect.Right;
                if (rect.X - PixelDelta <= translatedPoint.X && translatedPoint.X <= maxBoundsX + PixelDelta)
                {
                    xbounds.Add(display);
                }
                var distance = DistanceFromPointToRect(translatedPoint, rect);
                if (distance < minDistance)
                {
                    closest     = display;
                    minDistance = distance;
                }
            }
            IDisplay <TFont, TGlyph>?displayWithPoint;

            switch (xbounds.Count)
            {
            case 0:
                if (translatedPoint.X <= -PixelDelta)
                {
                    // All the way to the left
                    return(self.Range.Location < 0
                   ? null
                   : MathListIndex.Level0Index(self.Range.Location));
                }
                else if (translatedPoint.X >= self.Width + PixelDelta)
                {
                    // if closest is a script
                    if (closest is ListDisplay <TFont, TGlyph> ld && ld.LinePosition != LinePosition.Regular)
                    {
                        // then we try to find its parent
                        var parent = self.Displays.FirstOrDefault(d => d.HasScript && d.Range.Contains(ld.IndexInParent));
                        if (parent != null)
                        {
                            return(MathListIndex.Level0Index(parent.Range.End));
                        }
                    }
                    // All the way to the right
                    return
                        (self.Range.End < 0
              ? null
              : self.Displays.Count == 1 &&
                         self.Displays[0] is TextLineDisplay <TFont, TGlyph> {
                        Atoms : var atoms
                    } &&
                         atoms.Count == 1 &&
                         atoms[0] is Atom.Atoms.Placeholder
              ? MathListIndex.Level0Index(self.Range.Location)
                         : MathListIndex.Level0Index(self.Range.End));
                }
Exemplo n.º 23
0
        public static MathListIndex IndexForPoint <TFont, TGlyph>(this RadicalDisplay <TFont, TGlyph> self, TypesettingContext <TFont, TGlyph> context, PointF point) where TFont : IFont <TGlyph>
        {
            // We can be before or after the radical
            if (point.X < self.Position.X - PixelDelta)
            {
                //We are before the radical, so
                return(MathListIndex.Level0Index(self.Range.Location));
            }
            else if (point.X > self.Position.X + self.Width + PixelDelta)
            {
                //We are after the radical
                return(MathListIndex.Level0Index(self.Range.End));
            }

            //We can be either near the degree or the radicand
            var degreeDistance   = DistanceFromPointToRect(point, self.Degree?.DisplayBounds ?? default);
            var radicandDistance = DistanceFromPointToRect(point, self.Radicand.DisplayBounds);

            if (degreeDistance < radicandDistance)
            {
                return(MathListIndex.IndexAtLocation(self.Range.Location, self.Degree.IndexForPoint(context, point), MathListSubIndexType.Numerator));
            }
            else
            {
                return(MathListIndex.IndexAtLocation(self.Range.Location, self.Radicand.IndexForPoint(context, point), MathListSubIndexType.Denominator));
            }
        }
        public static MathListIndex IndexForPoint <TFont, TGlyph>(this FractionDisplay <TFont, TGlyph> self, TypesettingContext <TFont, TGlyph> context, PointF point) where TFont : IFont <TGlyph>
        {
            // We can be before or after the fraction
            if (point.X < self.Position.X - PixelDelta)
            {
                //We are before the fraction, so
                return(MathListIndex.Level0Index(self.Range.Location));
            }
            else if (point.X > self.Position.X + self.Width + PixelDelta)
            {
                //We are after the fraction
                return(MathListIndex.Level0Index(self.Range.End));
            }

            //We can be either near the numerator or denominator
            var numeratorDistance   = DistanceFromPointToRect(point, self.Numerator.DisplayBounds);
            var denominatorDistance = DistanceFromPointToRect(point, self.Denominator.DisplayBounds);

            if (numeratorDistance < denominatorDistance)
            {
                return(MathListIndex.IndexAtLocation(self.Range.Location, self.Numerator.IndexForPoint(context, point), MathListSubIndexType.Numerator));
            }
            else
            {
                return(MathListIndex.IndexAtLocation(self.Range.Location, self.Denominator.IndexForPoint(context, point), MathListSubIndexType.Denominator));
            }
        }
Exemplo n.º 25
0
        public static MathListIndex IndexForPoint <TFont, TGlyph>(this RadicalDisplay <TFont, TGlyph> self, TypesettingContext <TFont, TGlyph> context, PointF point) where TFont : IFont <TGlyph>
        {
            // We can be before or after the radical
            if (point.X < self.Position.X - PixelDelta)
            {
                //We are before the radical, so
                return(MathListIndex.Level0Index(self.Range.Location));
            }
            else if (point.X > self.Position.X + self.Width + PixelDelta)
            {
                //We are after the radical
                return(MathListIndex.Level0Index(self.Range.End));
            }

            //We can be either near the degree or the radicand
            var degreeRect       = self.Degree != null ? new RectangleF(self.Degree.Position, self.Degree.DisplayBounds.Size) : default;
            var radicandRect     = new RectangleF(self.Radicand.Position, self.Radicand.DisplayBounds.Size);
            var degreeDistance   = DistanceFromPointToRect(point, degreeRect);
            var radicandDistance = DistanceFromPointToRect(point, radicandRect);

            if (degreeDistance < radicandDistance)
            {
                if (self.Degree != null)
                {
                    return(MathListIndex.IndexAtLocation(self.Range.Location, MathListSubIndexType.Degree, self.Degree.IndexForPoint(context, point)));
                }
                return(MathListIndex.Level0Index(self.Range.Location));
            }
            else
            {
                return(MathListIndex.IndexAtLocation(self.Range.Location, MathListSubIndexType.Radicand, self.Radicand.IndexForPoint(context, point)));
            }
        }
Exemplo n.º 26
0
        public static MathListIndex IndexForPoint <TFont, TGlyph>(this ListDisplay <TFont, TGlyph> self, TypesettingContext <TFont, TGlyph> context, PointF point) where TFont : IFont <TGlyph>
        {
            // The origin of for the subelements of a MathList is the current position, so translate the current point to our origin.
            var translatedPoint = new PointF(point.X - self.Position.X, point.Y - self.Position.Y);

            IDisplay <TFont, TGlyph> closest = null;
            var   xbounds     = new List <IDisplay <TFont, TGlyph> >();
            float minDistance = float.MaxValue;

            foreach (var display in self.Displays)
            {
                var bounds     = display.DisplayBounds;
                var rect       = new RectangleF(display.Position, bounds.Size);
                var maxBoundsX = rect.Right;
                if (rect.X - PixelDelta <= translatedPoint.X && translatedPoint.X <= maxBoundsX + PixelDelta)
                {
                    xbounds.Add(display);
                }
                var distance = DistanceFromPointToRect(translatedPoint, rect);
                if (distance < minDistance)
                {
                    closest     = display;
                    minDistance = distance;
                }
            }
            IDisplay <TFont, TGlyph> displayWithPoint;

            switch (xbounds.Count)
            {
            case 0:
                if (translatedPoint.X <= -PixelDelta)
                {
                    // All the way to the left
                    return(self.Range.Location < 0 ? null : MathListIndex.Level0Index(self.Range.Location));
                }
                else if (translatedPoint.X >= self.Width + PixelDelta)
                {
                    // if closest is a script
                    if (closest != null && closest is ListDisplay <TFont, TGlyph> ld &&
                        ld.LinePosition != Enumerations.LinePosition.Regular)
                    {
                        // then we try to find its parent
                        var parent = self.Displays.FirstOrDefault(d => d.HasScript && d.Range.Contains(ld.IndexInParent));

                        if (parent != null)
                        {
                            return(MathListIndex.Level0Index(parent.Range.End));
                        }
                    }
                    // All the way to the right
                    return(self.Range.End < 0 ? null : MathListIndex.Level0Index(self.Range.End));
                }
                else
                {
                    // It is within the ListDisplay but not within the X bounds of any sublist. Use the closest in that case.
                    displayWithPoint = closest;
                }
                break;

            case 1:
                displayWithPoint = xbounds[0];
                var rect = new RectangleF(displayWithPoint.Position, displayWithPoint.DisplayBounds.Size);
                if (translatedPoint.X >= self.Width - PixelDelta)
                {
                    //The point is close to the end. Only use the selected X bounds if the Y is within range.
                    if (translatedPoint.Y <= rect.YMin() - PixelDelta)
                    {
                        //The point is less than the Y including the delta. Move the cursor to the end rather than in this atom.
                        return(MathListIndex.Level0Index(self.Range.End));
                    }
                }
                break;

            default:
                //Use the closest since there are more than 2 sublists which have this X position.
                displayWithPoint = closest;
                break;
            }
            if (displayWithPoint is null)
            {
                return(null);
            }

            var index = displayWithPoint.IndexForPoint(context, translatedPoint);

            if (displayWithPoint is ListDisplay <TFont, TGlyph> closestLine)
            {
                if (closestLine.LinePosition is Enumerations.LinePosition.Regular)
                {
                    throw Arg($"{nameof(ListDisplay<TFont, TGlyph>)} {nameof(ListDisplay<TFont, TGlyph>.LinePosition)} {nameof(Enumerations.LinePosition.Regular)} " +
                              $"inside an {nameof(ListDisplay<TFont, TGlyph>)} - shouldn't happen", nameof(self));
                }
                // This is a subscript or a superscript, return the right type of subindex
                var indexType = closestLine.LinePosition is Enumerations.LinePosition.Subscript ? MathListSubIndexType.Subscript : MathListSubIndexType.Superscript;
                // The index of the atom this denotes.
                if (closestLine.IndexInParent is int.MinValue)
                {
                    throw Arg($"Index was not set for a {indexType} in the {nameof(ListDisplay<TFont, TGlyph>)}.", nameof(self));
                }
                return(MathListIndex.IndexAtLocation(closestLine.IndexInParent, indexType, index));
            }
            else if (displayWithPoint.HasScript)
            {
                //The display list has a subscript or a superscript. If the index is at the end of the atom, then we need to put it before the sub/super script rather than after.
                if (index?.AtomIndex == displayWithPoint.Range.End)
                {
                    return(MathListIndex.IndexAtLocation(index.AtomIndex - 1, MathListSubIndexType.BetweenBaseAndScripts, MathListIndex.Level0Index(1)));
                }
            }
            return(index);
        }
        public static MathListIndex IndexForPoint <TFont, TGlyph>(this TextLineDisplay <TFont, TGlyph> self, TypesettingContext <TFont, TGlyph> context, PointF point) where TFont : IFont <TGlyph>
        {
            // Convert the point to the reference of the CTLine
            var relativePoint = new PointF(point.X - self.Position.X, point.Y - self.Position.Y);
            var indices       = self.Runs.Select(run => run.Run.GlyphIndexForXOffset(context, relativePoint.Plus(run.Position).X)).Where(x => x.HasValue);

            if (indices.IsEmpty())
            {
                return(null);
            }
            var index = indices.Single().GetValueOrDefault();
            // The index returned is in UTF-16, translate to codepoint index.
            // NSUInteger codePointIndex = stringIndexToCodePointIndex(self.attributedString.string, index);
            // Convert the code point index to an index into the mathlist
            var mlIndex = self.StringIndexToMathListIndex(index);

            // index will be between 0 and _range.length inclusive
            if (mlIndex < 0 || mlIndex > self.Range.Length)
            {
                throw new InvalidCodePathException($"Returned index out of range: {index}, range ({self.Range.Location}, {self.Range.Length})");
            }
            // translate to the current index
            return(MathListIndex.Level0Index(self.Range.Location + mlIndex));
        }
Exemplo n.º 28
0
        public static PointF?PointForIndex <TFont, TGlyph>(this ListDisplay <TFont, TGlyph> self, TypesettingContext <TFont, TGlyph> context, MathListIndex index) where TFont : IFont <TGlyph>
        {
            if (index is null)
            {
                return(null);
            }

            PointF?position    = null;
            var    nonScripted =
                self.Displays
                .Where(d => !(d is ListDisplay <TFont, TGlyph> ld &&
                              ld.LinePosition != Enumerations.LinePosition.Regular))
                .ToArray();

            if (index.SubIndexType == MathListSubIndexType.None &&
                nonScripted.Length > 0 &&
                nonScripted.All(d => d.Range.End <= index.AtomIndex))
            {
                position = new PointF(self.Width, 0);
            }
            else
            {
                if (index.AtomIndex == self.Range.End)
                {
                    // Special case the edge of the range
                    position = new PointF(self.Width, 0);
                }
                else if (self.Range.Contains(index.AtomIndex) && self.SubDisplayForIndex(index) is IDisplay <TFont, TGlyph> display)
                {
                    switch (index.SubIndexType)
                    {
                    case MathListSubIndexType.BetweenBaseAndScripts:
                        var nucleusPosition = index.AtomIndex + index.SubIndex.AtomIndex;
                        position = display.PointForIndex(context, MathListIndex.Level0Index(nucleusPosition));
                        break;

                    case MathListSubIndexType.None:
                        if (!display.HasScript)
                        {
                            position = display.PointForIndex(context, index);
                        }
                        else
                        {
                            var mainPosition = display.PointForIndex(context, index);
                            position = self.Displays.SingleOrDefault(d =>
                                                                     d is ListDisplay <TFont, TGlyph> ld && ld.IndexInParent == index.AtomIndex - 1)
                                       is IDisplay <TFont, TGlyph> scripted && mainPosition != null
                  ? new PointF(mainPosition.Value.X + scripted.Width, 0)
                  : mainPosition;
                        }
                        break;

                    default:
                        // Recurse
                        position = display.PointForIndex(context, index.SubIndex);
                        break;
                    }
                }
                else
                {
                    // Outside the range
                    return(null);
                }
            }
            if (position is PointF found)
            {
                // Convert bounds from our coordinate system before returning
                found.X += self.Position.X;
                found.Y += self.Position.Y;
                return(found);
            }
            else
            {
                // We didn't find the position
                return(null);
            }
        }
Exemplo n.º 29
0
 /// <summary>
 /// Finds the index in the mathlist before which a new character should be inserted.
 /// Returns null if it cannot find the index.
 /// </summary>
 public static MathListIndex?IndexForPoint <TFont, TGlyph>(
     this IDisplay <TFont, TGlyph> display,
     TypesettingContext <TFont, TGlyph> context, PointF point)
     where TFont : IFont <TGlyph> => display switch
 {
Exemplo n.º 30
0
 public MathKeyboard(TypesettingContext <TFont, TGlyph> context, TFont font) =>
 (Context, Font) = (context, font);