Example #1
0
        /// <summary>
        /// Calculate the charecter index and offset by charecters for the given word and given offset.
        /// If the location is below the word line then set the selection to the end.<br/>
        /// If the location is to the right of the word then set the selection to the end.<br/>
        /// If the offset is to the left of the word set the selection to the begining.<br/>
        /// Otherwise calculate the width of each substring to find the char the location is on.
        /// </summary>
        /// <param name="control">used to create graphics to measure string</param>
        /// <param name="word">the word to calculate its index and offset</param>
        /// <param name="loc">the location to calculate for</param>
        /// <param name="selectionIndex">return the index of the char under the location</param>
        /// <param name="selectionOffset">return the offset of the char under the location</param>
        /// <param name="inclusive">is to include the first charecter in the calculation</param>
        private static void CalculateWordCharIndexAndOffset(Control control, CssRect word, Point loc, bool inclusive, out int selectionIndex, out float selectionOffset)
        {
            selectionIndex  = 0;
            selectionOffset = 0.1f;
            var offset = loc.X - word.Left;

            if (word.Text == null)
            {
                // not a text word - set full selection
                selectionIndex  = -1;
                selectionOffset = -1;
            }
            else if (offset > word.Width - word.OwnerBox.ActualWordSpacing || loc.Y > DomUtils.GetCssLineBoxByWord(word).LineBottom)
            {
                // mouse under the line, to the right of the word - set to the end of the word
                selectionIndex  = word.Text.Length;
                selectionOffset = word.Width;
            }
            else if (offset > 0)
            {
                // calculate partial word selection
                selectionIndex  = word.Text.Length;
                selectionOffset = word.OwnerBox.ActualWordSpacing / 2f;
                using (var g = control.CreateGraphics())
                {
                    for (int i = 1; i <= word.Text.Length; i++)
                    {
                        var sf = new StringFormat();
                        sf.SetMeasurableCharacterRanges(new[] { new CharacterRange(0, i) });

                        var regions = g.MeasureCharacterRanges(word.Text, word.OwnerBox.ActualFont, new RectangleF(0, 0, float.MaxValue, float.MaxValue), sf);

                        SizeF s = regions[0].GetBounds(g).Size;

                        if (!inclusive)
                        {
                            selectionOffset = s.Width + (s.Width / i / 15f);
                        }
                        if (s.Width > offset)
                        {
                            selectionIndex = i - (inclusive ? 1 : 0);
                            break;
                        }
                        selectionOffset = s.Width + (s.Width / i / 15f);
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        /// Handle html text selection by mouse move over the html with left mouse button pressed.<br/>
        /// Calculate the words in the selected range and set their selected property.
        /// </summary>
        /// <param name="control">the control hosting the html to invalidate</param>
        /// <param name="loc">the mouse location</param>
        /// <param name="allowPartialSelect">true - partial word selection allowed, false - only full words selection</param>
        private void HandleSelection(Control control, Point loc, bool allowPartialSelect)
        {
            // get the line under the mouse or nearest from the top
            var lineBox = DomUtils.GetCssLineBox(_root, loc);

            if (lineBox != null)
            {
                // get the word under the mouse
                var word = DomUtils.GetCssBoxWord(lineBox, loc);

                // if no word found uner the mouse use the last or the first word in the line
                if (word == null && lineBox.Words.Count > 0)
                {
                    if (loc.Y > lineBox.LineBottom)
                    {
                        // under the line
                        word = lineBox.Words[lineBox.Words.Count - 1];
                    }
                    else if (loc.X < lineBox.Words[0].Left)
                    {
                        // before the line
                        word = lineBox.Words[0];
                    }
                    else if (loc.X > lineBox.Words[lineBox.Words.Count - 1].Right)
                    {
                        // at the end of the line
                        word = lineBox.Words[lineBox.Words.Count - 1];
                    }
                }

                // if there is matching word
                if (word != null)
                {
                    if (_selectionStart == null)
                    {
                        // on start set the selection start word
                        _selectionStartPoint = loc;
                        _selectionStart      = word;
                        if (allowPartialSelect)
                        {
                            CalculateWordCharIndexAndOffset(control, word, loc, true);
                        }
                    }

                    // always set selection end word
                    _selectionEnd = word;
                    if (allowPartialSelect)
                    {
                        CalculateWordCharIndexAndOffset(control, word, loc, false);
                    }

                    ClearSelection(_root);
                    if (CheckNonEmptySelection(loc, allowPartialSelect))
                    {
                        CheckSelectionDirection();
                        SelectWordsInRange(_root, _backwardSelection ? _selectionEnd : _selectionStart, _backwardSelection ? _selectionStart : _selectionEnd);
                    }
                    else
                    {
                        _selectionEnd = null;
                    }

                    _cursorChanged = true;
                    control.Cursor = Cursors.IBeam;
                    control.Invalidate();
                }
            }
        }