public Textfield() : base() { SizeChanged += new Action <Size>(Textfield_SizeChanged); LocationChanged += new Action <Point>(Textfield_LocationChanged); selectRange = new UStyleRange(0, 0, null, selectFG, selectBG); data.styleRanges.Add(selectRange); Cursor = NoForms.Common.Cursors.IBeam; UpdateTextLayout(); System.Timers.Timer tm = new System.Timers.Timer(800) { AutoReset = true }; tm.Elapsed += new System.Timers.ElapsedEventHandler(tm_Elapsed); tm.Start(); }
UGlyphRun BuildGlyphRun(int start, int length, UStyleRange currentStyle, UText text, BreakType bt) { FontClass useFont = Translate(currentStyle == null ? text.font : currentStyle.fontOverride ?? text.font); var gr = new UGlyphRun() { startPosition = start, runLength = length, breakingType = bt, drawStyle = currentStyle, charSizes = new Size[length] }; float tw = 0; gr.content = gr.runLength > 0 ? text.text.Substring(gr.startPosition, gr.runLength) : ""; gr.runSize = MeasureString(text, gr.content, useFont); if (bt == BreakType.word) { // handle space spacing ;) String ltx = gr.startPosition > 0 ? text.text.Substring(gr.startPosition - 1, 1) : ""; String rtx = gr.startPosition + length < text.text.Length ? text.text.Substring(length, 1) : ""; var s1 = MeasureString(text, ltx + gr.content + rtx, useFont); var s2 = MeasureString(text, ltx + rtx, useFont); gr.runSize.width = s1.width - s2.width; } for (int i = 0; i < gr.content.Length; i++) { gr.charSizes[i] = MeasureString(text, gr.content.Substring(i, 1), useFont); tw += gr.charSizes[i].width; } float corr = gr.runSize.width / tw; for (int i = 0; i < gr.content.Length; i++) { gr.charSizes[i].width *= corr; } return(gr); }
static String[] lineBreak = new String[] { "\r\n", "\n" }; //order is important IEnumerable <UGlyphRun> GetGlyphRuns(UText text) { // concecutive wordbreaks are one glyphrun, while concecutive linebreaks are individual glpyhruns List <TR> breaks = new List <TR>(); foreach (String lb in lineBreak) { foreach (int idx in AllIndexes(text.text, lb)) { breaks.Add(new TR() { type = BreakType.line, content = lb, location = idx }); } } int lastIdx = -2; foreach (String wb in wordBreak) { foreach (int idx in AllIndexes(text.text, wb)) { if (idx == lastIdx + 1) // inflate last break { breaks[breaks.Count - 1].content += wb; } else { breaks.Add(new TR() { type = BreakType.word, content = wb, location = idx }); } } } int cpos = 0; UStyleRange cstyle = null; bool flatch = true; // splitting glyphs also by changes in UStyleRange var srs = new List <UStyleRange>(text.SafeGetStyleRanges); foreach (var sr in NormaliseStyleRanges(srs, text.text.Length)) { var lsi = sr.leftStlyeIdx; var rsi = sr.rightStyleIdx; var tr = new TR() { type = BreakType.font, content = "", location = sr.splitPoint, styley = new UStyleRange[] { lsi > -1 ? srs[lsi] : null, rsi > -1 ? srs[rsi] : null } }; breaks.Add(tr); if (flatch) { cstyle = tr.styley[0]; flatch = false; } } // Sort those breaks... FIXME sorting is slow breaks.Sort((a, b) => { var lb = a.location.CompareTo(b.location); return(lb == 0 ? a.content.Length.CompareTo(b.content.Length) : lb); }); // build glyphruns from the breaks... foreach (var tr in breaks) { // two glyphruns in this, first is before the break (could be zero length) yield return(BuildGlyphRun(cpos, tr.location - cpos, cstyle, text, BreakType.none)); // next is the break itself, dont add font breaks (geting dirty here) if (tr.type == BreakType.font) { cstyle = tr.styley[1]; } else { yield return(BuildGlyphRun(tr.location, tr.content.Length, cstyle, text, tr.type)); } // cpos set to after the break cpos = tr.location + tr.content.Length; } // possible last glyphrun if (cpos < text.text.Length) { yield return(BuildGlyphRun(cpos, text.text.Length - cpos, cstyle, text, BreakType.none)); } }