ArrangeBoxes() private méthode

private ArrangeBoxes ( FwTextAlign align, int gapLeft, int gapRight, int firstLineIndent, int availWidth, int topDepth ) : void
align FwTextAlign
gapLeft int
gapRight int
firstLineIndent int
availWidth int
topDepth int
Résultat void
Exemple #1
0
        private void BuildALine()
        {
            m_currentLine            = new ParaLine();
            m_spaceLeftOnCurrentLine = m_layoutInfo.MaxWidth - m_surroundWidth;

            if (m_lines.Count == 0)
            {
                m_currentLine.Top         = m_gapTop;
                m_spaceLeftOnCurrentLine -= m_layoutInfo.MpToPixelsY(m_para.Style.FirstLineIndent);
            }
            m_lines.Add(m_currentLine);
            m_lineSegTypes.Clear();
            while (!Finished)
            {
                if (!AddSomethingToLine())
                {
                    break;
                }
            }
            while (!FinalizeLine())
            {
                if (!Backtrack())
                {
                    break;
                }
            }
            if (m_lines.Count > 1)
            {
                ParaLine previous = m_lines[m_lines.Count - 2];
                previous.LastBox.Next = m_currentLine.FirstBox;
                m_currentLine.Top     = TopOfNextLine(previous, m_currentLine.Ascent);
            }
            m_currentLine.ArrangeBoxes(m_para.Style.ParaAlignment, m_gapLeft, m_gapRight,
                                       m_lines.Count == 1 ? m_layoutInfo.MpToPixelsY(m_para.Style.FirstLineIndent) : 0,
                                       m_layoutInfo.MaxWidth,
                                       TopDepth);
        }
Exemple #2
0
		private void BuildALine()
		{
			m_currentLine = new ParaLine();
			m_spaceLeftOnCurrentLine = m_layoutInfo.MaxWidth - m_surroundWidth;

			if (m_lines.Count == 0)
			{
				m_currentLine.Top = m_gapTop;
				m_spaceLeftOnCurrentLine -= m_layoutInfo.MpToPixelsY(m_para.Style.FirstLineIndent);
			}
			m_lines.Add(m_currentLine);
			m_lineSegTypes.Clear();
			while (!Finished)
				if (!AddSomethingToLine())
					break;
			while (!FinalizeLine())
				if (!Backtrack())
					break;
			if (m_lines.Count > 1)
			{
				ParaLine previous = m_lines[m_lines.Count - 2];
				previous.LastBox.Next = m_currentLine.FirstBox;
				m_currentLine.Top = TopOfNextLine(previous, m_currentLine.Ascent);
			}
			m_currentLine.ArrangeBoxes(m_para.Style.ParaAlignment, m_gapLeft, m_gapRight,
									   m_lines.Count == 1 ? m_layoutInfo.MpToPixelsY(m_para.Style.FirstLineIndent) : 0,
									   m_layoutInfo.MaxWidth,
									   TopDepth);
		}
		public void ArrangeBoxes()
		{
			var styles = new AssembledStyles();

			// Ordinary layout
			var line = new ParaLine();
			line.Add(MakeStringBox(styles, 0, false));
			var box2 = MakeStringBox(styles, 0, false);
			line.Add(box2);
			line.Add(MakeStringBox(styles, 0, false));
			((MockDirectionSegment) box2.Segment).SimulatedWidth = 20;
			var layoutInfo = MakeLayoutInfo();
			foreach (var box in line.Boxes)
				box.Layout(layoutInfo);
			line.ArrangeBoxes(FwTextAlign.ktalLeft, 7, 0, 0, 100, 0);
			Assert.That(line.Boxes.First().Left, Is.EqualTo(7));
			Assert.That(line.Boxes.Skip(1).First().Left, Is.EqualTo(17)); // past first default(10)-width box
			Assert.That(line.Boxes.Skip(2).First().Left, Is.EqualTo(37)); // past second, 20-pixel box.

			// Still LTR, but aligned right
			line.ArrangeBoxes(FwTextAlign.ktalRight, 7, 3, 10, 100, 0);
			Assert.That(line.Boxes.Skip(2).First().Left, Is.EqualTo(100 - 3 - 10)); // from maxwidth, minus gapright, minus 10 pix width.
			Assert.That(line.Boxes.Skip(1).First().Left, Is.EqualTo(100 - 3 - 10 - 20)); // further left by 20 pix width of middle default-width box
			Assert.That(line.Boxes.First().Left, Is.EqualTo(100 -3 - 10 - 20 - 10)); // still further by 10 pix width of first box

			// Still LTR, but aligned center
			line.ArrangeBoxes(FwTextAlign.ktalCenter, 7, 3, 10, 100, 0);
			int sumBoxWidth = 40;
			int available = 100 - 7 - 3 - 10; // the width in which we can center
			int start = 7 + 10 + (available - sumBoxWidth)/2;
			Assert.That(line.Boxes.First().Left, Is.EqualTo(start));
			Assert.That(line.Boxes.Skip(1).First().Left, Is.EqualTo(start + 10)); // past first default(10)-width box
			Assert.That(line.Boxes.Skip(2).First().Left, Is.EqualTo(start + 30)); // past second, 20-pixel box.

			// Enhance: add test for justified.

			// Now simulate RTL paragraph with similar contents. Boxes are in opposite order.
			line = new ParaLine();
			line.Add(MakeStringBox(styles, 1, false));
			box2 = MakeStringBox(styles, 1, false);
			line.Add(box2);
			line.Add(MakeStringBox(styles, 1, false));
			((MockDirectionSegment)box2.Segment).SimulatedWidth = 30;
			foreach (var box in line.Boxes)
				box.Layout(layoutInfo);
			line.ArrangeBoxes(FwTextAlign.ktalLeft, 7, 0, 0, 100, 1);
			Assert.That(line.Boxes.Skip(2).First().Left, Is.EqualTo(7)); // last box is now leftmost.
			Assert.That(line.Boxes.Skip(1).First().Left, Is.EqualTo(17)); // second is left of first by width of first
			Assert.That(line.Boxes.First().Left, Is.EqualTo(47)); // first is now on the right.

			// Verify that it works correctly for align right (obey firstLineIndent!) and center.
			line.ArrangeBoxes(FwTextAlign.ktalRight, 7, 3, 15, 100, 1);
			var rightOfFirstBox = 100 - 3 - 15;
			Assert.That(line.Boxes.First().Right, Is.EqualTo(rightOfFirstBox));
			Assert.That(line.Boxes.Skip(1).First().Right, Is.EqualTo(rightOfFirstBox - 10)); // past first default-width box
			Assert.That(line.Boxes.Skip(2).First().Right, Is.EqualTo(rightOfFirstBox - 10 - 30)); // past second, 30-pixel box.
		}
Exemple #4
0
        /// <summary>
        /// Redo layout. Should produce the same segments as FullLayout, but assume that segments for text up to
        /// details.StartChange may be reused (if not affected by changing line breaks), and segments after
        /// details.StartChange+details.DeleteCount may be re-used if a line break works out (and after adjusting
        /// their begin offset).
        /// </summary>
        /// <param name="details"></param>
        internal void Relayout(SourceChangeDetails details, LayoutCallbacks lcb)
        {
            m_reuseableLines = m_para.Lines;
            m_lines          = new List <ParaLine>();
            m_renderRunIndex = 0;
            m_ichRendered    = 0;
            IRenderRun last = m_renderRuns[m_renderRuns.Count - 1];

            m_ichLim             = last.RenderStart + last.RenderLength;
            m_lastRenderRunIndex = m_renderRuns.Count;
            Rectangle invalidateRect = m_para.InvalidateRect;
            int       delta          = details.InsertCount - details.DeleteCount;
            int       oldHeight      = m_para.Height;
            int       oldWidth       = m_para.Width;

            // Make use of details.StartChange to reuse some lines at start.
            if (m_reuseableLines.Count > 0)
            {
                // As long as we have two complete lines before the change, we can certainly reuse the first of them.
                while (m_reuseableLines.Count > 2 && details.StartChange > m_reuseableLines[2].IchMin)
                {
                    m_lines.Add(m_reuseableLines[0]);
                    m_reuseableLines.RemoveAt(0);
                }
                // If we still have one complete line before the change, we can reuse it provided there is white
                // space after the end of the line and before the change.
                if (m_reuseableLines.Count > 1)
                {
                    int startNextLine = m_reuseableLines[1].IchMin;
                    if (details.StartChange > startNextLine)
                    {
                        bool   fGotWhite = false;
                        string line1Text = m_reuseableLines[1].CheckedText;
                        int    lim       = details.StartChange - startNextLine;
                        var    cpe       = LgIcuCharPropEngineClass.Create();
                        for (int ich = 0; ich < lim; ich++)
                        {
                            // Enhance JohnT: possibly we need to consider surrogates here?
                            // Worst case is we don't reuse a line we could have, since a surrogate won't
                            // be considered white.
                            if (cpe.get_IsSeparator(Convert.ToInt32(line1Text[ich])))
                            {
                                fGotWhite = true;
                                break;
                            }
                        }
                        if (fGotWhite)
                        {
                            m_lines.Add(m_reuseableLines[0]);
                            m_reuseableLines.RemoveAt(0);
                        }
                    }
                }
                m_ichRendered = m_reuseableLines[0].IchMin;
                int topOfFirstDiscardedLine = m_reuseableLines[0].Top;
                // We don't need to invalidate the lines we're keeping.
                invalidateRect = new Rectangle(invalidateRect.Left, invalidateRect.Top + topOfFirstDiscardedLine,
                                               invalidateRect.Width, invalidateRect.Height - topOfFirstDiscardedLine);
            }

            // Figure out which run we need to continue from, to correspond to the start of the first line
            // we need to rebuild.
            while (m_renderRunIndex < m_renderRuns.Count && m_renderRuns[m_renderRunIndex].RenderLim <= m_ichRendered)
            {
                m_renderRunIndex++;
            }

            while (!Finished)
            {
                // Todo: I think we need to adjust available width if this is the first line.
                BuildALine();
                // Drop any initial reusable lines we now determine to be unuseable after all.
                // If we've used characters beyond the start of this potentially reusable line, we can't reuse it.
                // Also, we don't reuse empty lines. Typically an empty line is left over from a previously empty
                // paragraph, and we no longer need the empty segment, even though it doesn't have any of the same
                // characters (since it has none) as the segment that has replaced it.
                while (m_reuseableLines.Count > 0 && (m_ichRendered > m_reuseableLines[0].IchMin + delta || m_reuseableLines[0].Length == 0))
                {
                    m_reuseableLines.RemoveAt(0);
                }
                if (m_reuseableLines.Count > 0)
                {
                    // See if we can resync.
                    var nextLine = m_reuseableLines[0];
                    if (m_ichRendered == nextLine.IchMin + delta)
                    {
                        // reuse it.
                        int top = m_gapTop;
                        if (m_lines.Count > 0)
                        {
                            ParaLine previous = m_lines.Last();
                            previous.LastBox.Next = nextLine.FirstBox;
                            top = TopOfNextLine(previous, nextLine.Ascent);
                        }

                        m_lines.AddRange(m_reuseableLines);
                        if (top != nextLine.Top)
                        {
                            ParaLine previous = null;
                            foreach (var line in m_reuseableLines)
                            {
                                if (previous != null)                                 // first time top has already been computed
                                {
                                    top = TopOfNextLine(previous, line.Ascent);
                                }
                                line.Top = top;                                 // BEFORE ArrangeBoxes, since it gets copied to the individual boxes
                                m_currentLine.ArrangeBoxes(m_para.Style.ParaAlignment, m_gapLeft, m_gapRight, 0, m_layoutInfo.MaxWidth, TopDepth);
                                previous = line;
                            }
                        }
                        else
                        {
                            // reusable lines have not moved, we don't need to invalidate them.
                            invalidateRect.Height -= (m_reuseableLines.Last().Bottom - top);
                        }
                        for (Box box = nextLine.FirstBox; box != null; box = box.Next)
                        {
                            if (box is StringBox)
                            {
                                (box as StringBox).IchMin += delta;
                            }
                        }

                        break;
                    }
                }
            }
            SetParaInfo();
            // if the paragraph got larger, we need to invalidate the extra area.
            // (But, don't reduce it if it got smaller; we want to invalidate all the old stuff as well as all the new.)
            if (m_para.Height > oldHeight)
            {
                invalidateRect.Height += m_para.Height - oldHeight;
            }
            if (m_para.Width > oldWidth)
            {
                invalidateRect.Width += m_para.Width - oldWidth;
            }
            lcb.InvalidateInRoot(invalidateRect);
        }