/// <summary>
        /// Render text lines.
        /// </summary>
        /// <param name="destArea"></param>
        protected void CacheTextLines(Rectf destArea)
        {
            var w = (MultiLineEditbox)Window;

            // text is already formatted, we just grab the lines and
            // create the render geometry for them with the required alignment.
            var drawArea      = destArea;
            var vertScrollPos = w.GetVertScrollbar().GetScrollPosition();

            drawArea.Offset(new Lunatics.Mathematics.Vector2(-w.GetHorzScrollbar().GetScrollPosition(), -vertScrollPos));

            var fnt = w.GetFont();

            if (fnt != null)
            {
                // calculate final colours to use.
                var alpha         = w.GetEffectiveAlpha();
                var normalTextCol = new ColourRect();
                SetColourRectToUnselectedTextColour(ref normalTextCol);
                normalTextCol.ModulateAlpha(alpha);
                var selectTextCol = new ColourRect();
                SetColourRectToSelectedTextColour(ref selectTextCol);
                selectTextCol.ModulateAlpha(alpha);
                var selectBrushCol = new ColourRect();
                if (w.HasInputFocus())
                {
                    SetColourRectToActiveSelectionColour(ref selectBrushCol);
                }
                else
                {
                    SetColourRectToInactiveSelectionColour(ref selectBrushCol);
                }

                selectBrushCol.ModulateAlpha(alpha);

                var lines    = w.GetFormattedLines();
                var numLines = lines.Count;

                // calculate the range of visible lines
                var sidx = (int)(vertScrollPos / fnt.GetLineSpacing());
                var eidx = 1 + sidx + (int)(destArea.Height / fnt.GetLineSpacing());
                eidx              = Math.Min(eidx, numLines);
                drawArea.d_min.Y += fnt.GetLineSpacing() * sidx;

                // for each formatted line.
                for (var i = sidx; i < eidx; ++i)
                {
                    var lineRect = drawArea;
                    var currLine = lines[i];
                    var lineText = w.GetTextVisual().CEGuiSubstring(currLine.d_startIdx, currLine.d_length);

                    // offset the font little down so that it's centered within its own spacing
                    var oldTop = lineRect.Top;
                    lineRect.d_min.Y += (fnt.GetLineSpacing() - fnt.GetFontHeight()) * 0.5f;

                    // if it is a simple 'no selection area' case
                    ColourRect colours;
                    if ((currLine.d_startIdx >= w.GetSelectionEndIndex()) ||
                        ((currLine.d_startIdx + currLine.d_length) <= w.GetSelectionStartIndex()) ||
                        (w.GetSelectionBrushImage() == null))
                    {
                        colours = normalTextCol;

                        // Create Geometry buffers for the text and add to the Window
                        var nextGlyphPos    = 0.0f;
                        var textGeomBuffers = fnt.CreateRenderGeometryForText(lineText, out nextGlyphPos, lineRect.Position, destArea, true, colours);
                        w.AppendGeometryBuffers(textGeomBuffers);
                    }
                    else // we have at least some selection highlighting to do
                    {
                        // Start of actual rendering section.
                        String sect;
                        int    sectIdx = 0, sectLen;
                        float  selStartOffset = 0.0f;

                        // Create the render geometry for any text prior to selected region of line.
                        if (currLine.d_startIdx < w.GetSelectionStartIndex())
                        {
                            // calculate length of text section
                            sectLen = w.GetSelectionStartIndex() - currLine.d_startIdx;

                            // get text for this section
                            sect     = lineText.CEGuiSubstring(sectIdx, sectLen);
                            sectIdx += sectLen;

                            // get the pixel offset to the beginning of the selection area highlight.
                            selStartOffset = fnt.GetTextAdvance(sect);

                            // Create the render geometry for this portion of the text
                            colours = normalTextCol;
                            var geomBuffers = fnt.CreateRenderGeometryForText(sect, lineRect.Position, destArea, true, colours);

                            // set position ready for next portion of text
                            lineRect.d_min.X += selStartOffset;
                        }

                        // calculate the length of the selected section
                        sectLen = Math.Min(w.GetSelectionEndIndex() - currLine.d_startIdx, currLine.d_length) - sectIdx;

                        // get the text for this section
                        sect     = lineText.CEGuiSubstring(sectIdx, sectLen);
                        sectIdx += sectLen;

                        // get the extent to use as the width of the selection area highlight
                        var selAreaWidth = fnt.GetTextAdvance(sect);

                        var textTop = lineRect.Top;
                        lineRect.Top = oldTop;

                        // calculate area for the selection brush on this line
                        lineRect.Left   = drawArea.Left + selStartOffset;
                        lineRect.Right  = lineRect.Left + selAreaWidth;
                        lineRect.Bottom = lineRect.Top + fnt.GetLineSpacing();

                        // Create the render geometry for the selection area brush for this line
                        colours = selectBrushCol;
                        var renderSettings       = new ImageRenderSettings(lineRect, destArea, true, colours);
                        var selectionGeomBuffers = w.GetSelectionBrushImage().CreateRenderGeometry(renderSettings);
                        w.AppendGeometryBuffers(selectionGeomBuffers);

                        // Create the render geometry for the text for this section
                        colours = selectTextCol;
                        var textGeomBuffers = fnt.CreateRenderGeometryForText(sect, lineRect.Position, destArea, true, colours);
                        w.AppendGeometryBuffers(textGeomBuffers);

                        lineRect.Top = textTop;

                        // Create the render geometry for any text beyond selected region of line
                        if (sectIdx < currLine.d_length)
                        {
                            // update render position to the end of the selected area.
                            lineRect.d_min.X += selAreaWidth;

                            // calculate length of this section
                            sectLen = currLine.d_length - sectIdx;

                            // get the text for this section
                            sect = lineText.CEGuiSubstring(sectIdx, sectLen);

                            // render the text for this section.
                            colours = normalTextCol;

                            var textAfterSelectionGeomBuffers = fnt.CreateRenderGeometryForText(sect, lineRect.Position, destArea, true, colours);
                            w.AppendGeometryBuffers(textAfterSelectionGeomBuffers);
                        }
                    }

                    // update master position for next line in paragraph.
                    drawArea.d_min.Y += fnt.GetLineSpacing();
                }
            }
        }
示例#2
0
        protected void CreateRenderGeometryForTextWithBidi(WidgetLookFeel wlf, string text, Rectf textArea, float textOffset)
        {
            var font = Window.GetFont();

            // setup initial rect for text formatting
            var textPartRect = textArea;

            // allow for scroll position
            textPartRect.d_min.X += textOffset;
            // centre text vertically within the defined text area
            textPartRect.d_min.Y += (textArea.Height - font.GetFontHeight()) * 0.5f;

            var colours   = new ColourRect();
            var alphaComp = Window.GetEffectiveAlpha();
            // get unhighlighted text colour (saves accessing property twice)
            var unselectedColour = new ColourRect();

            SetColourRectToUnselectedTextColour(ref unselectedColour);
            // see if the editbox is active or inactive.
            var w      = (Editbox)Window;
            var active = EditboxIsFocussed();

            if (w.GetSelectionLength() == 0)
            {
                // no highlighted text - we can draw the whole thing
                colours = unselectedColour;
                w.AppendGeometryBuffers(font.CreateRenderGeometryForText(text, out textPartRect.d_min.X, textPartRect.Position, textArea, true, colours));
            }
            else
            {
                // there is highlighted text - because of the Bidi support - the
                // highlighted area can be in some cases nonconsecutive.
                // So - we need to draw it char by char (I guess we can optimize it more
                // but this is not that big performance hit because it only happens if
                // we have highlighted text - not that common...)
                for (var i = 0; i < text.Length; i++)
                {
                    // get the char
                    var currChar = text[i];
                    var realPos  = 0;

                    // get he visual pos of the char
                    if (w.GetBidiVisualMapping().GetV2lMapping().Count > i)
                    {
                        realPos = w.GetBidiVisualMapping().GetV2lMapping()[i];
                    }

                    // check if it is in the highlighted region
                    var highlighted = realPos >= w.GetSelectionStart() &&
                                      realPos < w.GetSelectionStart() + w.GetSelectionLength();

                    var charAdvance = font.GetGlyphData(currChar).GetAdvance();

                    if (highlighted)
                    {
                        SetColourRectToSelectedTextColour(ref colours);
                        colours.ModulateAlpha(alphaComp);

                        {
                            // calculate area for selection imagery.
                            var hlarea = textArea;
                            hlarea.d_min.X = textPartRect.d_min.X;
                            hlarea.d_max.X = textPartRect.d_min.X + charAdvance;

                            // render the selection imagery.
                            wlf.GetStateImagery(active ? "ActiveSelection" :"InactiveSelection").Render(w, hlarea, null, textArea);
                        }
                    }
                    else
                    {
                        colours = unselectedColour;
                        colours.ModulateAlpha(alphaComp);
                    }

                    w.AppendGeometryBuffers(font.CreateRenderGeometryForText(currChar.ToString(CultureInfo.InvariantCulture), textPartRect.Position, textArea, true, colours));

                    // adjust rect for next section
                    textPartRect.d_min.X += charAdvance;
                }
            }
        }