/// <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(); } } }
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; } } }