コード例 #1
0
ファイル: CssBox.cs プロジェクト: Alister742/ParseKit
        /// <summary>
        /// Assigns words its width and height
        /// </summary>
        /// <param name="g"></param>
        internal void MeasureWordsSize(Graphics g)
        {
            // Check if measure white space if not yet done to measure once
            if (!_wordsSizeMeasured)
            {
                MeasureWordSpacing(g);

                if (HtmlTag != null && HtmlTag.Name == "img")
                {
                    var image = CssValueParser.GetImage(GetAttribute("src"), HtmlContainer.Bridge);
                    var word  = new CssBoxWord(this, image);
                    Words.Clear();
                    Words.Add(word);
                }
                else if (Words.Count > 0)
                {
                    foreach (var boxWord in Words)
                    {
                        var sf = new StringFormat();
                        sf.SetMeasurableCharacterRanges(new[] { new CharacterRange(0, boxWord.Text.Length) });

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

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

                        boxWord.LastMeasureOffset = new PointF(p.X, p.Y);
                        boxWord.Width             = s.Width + ActualWordSpacing;
                        boxWord.Height            = s.Height;
                    }
                }
                _wordsSizeMeasured = true;
            }
        }
コード例 #2
0
ファイル: CssBox.cs プロジェクト: Alister742/ParseKit
        /// <summary>
        /// Searches for the first word occourence inside the box, on the specified linebox
        /// </summary>
        /// <param name="b"></param>
        /// <param name="line"> </param>
        /// <returns></returns>
        internal CssBoxWord FirstWordOccourence(CssBox b, CssLineBox line)
        {
            if (b.Words.Count == 0 && b.Boxes.Count == 0)
            {
                return(null);
            }

            if (b.Words.Count > 0)
            {
                foreach (CssBoxWord word in b.Words)
                {
                    if (line.Words.Contains(word))
                    {
                        return(word);
                    }
                }
                return(null);
            }
            else
            {
                foreach (CssBox bb in b.Boxes)
                {
                    CssBoxWord w = FirstWordOccourence(bb, line);

                    if (w != null)
                    {
                        return(w);
                    }
                }

                return(null);
            }
        }
コード例 #3
0
        /// <summary>
        /// Applies right alignment to the text on the linebox
        /// </summary>
        /// <param name="g"></param>
        /// <param name="line"></param>
        private static void ApplyRightAlignment(Graphics g, CssLineBox line)
        {
            if (line.Words.Count == 0)
            {
                return;
            }


            CssBoxWord lastWord = line.Words[line.Words.Count - 1];
            float      right    = line.OwnerBox.ActualRight - line.OwnerBox.ActualPaddingRight - line.OwnerBox.ActualBorderRightWidth;
            float      diff     = right - lastWord.Right - lastWord.LastMeasureOffset.X - lastWord.OwnerBox.ActualBorderRightWidth - lastWord.OwnerBox.ActualPaddingRight;


            if (diff <= 0)
            {
                return;
            }

            //if (line.OwnerBox.Direction == CssConstants.Rtl)
            //{

            //}

            foreach (CssBoxWord word in line.Words)
            {
                word.Left += diff;
            }

            foreach (CssBox b in line.Rectangles.Keys)
            {
                RectangleF r = b.Rectangles[line];
                b.Rectangles[line] = new RectangleF(r.X + diff, r.Y, r.Width, r.Height);
            }
        }
コード例 #4
0
ファイル: CssLineBox.cs プロジェクト: Alister742/ParseKit
        /// <summary>
        /// Sets the baseline of the words of the specified box to certain height
        /// </summary>
        /// <param name="g">Device info</param>
        /// <param name="b">box to check words</param>
        /// <param name="baseline">baseline</param>
        internal void SetBaseLine(Graphics g, CssBox b, float baseline)
        {
            //TODO: Aqui me quede, checar poniendo "by the" con un font-size de 3em
            List <CssBoxWord> ws = WordsOf(b);

            if (!Rectangles.ContainsKey(b))
            {
                return;
            }

            RectangleF r = Rectangles[b];

            //Save top of words related to the top of rectangle
            float gap = 0f;

            if (ws.Count > 0)
            {
                gap = ws[0].Top - r.Top;
            }
            else
            {
                CssBoxWord firstw = b.FirstWordOccourence(b, this);

                if (firstw != null)
                {
                    gap = firstw.Top - r.Top;
                }
            }

            //New top that words will have
            //float newtop = baseline - (Height - OwnerBox.FontDescent - 3); //OLD
            float newtop = baseline;// -GetBaseLineHeight(b, g); //OLD

            if (b.ParentBox != null &&
                b.ParentBox.Rectangles.ContainsKey(this) &&
                r.Height < b.ParentBox.Rectangles[this].Height)
            {
                //Do this only if rectangle is shorter than parent's
                float      recttop = newtop - gap;
                RectangleF newr    = new RectangleF(r.X, recttop, r.Width, r.Height);
                Rectangles[b] = newr;
                b.OffsetRectangle(this, gap);
            }

            foreach (var word in ws)
            {
                if (!word.IsImage)
                {
                    word.Top = newtop;
                }
            }
        }
コード例 #5
0
ファイル: CssLineBox.cs プロジェクト: Alister742/ParseKit
        /// <summary>
        /// Lets the linebox add the word an its box to their lists if necessary.
        /// </summary>
        /// <param name="word"></param>
        internal void ReportExistanceOf(CssBoxWord word)
        {
            if (!Words.Contains(word))
            {
                Words.Add(word);
                word.LineBox = this;
            }

            if (!RelatedBoxes.Contains(word.OwnerBox))
            {
                RelatedBoxes.Add(word.OwnerBox);
            }
        }
コード例 #6
0
ファイル: CssBox.cs プロジェクト: Alister742/ParseKit
        /// <summary>
        /// Gets the minimum width that the box can be.
        /// The box can be as thin as the longest word plus padding.
        /// The check is deep thru box tree.
        /// </summary>
        /// <returns></returns>
        internal float GetMinimumWidth()
        {
            float      maxw    = 0f;
            float      padding = 0f;
            CssBoxWord word    = null;

            GetMinimumWidth_LongestWord(this, ref maxw, ref word);

            if (word != null)
            {
                GetMinimumWidth_BubblePadding(word.OwnerBox, this, ref padding);
            }

            return(maxw + padding);
        }
コード例 #7
0
ファイル: CssBox.cs プロジェクト: Alister742/ParseKit
 /// <summary>
 /// Gets the longest word (in width) inside the box, deeply.
 /// </summary>
 /// <param name="b"></param>
 /// <param name="maxw"> </param>
 /// <param name="word"> </param>
 /// <returns></returns>
 private void GetMinimumWidth_LongestWord(CssBox b, ref float maxw, ref CssBoxWord word)
 {
     if (b.Words.Count > 0)
     {
         foreach (CssBoxWord w in b.Words)
         {
             if (w.FullWidth > maxw)
             {
                 maxw = w.FullWidth;
                 word = w;
             }
         }
     }
     else
     {
         foreach (CssBox bb in b.Boxes)
         {
             GetMinimumWidth_LongestWord(bb, ref maxw, ref word);
         }
     }
 }
コード例 #8
0
 /// <summary>
 /// The selection start index if the first selected word is partially selected (-1 if not selected or fully selected)<br/>
 /// if the given word is not starting or ending selection word -1 is returned as full word selection is in place.
 /// </summary>
 /// <remarks>
 /// Handles backward selecting by returning the selection end data instead of start.
 /// </remarks>
 /// <param name="word">the word to return the selection start index for</param>
 /// <returns>data value or -1 if not aplicable</returns>
 public int GetSelectingStartIndex(CssBoxWord word)
 {
     return word == (_backwardSelection ? _selectionEnd : _selectionStart) ? (_backwardSelection ? _selectionEndIndex : _selectionStartIndex) : -1;
 }
コード例 #9
0
        /// <summary>
        /// Select all the words that are between <paramref name="selectionStart"/> word and <paramref name="selectionEnd"/> word in the DOM hierarchy.
        /// </summary>
        /// <param name="box">the current traversal node</param>
        /// <param name="selectionStart">selection start word limit</param>
        /// <param name="selectionEnd">selection end word limit</param>
        /// <param name="inSelection">used to know the traversal is currently in selected range</param>
        /// <returns></returns>
        private bool SelectWordsInRange(CssBox box, CssBoxWord selectionStart, CssBoxWord selectionEnd, ref bool inSelection)
        {
            foreach (var boxWord in box.Words)
            {
                if (!inSelection && boxWord == selectionStart)
                {
                    inSelection = true;
                }
                if (inSelection)
                {
                    boxWord.Selection = this;

                    if (selectionStart == selectionEnd || boxWord == selectionEnd)
                    {
                        return true;
                    }
                }
            }

            foreach (var childBox in box.Boxes)
            {
                if (SelectWordsInRange(childBox, selectionStart, selectionEnd, ref inSelection))
                {
                    return true;
                }
            }

            return false;
        }
コード例 #10
0
 /// <summary>
 /// Select all the words that are between <paramref name="selectionStart"/> word and <paramref name="selectionEnd"/> word in the DOM hierarchy.<br/>
 /// </summary>
 /// <param name="root">the root of the DOM sub-tree the selection is in</param>
 /// <param name="selectionStart">selection start word limit</param>
 /// <param name="selectionEnd">selection end word limit</param>
 private void SelectWordsInRange(CssBox root, CssBoxWord selectionStart, CssBoxWord selectionEnd)
 {
     bool inSelection = false;
     SelectWordsInRange(root, selectionStart, selectionEnd, ref inSelection);
 }
コード例 #11
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;
                    }

                    control.Cursor = Cursors.IBeam;
                    control.Invalidate();
                }
            }
        }
コード例 #12
0
        /// <summary>
        /// Clear the current selection.
        /// </summary>
        private void ClearSelection()
        {
            // clear drag and drop
            _dragDropData = null;

            ClearSelection(_root);

            _selectionStartOffset = -1;
            _selectionStartIndex = -1;
            _selectionEndOffset = -1;
            _selectionEndIndex = -1;

            _selectionStartPoint = Point.Empty;
            _selectionStart = null;
            _selectionEnd = null;
        }
コード例 #13
0
        /// <summary>
        /// Calculate the charecter index and offset by charecters for the given word and given offset.<br/>
        /// <seealso cref="CalculateWordCharIndexAndOffset(Control, CssBoxWord, Point, bool, out int, out float)"/>.
        /// </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="selectionStart">to set the starting or ending char and offset data</param>
        private void CalculateWordCharIndexAndOffset(Control control, CssBoxWord word, Point loc, bool selectionStart)
        {
            int selectionIndex;
            float selectionOffset;
            CalculateWordCharIndexAndOffset(control, word, loc, selectionStart, out selectionIndex, out selectionOffset);

            if(selectionStart)
            {
                _selectionStartIndex = selectionIndex;
                _selectionStartOffset = selectionOffset;
            }
            else
            {
                _selectionEndIndex = selectionIndex;
                _selectionEndOffset = selectionOffset;
            }
        }
コード例 #14
0
ファイル: DomUtils.cs プロジェクト: Alister742/ParseKit
        /// <summary>
        /// Find the css line box that the given word is in.
        /// </summary>
        /// <param name="word">the word to search for it's line box</param>
        /// <returns>line box that the word is in</returns>
        public static CssLineBox GetCssLineBoxByWord(CssBoxWord word)
        {
            var box = word.OwnerBox;

            while (box != null && box.LineBoxes.Count == 0)
            {
                box = box.ParentBox;
            }

            if (box == null)
                return null;

            foreach (var lineBox in box.LineBoxes)
            {
                foreach (var lineWord in lineBox.Words)
                {
                    if(lineWord == word)
                    {
                        return lineBox;
                    }
                }
            }
            return box.LineBoxes[0];
        }
コード例 #15
0
 /// <summary>
 /// The selection start offset if the first selected word is partially selected (-1 if not selected or fully selected)<br/>
 /// if the given word is not starting or ending selection word -1 is returned as full word selection is in place.
 /// </summary>
 /// <remarks>
 /// Handles backward selecting by returning the selection end data instead of start.
 /// </remarks>
 /// <param name="word">the word to return the selection start offset for</param>
 public float GetSelectedStartOffset(CssBoxWord word)
 {
     return word == (_backwardSelection ? _selectionEnd : _selectionStart) ? (_backwardSelection ? _selectionEndOffset : _selectionStartOffset) : -1;
 }
コード例 #16
0
 /// <summary>
 /// The selection end index if the last selected word is partially selected (-1 if not selected or fully selected)<br/>
 /// if the given word is not starting or ending selection word -1 is returned as full word selection is in place.
 /// </summary>
 /// <remarks>
 /// Handles backward selecting by returning the selection end data instead of start.
 /// </remarks>
 /// <param name="word">the word to return the selection end index for</param>
 public int GetSelectedEndIndexOffset(CssBoxWord word)
 {
     return word == (_backwardSelection ? _selectionStart : _selectionEnd) ? (_backwardSelection ? _selectionStartIndex : _selectionEndIndex) : -1;
 }
コード例 #17
0
ファイル: CssBox.cs プロジェクト: Alister742/ParseKit
 /// <summary>
 /// Gets the longest word (in width) inside the box, deeply.
 /// </summary>
 /// <param name="b"></param>
 /// <param name="maxw"> </param>
 /// <param name="word"> </param>
 /// <returns></returns>
 private void GetMinimumWidth_LongestWord(CssBox b, ref float maxw, ref CssBoxWord word)
 {
     if (b.Words.Count > 0)
     {
         foreach (CssBoxWord w in b.Words)
         {
             if (w.FullWidth > maxw)
             {
                 maxw = w.FullWidth;
                 word = w;
             }
         }
     }
     else
     {
         foreach(CssBox bb in b.Boxes)
             GetMinimumWidth_LongestWord(bb, ref maxw,ref word);
     }
 }
コード例 #18
0
ファイル: CssBox.cs プロジェクト: Alister742/ParseKit
        /// <summary>
        /// Assigns words its width and height
        /// </summary>
        /// <param name="g"></param>
        internal void MeasureWordsSize(Graphics g)
        {
            // Check if measure white space if not yet done to measure once
            if (!_wordsSizeMeasured)
            {
                MeasureWordSpacing(g);

                if (HtmlTag != null && HtmlTag.Name == "img")
                {
                    var image = CssValueParser.GetImage(GetAttribute("src"), HtmlContainer.Bridge);
                    var word = new CssBoxWord(this, image);
                    Words.Clear();
                    Words.Add(word);
                }
                else if(Words.Count > 0)
                {
                    foreach (var boxWord in Words)
                    {
                        var sf = new StringFormat();
                        sf.SetMeasurableCharacterRanges(new[] { new CharacterRange(0, boxWord.Text.Length) });

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

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

                        boxWord.LastMeasureOffset = new PointF(p.X, p.Y);
                        boxWord.Width = s.Width + ActualWordSpacing;
                        boxWord.Height = s.Height;
                    }
                }
                _wordsSizeMeasured = true;
            }
        }
コード例 #19
0
ファイル: DomUtils.cs プロジェクト: Alister742/ParseKit
 /// <summary>
 /// Get the selected word with respect to partial selected words.
 /// </summary>
 /// <param name="boxWord">the word to append</param>
 /// <param name="selectedText">is to get selected text or all the text in the word</param>
 private static string GetSelectedWord(CssBoxWord boxWord, bool selectedText)
 {
     if (selectedText && boxWord.SelectedStartIndex > -1 && boxWord.SelectedEndIndexOffset > -1)
     {
         return boxWord.Text.Substring(boxWord.SelectedStartIndex, boxWord.SelectedEndIndexOffset - boxWord.SelectedStartIndex);
     }
     else if (selectedText && boxWord.SelectedStartIndex > -1)
     {
         return boxWord.Text.Substring(boxWord.SelectedStartIndex) + " ";
     }
     else if (selectedText && boxWord.SelectedEndIndexOffset > -1)
     {
         return boxWord.Text.Substring(0, boxWord.SelectedEndIndexOffset);
     }
     else
     {
         return boxWord.Text + " ";
     }
 }
コード例 #20
0
 /// <summary>
 /// Select the word at the given location if found.
 /// </summary>
 /// <param name="control">the control hosting the html to invalidate</param>
 /// <param name="loc">the location to select word at</param>
 public void SelectWord(Control control, Point loc)
 {
     var word = DomUtils.GetCssBoxWord(_root, loc);
     if (word != null)
     {
         word.Selection = this;
         _selectionStartPoint = loc;
         _selectionStart = _selectionEnd = word;
         control.Invalidate();
     }
 }
コード例 #21
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, CssBoxWord 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 > word.LineBox.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);
                    }
                }
            }
        }
コード例 #22
0
ファイル: CssLineBox.cs プロジェクト: Alister742/ParseKit
        /// <summary>
        /// Lets the linebox add the word an its box to their lists if necessary.
        /// </summary>
        /// <param name="word"></param>
        internal void ReportExistanceOf(CssBoxWord word)
        {
            if (!Words.Contains(word))
            {
                Words.Add(word);
                word.LineBox = this;
            }

            if (!RelatedBoxes.Contains(word.OwnerBox))
            {
                RelatedBoxes.Add(word.OwnerBox);
            }
        }