From e56d3c4df37f0644754a27ba40d2646a59cd9984 Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 08:07:56 -0500 Subject: [PATCH 01/24] Version 2 starting implementation --- src/dlangui/core/editable.d | 9 ++++ src/dlangui/widgets/editors.d | 83 ++++++++++++++++++++++++++++++++--- 2 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/dlangui/core/editable.d b/src/dlangui/core/editable.d index 3973d65c..3a781b36 100644 --- a/src/dlangui/core/editable.d +++ b/src/dlangui/core/editable.d @@ -450,6 +450,15 @@ struct LineSpan { int start; /// number of lines it spans int len; + /// the wrapping points + WrapPoint[] wrapPoints; + + dstring[] wrappedContent; +} + +struct WrapPoint { + int wrapPos; + int wrapWidth; } /// interface for custom syntax highlight, comments toggling, smart indents, and other language dependent features for source code editors diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 6460dc7e..2693b351 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -391,12 +391,28 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction return this; } - void wrapLine(dstring line, int maxWidth) { - + dstring[] wrapLine(dstring line, int maxWidth) { + return []; } /// information about line span into several lines - in word wrap mode protected LineSpan[] _span; + + int wrapsUpTo(int line) + { + if(line < _span.length) + { + + int sum; + for(int i = 0; i<line; i++) + { + sum += _span[i].len - 1; + } + //Log.d(sum); + return sum; + } + return 0; + } /// override to add custom items on left panel protected void updateLeftPaneWidth() { @@ -3321,6 +3337,15 @@ class EditBox : EditWidgetBase { } } + void resetVisibleSpans() + { + //TODO: Don't erase spans which have not been modified + _span = []; + } + + private bool needRewrap; + private int lastStartingLine; + override protected void drawClient(DrawBuf buf) { // update matched braces if (!content.findMatchedBraces(_caretPos, _matchingBraces)) { @@ -3329,6 +3354,23 @@ class EditBox : EditWidgetBase { } Rect rc = _clientRect; + + if (_contentChanged) + needRewrap = true; + + if (rc.width <= 0 && _wordWrap) + { + return; + } + + bool doRewrap = false; + + if (needRewrap && _wordWrap) + { + resetVisibleSpans(); + needRewrap = false; + doRewrap = true; + } FontRef font = font(); for (int i = 0; i < _visibleLines.length; i++) { @@ -3344,7 +3386,7 @@ class EditBox : EditWidgetBase { drawLineBackground(buf, _firstVisibleLine + i, lineRect, visibleRect); if (_showTabPositionMarks) drawTabPositionMarks(buf, font, _firstVisibleLine + i, lineRect); - if (!txt.length) + if (!txt.length && !_wordWrap) continue; if (_showWhiteSpaceMarks) drawWhiteSpaceMarks(buf, font, txt, tabSize, lineRect, visibleRect); @@ -3354,12 +3396,39 @@ class EditBox : EditWidgetBase { leftPaneRect.left -= _leftPaneWidth; drawLeftPane(buf, leftPaneRect, 0); } - if (txt.length > 0) { + if (txt.length > 0 || _wordWrap) { CustomCharProps[] highlight = _visibleLinesHighlights[i]; - if (highlight) - font.drawColoredText(buf, rc.left - _scrollPos.x, rc.top + i * _lineHeight, txt, highlight, tabSize); + if (_wordWrap) + { + dstring[] wrappedLine; + if (doRewrap) + wrappedLine = wrapLine(txt, _firstVisibleLine + i); + else + if (i < _span.length) + wrappedLine = _span[i].wrappedContent; + int accumulativeLength; + CustomCharProps[] wrapProps; + foreach (int q, curWrap; wrappedLine) + { + auto lineOffset = q + i + wrapsUpTo(i); + if (highlight) + { + wrapProps = highlight[accumulativeLength .. $]; + accumulativeLength += curWrap.length; + font.drawColoredText(buf, rc.left - _scrollPos.x, rc.top + lineOffset * _lineHeight, curWrap, wrapProps, tabSize); + } + else + font.drawText(buf, rc.left - _scrollPos.x, rc.top + lineOffset * _lineHeight, curWrap, textColor, tabSize); + + } + } else - font.drawText(buf, rc.left - _scrollPos.x, rc.top + i * _lineHeight, txt, textColor, tabSize); + { + if (highlight) + font.drawColoredText(buf, rc.left - _scrollPos.x, rc.top + i * _lineHeight, txt, highlight, tabSize); + else + font.drawText(buf, rc.left - _scrollPos.x, rc.top + i * _lineHeight, txt, textColor, tabSize); + } } } From 05a8dd7bdcd8154293dadf8c400a9587d877709e Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 08:20:01 -0500 Subject: [PATCH 02/24] Using WrapPoint[] --- src/dlangui/widgets/editors.d | 112 +++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 2 deletions(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 2693b351..f9e658fd 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -391,13 +391,121 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction return this; } - dstring[] wrapLine(dstring line, int maxWidth) { - return []; + dchar[] splitChars = [' ', '-', '\t']; + + dstring[] wrapLine(dstring str, int lineNumber) { + FontRef font = font(); + dstring[] words = explode(str, splitChars); + int curLineLength = 0; + dchar[] buildingStr; + dstring[] buildingStrArr; + WrapPoint[] wrapPoints; + int wrappedLineCount = 0; + int curLineWidth = 0; + int maxWidth = _clientRect.width; + for (int i = 0; i < words.length; i++) + { + dstring word = words[i]; + if (curLineWidth + measureWrappedText(word) > maxWidth) + { + if (curLineWidth > 0) + { + buildingStrArr ~= to!dstring(buildingStr); + wrappedLineCount++; + wrapPoints ~= WrapPoint(curLineLength, curLineWidth); + curLineLength = 0; + curLineWidth = 0; + buildingStr = []; + } + while (measureWrappedText(word) > maxWidth) + { + //For when string still too long + int wrapPoint = findWrapPoint(word); + wrapPoints ~= WrapPoint(wrapPoint, measureWrappedText(word[0..wrapPoint])); + buildingStr ~= word[0 .. wrapPoint]; + word = word[wrapPoint .. $]; + buildingStrArr ~= to!dstring(buildingStr); + buildingStr = []; + wrappedLineCount++; + } + } + buildingStr ~= word; + curLineLength += to!int(word.length); + curLineWidth += measureWrappedText(word); + } + wrapPoints ~= WrapPoint(curLineLength, curLineWidth); + buildingStrArr ~= to!dstring(buildingStr); + _span ~= LineSpan(lineNumber, wrappedLineCount + 1, wrapPoints, buildingStrArr); + return buildingStrArr; } + dstring[] explode(dstring str, dchar[] splitChars) + { + dstring[] parts; + int startIndex = 0; + import std.string:indexOfAny; + while (true) + { + int index = to!int(str.indexOfAny(splitChars, startIndex)); + + if (index == -1) + { + parts ~= str[startIndex .. $]; + //Log.d("Explode output: ", parts); + return parts; + } + + dstring word = str[startIndex .. index]; + dchar nextChar = (str[index .. index + 1])[0]; + + import std.ascii:isWhite; + if (isWhite(nextChar)) + { + parts ~= word; + parts ~= to!dstring(nextChar); + } + else + { + parts ~= word ~ nextChar; + } + startIndex = index + 1; + } + } + /// information about line span into several lines - in word wrap mode protected LineSpan[] _span; + //Finds good visual wrapping point for string + int findWrapPoint(dstring text) + { + int maxWidth = _clientRect.width; + int wrapPoint = 0; + while (true) + { + if (measureWrappedText(text[0 .. wrapPoint]) < maxWidth) + { + wrapPoint++; + } + else + { + return wrapPoint; + } + } + } + + //Calls measureText for word wrap + int measureWrappedText(dstring text) + { + FontRef font = font(); + int[] measuredWidths; + measuredWidths.length = text.length; + //DO NOT REMOVE THIS + int boggle = font.measureText(text, measuredWidths); + if (measuredWidths.length > 0) + return measuredWidths[$-1]; + return 0; + } + int wrapsUpTo(int line) { if(line < _span.length) From 8df39f232b9146d0361c15c50c897383dbda7ee9 Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 08:23:07 -0500 Subject: [PATCH 03/24] Set need rewrap true by default --- src/dlangui/widgets/editors.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index f9e658fd..e383c65c 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -3451,7 +3451,7 @@ class EditBox : EditWidgetBase { _span = []; } - private bool needRewrap; + private bool needRewrap = true; private int lastStartingLine; override protected void drawClient(DrawBuf buf) { From 761a7bc821ff0e2477782ac7ae52084678a22e86 Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 08:50:59 -0500 Subject: [PATCH 04/24] Sort of working --- src/dlangui/widgets/editors.d | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index e383c65c..afc84b2a 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -474,6 +474,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction /// information about line span into several lines - in word wrap mode protected LineSpan[] _span; + protected LineSpan[] _spanCache; //Finds good visual wrapping point for string int findWrapPoint(dstring text) @@ -508,7 +509,14 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction int wrapsUpTo(int line) { - if(line < _span.length) + int sum; + lineSpanIterate(delegate(int wantedLine, int wantedWrap) + { + if (wantedLine < line) + sum += _span[wantedLine].len - 1; + }); + return sum; + /*if(line < _span.length) { int sum; @@ -518,8 +526,19 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction } //Log.d(sum); return sum; + }*/ + //return 0; + } + + void lineSpanIterate(void delegate(int wantedLine, int wantedWrap) iterator) + { + for (int i; i<_span.length; i++) + { + for (int q; q<_span[i].wrapPoints.length; q++) + { + iterator(i, q); + } } - return 0; } /// override to add custom items on left panel From 64dab5989e157c7ff9254dc504785a265bb7830e Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 08:55:00 -0500 Subject: [PATCH 05/24] Working now --- src/dlangui/widgets/editors.d | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index afc84b2a..6dc5fb7e 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -510,35 +510,18 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction int wrapsUpTo(int line) { int sum; - lineSpanIterate(delegate(int wantedLine, int wantedWrap) + lineSpanIterate(delegate(LineSpan curSpan) { - if (wantedLine < line) - sum += _span[wantedLine].len - 1; + if (curSpan.start < line) + sum += curSpan.len - 1; }); return sum; - /*if(line < _span.length) - { - - int sum; - for(int i = 0; i<line; i++) - { - sum += _span[i].len - 1; - } - //Log.d(sum); - return sum; - }*/ - //return 0; } - void lineSpanIterate(void delegate(int wantedLine, int wantedWrap) iterator) + void lineSpanIterate(void delegate(LineSpan curSpan) iterator) { - for (int i; i<_span.length; i++) - { - for (int q; q<_span[i].wrapPoints.length; q++) - { - iterator(i, q); - } - } + foreach (currentSpan; _span) + iterator(currentSpan); } /// override to add custom items on left panel From ad6d547812bf688ea292ca555d4a26e4b3f66ef3 Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 09:19:02 -0500 Subject: [PATCH 06/24] Even better, scrolling --- src/dlangui/widgets/editors.d | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 6dc5fb7e..fcc80671 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -3468,6 +3468,12 @@ class EditBox : EditWidgetBase { if (_contentChanged) needRewrap = true; + if (lastStartingLine != _firstVisibleLine) + { + needRewrap = true; + lastStartingLine = _firstVisibleLine; + } + if (rc.width <= 0 && _wordWrap) { return; @@ -3520,7 +3526,7 @@ class EditBox : EditWidgetBase { CustomCharProps[] wrapProps; foreach (int q, curWrap; wrappedLine) { - auto lineOffset = q + i + wrapsUpTo(i); + auto lineOffset = q + i + wrapsUpTo(i + _firstVisibleLine); if (highlight) { wrapProps = highlight[accumulativeLength .. $]; From 72187063bd3272e227728556c4a8e0aba340990f Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 09:38:35 -0500 Subject: [PATCH 07/24] findWrapLine and getSpan added into the mix --- src/dlangui/widgets/editors.d | 38 ++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index fcc80671..44cb04e3 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -518,6 +518,36 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction return sum; } + LineSpan getSpan(int lineNumber) + { + LineSpan lineSpan = LineSpan(lineNumber, 0, [], []); + lineSpanIterate(delegate(LineSpan curSpan) + { + if (curSpan.start == lineNumber) + lineSpan = curSpan; + }); + return lineSpan; + } + + int findWrapLine(TextPosition textPos) + { + int curLine = 0; + int curPosition = textPos.pos; + int i = 0; + while (true) + { + if (i == getSpan(textPos.line).wrapPoints.length - 1) + return curLine; + curPosition -= getSpan(textPos.line).wrapPoints[i].wrapPos; + if (curPosition < 0) + { + return curLine; + } + curLine++; + i++; + } + } + void lineSpanIterate(void delegate(LineSpan curSpan) iterator) { foreach (currentSpan; _span) @@ -1249,7 +1279,13 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction caretRc.right += _spaceWidth; } } - caretRc.offset(_clientRect.left, _clientRect.top); + if (_wordWrap) + { + _scrollPos.x = 0; + caretRc.offset(_clientRect.left, _clientRect.top); + } + else + caretRc.offset(_clientRect.left, _clientRect.top); return caretRc; } From d39fadd1d07e073771960d72d6294cb40cc7bc1f Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 09:59:15 -0500 Subject: [PATCH 08/24] CaretRect in progress --- src/dlangui/core/editable.d | 16 +++++++++++++++- src/dlangui/widgets/editors.d | 16 +++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/dlangui/core/editable.d b/src/dlangui/core/editable.d index 3a781b36..b6f8e4de 100644 --- a/src/dlangui/core/editable.d +++ b/src/dlangui/core/editable.d @@ -452,8 +452,22 @@ struct LineSpan { int len; /// the wrapping points WrapPoint[] wrapPoints; - + /// the wrapped text dstring[] wrappedContent; + + int widthAccumulation(int wrapLine) + { + int widthTotal; + for (int i; i < wrapLine; i++) + { + if (i < this.wrapPoints.length - 1) + { + int curWidth = this.wrapPoints[i].wrapWidth; + widthTotal += curWidth; + } + } + return widthTotal; + } } struct WrapPoint { diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 44cb04e3..79f73803 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -1264,6 +1264,8 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction handleAction(ACTION_EDITOR_SELECT_ALL); super.handleFocusChange(focused); } + + protected int _firstVisibleLine; /// returns cursor rectangle protected Rect caretRect() { @@ -1280,10 +1282,18 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction } } if (_wordWrap) + { + _scrollPos.x = 0; + int wrapLine = findWrapLine(_caretPos); + int xOffset; + if (wrapLine > 0) { - _scrollPos.x = 0; - caretRc.offset(_clientRect.left, _clientRect.top); + LineSpan curSpan = getSpan(_caretPos.line); + xOffset = curSpan.widthAccumulation(wrapLine); } + auto yOffset = -1 * _lineHeight * (wrapsUpTo(_caretPos.line - _firstVisibleLine) + wrapLine); + caretRc.offset(_clientRect.left - xOffset, _clientRect.top - yOffset); + } else caretRc.offset(_clientRect.left, _clientRect.top); return caretRc; @@ -2470,7 +2480,7 @@ class EditBox : EditWidgetBase { } } - protected int _firstVisibleLine; + //protected int _firstVisibleLine; protected int _maxLineWidth; protected int _numVisibleLines; // number of lines visible in client area From e58538de60b5d7fde1f2f1142ad08112f3788cdf Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 10:09:51 -0500 Subject: [PATCH 09/24] Improved caret offset, put placeholder linespan into place --- src/dlangui/widgets/editors.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 79f73803..1a5d68be 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -520,7 +520,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction LineSpan getSpan(int lineNumber) { - LineSpan lineSpan = LineSpan(lineNumber, 0, [], []); + LineSpan lineSpan = LineSpan(lineNumber, 0, [WrapPoint(0,0)], []); lineSpanIterate(delegate(LineSpan curSpan) { if (curSpan.start == lineNumber) @@ -1291,7 +1291,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction LineSpan curSpan = getSpan(_caretPos.line); xOffset = curSpan.widthAccumulation(wrapLine); } - auto yOffset = -1 * _lineHeight * (wrapsUpTo(_caretPos.line - _firstVisibleLine) + wrapLine); + auto yOffset = -1 * _lineHeight * (wrapsUpTo(_caretPos.line) + wrapLine); caretRc.offset(_clientRect.left - xOffset, _clientRect.top - yOffset); } else From 7c500bd57a819404c34251d90cdf9592d0e3a025 Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 11:26:21 -0500 Subject: [PATCH 10/24] drawExtendedArea --- src/dlangui/widgets/editors.d | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 1a5d68be..4a6a252c 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -3320,8 +3320,28 @@ class EditBox : EditWidgetBase { if (lineRect.top >= _clientRect.bottom) break; drawLeftPane(buf, lineRect, i < lc ? i : -1); - i++; rc.top += _lineHeight; + if (_wordWrap) + { + int currentWrap = 1; + for (;;) + { + LineSpan curSpan = getSpan(i); + if (currentWrap > curSpan.len - 1) + break; + Rect lineRect2 = rc; + lineRect2.left = _clientRect.left - _leftPaneWidth; + lineRect2.right = _clientRect.left; + lineRect2.bottom = lineRect.top + _lineHeight; + if (lineRect2.top >= _clientRect.bottom) + break; + drawLeftPane(buf, lineRect2, -1); + rc.top += _lineHeight; + + currentWrap++; + } + } + i++; } } From ce39c13e316b3eacdeadea7a150c899d2d350930 Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 11:36:38 -0500 Subject: [PATCH 11/24] Don't horizontal scroll in word wrap mode --- src/dlangui/widgets/editors.d | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 4a6a252c..6384671e 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -2771,7 +2771,8 @@ class EditBox : EditWidgetBase { invalidate(); } else if (rc.left >= _clientRect.width - 10) { // scroll right - _scrollPos.x += (rc.left - _clientRect.width) + _clientRect.width / 4; + if (!_wordWrap) + _scrollPos.x += (rc.left - _clientRect.width) + _clientRect.width / 4; invalidate(); } updateScrollBars(); From 83a2f2ef5c26b49ab87608dda6010e7d89c189cc Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 11:56:00 -0500 Subject: [PATCH 12/24] Changed accumulation to work for both points and widths --- src/dlangui/core/editable.d | 16 +++++++++++----- src/dlangui/widgets/editors.d | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/dlangui/core/editable.d b/src/dlangui/core/editable.d index b6f8e4de..16de7294 100644 --- a/src/dlangui/core/editable.d +++ b/src/dlangui/core/editable.d @@ -455,18 +455,24 @@ struct LineSpan { /// the wrapped text dstring[] wrappedContent; - int widthAccumulation(int wrapLine) + enum WrapPointInfo : bool { + Position, + Width, + } + + int accumulation(int wrapLine, bool wrapPointInfo) { - int widthTotal; + int total; for (int i; i < wrapLine; i++) { if (i < this.wrapPoints.length - 1) { - int curWidth = this.wrapPoints[i].wrapWidth; - widthTotal += curWidth; + int curVal; + curVal = wrapPointInfo ? this.wrapPoints[i].wrapWidth : this.wrapPoints[i].wrapPos; + total += curVal; } } - return widthTotal; + return total; } } diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 6384671e..d805b2e6 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -1289,7 +1289,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction if (wrapLine > 0) { LineSpan curSpan = getSpan(_caretPos.line); - xOffset = curSpan.widthAccumulation(wrapLine); + xOffset = curSpan.accumulation(wrapLine, LineSpan.WrapPointInfo.Width); } auto yOffset = -1 * _lineHeight * (wrapsUpTo(_caretPos.line) + wrapLine); caretRc.offset(_clientRect.left - xOffset, _clientRect.top - yOffset); From bc40bbf561d7cb5e95d90b468ad368a6d3626b99 Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 12:37:20 -0500 Subject: [PATCH 13/24] Removed some redundant parts from findWrapLine --- src/dlangui/widgets/editors.d | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index d805b2e6..68358af2 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -531,20 +531,18 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction int findWrapLine(TextPosition textPos) { - int curLine = 0; + int curWrapLine = 0; int curPosition = textPos.pos; - int i = 0; while (true) { - if (i == getSpan(textPos.line).wrapPoints.length - 1) - return curLine; - curPosition -= getSpan(textPos.line).wrapPoints[i].wrapPos; + if (curWrapLine == getSpan(textPos.line).wrapPoints.length - 1) + return curWrapLine; + curPosition -= getSpan(textPos.line).wrapPoints[curWrapLine].wrapPos; if (curPosition < 0) { - return curLine; + return curWrapLine; } - curLine++; - i++; + curWrapLine++; } } From bd721d590ee22ca58284fb6b3c45a0620b84cf3e Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 12:40:32 -0500 Subject: [PATCH 14/24] Improved efficiency a bit --- src/dlangui/widgets/editors.d | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 68358af2..338bfecf 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -533,11 +533,12 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction { int curWrapLine = 0; int curPosition = textPos.pos; + LineSpan curSpan = getSpan(textPos.line); while (true) { - if (curWrapLine == getSpan(textPos.line).wrapPoints.length - 1) + if (curWrapLine == curSpan.wrapPoints.length - 1) return curWrapLine; - curPosition -= getSpan(textPos.line).wrapPoints[curWrapLine].wrapPos; + curPosition -= curSpan.wrapPoints[curWrapLine].wrapPos; if (curPosition < 0) { return curWrapLine; From 422517aff49fdce2cb0ab6001f49de269e42311e Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 13:02:13 -0500 Subject: [PATCH 15/24] Caret movement --- src/dlangui/widgets/editors.d | 68 +++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 338bfecf..57b91f53 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -2848,17 +2848,73 @@ class EditBox : EditWidgetBase { return true; case Up: case SelectUp: - if (_caretPos.line > 0) { - _caretPos.line--; - correctCaretPos(); - updateSelectionAfterCursorMovement(oldCaretPos, (a.id & 1) != 0); - ensureCaretVisible(); + if ((_caretPos.line > 0) | wordWrap) { + if (_wordWrap) + { + LineSpan curSpan = getSpan(_caretPos.line); + int curWrap = findWrapLine(_caretPos); + if (curWrap > 0) + { + _caretPos.pos-= curSpan.wrapPoints[curWrap - 1].wrapPos; + } + else + { + int previousPos = _caretPos.pos; + curSpan = getSpan(_caretPos.line - 1); + curWrap = curSpan.len - 1; + if (curWrap > 0) + { + int accumulativePoint = curSpan.accumulation(curSpan.len - 1, LineSpan.WrapPointInfo.Position); + _caretPos.line--; + _caretPos.pos = accumulativePoint + previousPos; + } + else + { + _caretPos.line--; + } + } + } + else if(_caretPos.line > 0) + _caretPos.line--; + correctCaretPos(); + updateSelectionAfterCursorMovement(oldCaretPos, (a.id & 1) != 0); + ensureCaretVisible(); } return true; case Down: case SelectDown: if (_caretPos.line < _content.length - 1) { - _caretPos.line++; + if (_wordWrap) + { + LineSpan curSpan = getSpan(_caretPos.line); + int curWrap = findWrapLine(_caretPos); + if (curWrap < curSpan.len - 1) + { + int previousPos = _caretPos.pos; + _caretPos.pos+= curSpan.wrapPoints[curWrap].wrapPos; + correctCaretPos(); + if (_caretPos.pos == previousPos) + { + _caretPos.pos = 0; + _caretPos.line++; + } + } + else if (curSpan.len > 1) + { + int previousPos = _caretPos.pos; + int previousAccumulatedPosition = curSpan.accumulation(curSpan.len - 1, LineSpan.WrapPointInfo.Position); + _caretPos.line++; + _caretPos.pos = previousPos - previousAccumulatedPosition; + } + else + { + _caretPos.line++; + } + } + else + { + _caretPos.line++; + } correctCaretPos(); updateSelectionAfterCursorMovement(oldCaretPos, (a.id & 1) != 0); ensureCaretVisible(); From 71931c8e43f5bd0b3e1710c3b0a19aae9657e624 Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 17:41:18 -0500 Subject: [PATCH 16/24] Basic implementation for highlighting text selection in word wrap --- src/dlangui/widgets/editors.d | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 57b91f53..55d6ca89 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -3336,7 +3336,23 @@ class EditBox : EditWidgetBase { Rect rc = lineRect; rc.left = startx; rc.right = endx; - if (!rc.empty) { + if (!rc.empty && _wordWrap) + { + auto limitNumber = (int num, int limit) => num > limit ? limit : num; + LineSpan curSpan = getSpan(lineIndex); + int yOffset = _lineHeight * (wrapsUpTo(lineIndex)); + rc.offset(0, yOffset); + Rect[] wrappedSelection; + wrappedSelection.length = curSpan.len; + foreach (int i, wrapLineRect; wrappedSelection) + { + wrapLineRect = rc; + wrapLineRect.offset(-1 * curSpan.accumulation(i, LineSpan.WrapPointInfo.Width), i * _lineHeight); + wrapLineRect.right = limitNumber(wrapLineRect.right,(rc.left + curSpan.wrapPoints[i].wrapWidth)); + buf.fillRect(wrapLineRect, focused ? _selectionColorFocused : _selectionColorNormal); + } + } + else if (!rc.empty) { // draw selection rect for line buf.fillRect(rc, focused ? _selectionColorFocused : _selectionColorNormal); } From d28eab7e9dc2e2c78b7e558cdc6527f2c14eaf4a Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 18:22:39 -0500 Subject: [PATCH 17/24] highlightLineRange implemented like last --- src/dlangui/widgets/editors.d | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 55d6ca89..7fc2ed7f 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -3315,7 +3315,24 @@ class EditBox : EditWidgetBase { Rect rc = lineRect; rc.left = _clientRect.left + startrc.left; rc.right = _clientRect.left + endrc.right; - if (!rc.empty) { + if (_wordWrap && !rc.empty) + { + auto limitNumber = (int num, int limit) => num > limit ? limit : num; + LineSpan curSpan = getSpan(r.start.line); + int yOffset = _lineHeight * (wrapsUpTo(r.start.line)); + rc.offset(0, yOffset); + Rect[] wrappedSelection; + wrappedSelection.length = curSpan.len; + foreach (int i, wrapLineRect; wrappedSelection) + { + wrapLineRect = rc; + wrapLineRect.offset(-1 * curSpan.accumulation(i, LineSpan.WrapPointInfo.Width), i * _lineHeight); + wrapLineRect.right = limitNumber(wrapLineRect.right,(rc.left + curSpan.wrapPoints[i].wrapWidth)); + //buf.fillRect(wrapLineRect, focused ? _selectionColorFocused : _selectionColorNormal); + buf.fillRect(wrapLineRect, color); + } + } + else if (!rc.empty) { // draw selection rect for matching bracket buf.fillRect(rc, color); } From 3463fec39d8ca18d770438c6bb79dc483acb03a4 Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Thu, 11 Jan 2018 19:55:28 -0500 Subject: [PATCH 18/24] Made function for filling rect in word wrap --- src/dlangui/widgets/editors.d | 47 +++++++++++++++-------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 7fc2ed7f..bb1cc046 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -3317,26 +3317,31 @@ class EditBox : EditWidgetBase { rc.right = _clientRect.left + endrc.right; if (_wordWrap && !rc.empty) { - auto limitNumber = (int num, int limit) => num > limit ? limit : num; - LineSpan curSpan = getSpan(r.start.line); - int yOffset = _lineHeight * (wrapsUpTo(r.start.line)); - rc.offset(0, yOffset); - Rect[] wrappedSelection; - wrappedSelection.length = curSpan.len; - foreach (int i, wrapLineRect; wrappedSelection) - { - wrapLineRect = rc; - wrapLineRect.offset(-1 * curSpan.accumulation(i, LineSpan.WrapPointInfo.Width), i * _lineHeight); - wrapLineRect.right = limitNumber(wrapLineRect.right,(rc.left + curSpan.wrapPoints[i].wrapWidth)); - //buf.fillRect(wrapLineRect, focused ? _selectionColorFocused : _selectionColorNormal); - buf.fillRect(wrapLineRect, color); - } + wordWrapFillRect(buf, r.start.line, rc, color); } else if (!rc.empty) { // draw selection rect for matching bracket buf.fillRect(rc, color); } } + + void wordWrapFillRect(DrawBuf buf, int line, Rect lineToDivide, uint color) + { + Rect rc = lineToDivide; + auto limitNumber = (int num, int limit) => num > limit ? limit : num; + LineSpan curSpan = getSpan(line); + int yOffset = _lineHeight * (wrapsUpTo(line)); + rc.offset(0, yOffset); + Rect[] wrappedSelection; + wrappedSelection.length = curSpan.len; + foreach (int i, wrapLineRect; wrappedSelection) + { + wrapLineRect = rc; + wrapLineRect.offset(-1 * curSpan.accumulation(i, LineSpan.WrapPointInfo.Width), i * _lineHeight); + wrapLineRect.right = limitNumber(wrapLineRect.right,(rc.left + curSpan.wrapPoints[i].wrapWidth)); + buf.fillRect(wrapLineRect, color); + } + } /// override to custom highlight of line background protected void drawLineBackground(DrawBuf buf, int lineIndex, Rect lineRect, Rect visibleRect) { @@ -3355,19 +3360,7 @@ class EditBox : EditWidgetBase { rc.right = endx; if (!rc.empty && _wordWrap) { - auto limitNumber = (int num, int limit) => num > limit ? limit : num; - LineSpan curSpan = getSpan(lineIndex); - int yOffset = _lineHeight * (wrapsUpTo(lineIndex)); - rc.offset(0, yOffset); - Rect[] wrappedSelection; - wrappedSelection.length = curSpan.len; - foreach (int i, wrapLineRect; wrappedSelection) - { - wrapLineRect = rc; - wrapLineRect.offset(-1 * curSpan.accumulation(i, LineSpan.WrapPointInfo.Width), i * _lineHeight); - wrapLineRect.right = limitNumber(wrapLineRect.right,(rc.left + curSpan.wrapPoints[i].wrapWidth)); - buf.fillRect(wrapLineRect, focused ? _selectionColorFocused : _selectionColorNormal); - } + wordWrapFillRect(buf, lineIndex, rc, focused ? _selectionColorFocused : _selectionColorNormal); } else if (!rc.empty) { // draw selection rect for line From d2caa2a1a783be606276182396d9bd32c57ed6fa Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Fri, 12 Jan 2018 07:17:09 -0500 Subject: [PATCH 19/24] EnsureCaretVisible for word wrap --- src/dlangui/widgets/editors.d | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index bb1cc046..a053bd57 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -1266,6 +1266,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction protected int _firstVisibleLine; + protected int caretHeightOffset; /// returns cursor rectangle protected Rect caretRect() { Rect caretRc = textPosToClient(_caretPos); @@ -1291,6 +1292,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction xOffset = curSpan.accumulation(wrapLine, LineSpan.WrapPointInfo.Width); } auto yOffset = -1 * _lineHeight * (wrapsUpTo(_caretPos.line) + wrapLine); + caretHeightOffset = yOffset; caretRc.offset(_clientRect.left - xOffset, _clientRect.top - yOffset); } else @@ -2743,6 +2745,22 @@ class EditBox : EditWidgetBase { _firstVisibleLine = maxFirstVisibleLine; measureVisibleText(); invalidate(); + } else if(_wordWrap && !(_firstVisibleLine > maxFirstVisibleLine)) { + //For wordwrap mode, move down sooner + int offsetLines = -1 * caretHeightOffset / _lineHeight; + //Log.d("offsetLines: ", offsetLines); + if (_caretPos.line >= _firstVisibleLine + visibleLines - offsetLines) + { + _firstVisibleLine = _caretPos.line - visibleLines + 1 + offsetLines; + if (center) + _firstVisibleLine += visibleLines / 2; + if (_firstVisibleLine > maxFirstVisibleLine) + _firstVisibleLine = maxFirstVisibleLine; + if (_firstVisibleLine < 0) + _firstVisibleLine = 0; + measureVisibleText(); + invalidate(); + } } else if (_caretPos.line >= _firstVisibleLine + visibleLines) { _firstVisibleLine = _caretPos.line - visibleLines + 1; if (center) From 278ecc75ebfa6e88b40c712d3264c3fc52556e1f Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Fri, 12 Jan 2018 08:09:37 -0500 Subject: [PATCH 20/24] Word wrap mouse offset --- src/dlangui/widgets/editors.d | 48 ++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index a053bd57..327b1f0a 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -1434,10 +1434,52 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction _textToHighlightOptions = textToHighlightOptions; invalidate(); } + + protected TextPosition wordWrapMouseOffset(int x, int y) + { + if(_span.length == 0) + return clientToTextPos(Point(x,y)); + int selectedVisibleLine = y / _lineHeight; + + LineSpan _curSpan; + + int wrapLine = 0; + int curLine = 0; + bool foundWrap = false; + int accumulativeWidths = 0; + int curWrapOfSpan = 0; + + lineSpanIterate(delegate(LineSpan curSpan){ + while (!foundWrap) + { + if (wrapLine == selectedVisibleLine) + { + foundWrap = true; + break; + } + accumulativeWidths += curSpan.wrapPoints[curWrapOfSpan].wrapWidth; + wrapLine++; + curWrapOfSpan++; + if (curWrapOfSpan >= curSpan.len) + { + break; + } + } + if (!foundWrap) + { + accumulativeWidths = 0; + curLine++; + } + curWrapOfSpan = 0; + }); + + int fakeLineHeight = curLine * _lineHeight; + return clientToTextPos(Point(x + accumulativeWidths,fakeLineHeight)); + } protected void selectWordByMouse(int x, int y) { TextPosition oldCaretPos = _caretPos; - TextPosition newPos = clientToTextPos(Point(x,y)); + TextPosition newPos = _wordWrap ? wordWrapMouseOffset(x,y) : clientToTextPos(Point(x,y)); TextRange r = content.wordBounds(newPos); if (r.start < r.end) { _selectionRange = r; @@ -1453,7 +1495,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction protected void selectLineByMouse(int x, int y, bool onSameLineOnly = true) { TextPosition oldCaretPos = _caretPos; - TextPosition newPos = clientToTextPos(Point(x,y)); + TextPosition newPos = _wordWrap ? wordWrapMouseOffset(x,y) : clientToTextPos(Point(x,y)); if (onSameLineOnly && newPos.line != oldCaretPos.line) return; // different lines TextRange r = content.lineRange(newPos.line); @@ -1471,7 +1513,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction protected void updateCaretPositionByMouse(int x, int y, bool selecting) { TextPosition oldCaretPos = _caretPos; - TextPosition newPos = clientToTextPos(Point(x,y)); + TextPosition newPos = _wordWrap ? wordWrapMouseOffset(x,y) : clientToTextPos(Point(x,y)); if (newPos != _caretPos) { _caretPos = newPos; updateSelectionAfterCursorMovement(oldCaretPos, selecting); From 87f4a8a918fd9d611f7f404a829400e3caa3f8cc Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Fri, 12 Jan 2018 09:10:29 -0500 Subject: [PATCH 21/24] Small additions from previous implementation --- src/dlangui/widgets/editors.d | 38 +++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 327b1f0a..588dd7be 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -379,6 +379,10 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction return 1; } + //Override for EditBox + void wordWrapRefresh(){return;} + + int previousXScrollPos; protected bool _wordWrap; /// true if word wrap mode is set @property bool wordWrap() { @@ -387,6 +391,19 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction /// true if word wrap mode is set @property EditWidgetBase wordWrap(bool v) { _wordWrap = v; + //Horizontal scrollbar should not be visible in word wrap mode + if (v) + { + _hscrollbar.visibility(Visibility.Invisible); + previousXScrollPos = _scrollPos.x; + _scrollPos.x = 0; + wordWrapRefresh(); + } + else + { + _hscrollbar.visibility(Visibility.Visible); + _scrollPos.x = previousXScrollPos; + } invalidate(); return this; } @@ -2537,6 +2554,17 @@ class EditBox : EditWidgetBase { protected dstring _textToSetWidgetSize = "aaaaa/naaaaa"d; protected int[] _measuredTextToSetWidgetSizeWidths; + override void wordWrapRefresh() + { + needRewrap = true; + } + + override @property int fontSize() const { return super.fontSize(); } + override @property Widget fontSize(int size) { + needRewrap = true; + return super.fontSize(size); + } + override protected int lineCount() { return _content.length; } @@ -2590,6 +2618,7 @@ class EditBox : EditWidgetBase { super.layout(contentRc); if (_contentChanged) { measureVisibleText(); + needRewrap = true; _contentChanged = false; } @@ -3134,6 +3163,7 @@ class EditBox : EditWidgetBase { Log.i("Font size in editor ", id, " zoomed to ", newFontSize); fontSize = cast(ushort)newFontSize; updateFontProps(); + needRewrap = true; measureVisibleText(); updateScrollBars(); invalidate(); @@ -3396,9 +3426,10 @@ class EditBox : EditWidgetBase { wrappedSelection.length = curSpan.len; foreach (int i, wrapLineRect; wrappedSelection) { + int startingDifference = rc.left - _clientRect.left; wrapLineRect = rc; wrapLineRect.offset(-1 * curSpan.accumulation(i, LineSpan.WrapPointInfo.Width), i * _lineHeight); - wrapLineRect.right = limitNumber(wrapLineRect.right,(rc.left + curSpan.wrapPoints[i].wrapWidth)); + wrapLineRect.right = limitNumber(wrapLineRect.right,(rc.left + curSpan.wrapPoints[i].wrapWidth) - startingDifference); buf.fillRect(wrapLineRect, color); } } @@ -3441,6 +3472,9 @@ class EditBox : EditWidgetBase { // frame around current line if (focused && lineIndex == _caretPos.line && _selectionRange.singleLine && _selectionRange.start.line == _caretPos.line) { + //TODO: Figure out why a little slow to catch up + if (_wordWrap) + visibleRect.offset(0, -caretHeightOffset); buf.drawFrame(visibleRect, 0xA0808080, Rect(1,1,1,1)); } @@ -3657,7 +3691,7 @@ class EditBox : EditWidgetBase { void resetVisibleSpans() { - //TODO: Don't erase spans which have not been modified + //TODO: Don't erase spans which have not been modified, cache them _span = []; } From f40ae806da97ea99b86ab0a0d277f5359a6eb2d9 Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Fri, 12 Jan 2018 09:47:43 -0500 Subject: [PATCH 22/24] Whitespace marks --- src/dlangui/widgets/editors.d | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 588dd7be..b2e550ac 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -3731,6 +3731,7 @@ class EditBox : EditWidgetBase { } FontRef font = font(); + int previousWraps; for (int i = 0; i < _visibleLines.length; i++) { dstring txt = _visibleLines[i]; Rect lineRect; @@ -3747,7 +3748,16 @@ class EditBox : EditWidgetBase { if (!txt.length && !_wordWrap) continue; if (_showWhiteSpaceMarks) - drawWhiteSpaceMarks(buf, font, txt, tabSize, lineRect, visibleRect); + { + Rect whiteSpaceRc = lineRect; + Rect whiteSpaceRcVisible = visibleRect; + for(int z; z < previousWraps; z++) + { + whiteSpaceRc.offset(0, _lineHeight); + whiteSpaceRcVisible.offset(0, _lineHeight); + } + drawWhiteSpaceMarks(buf, font, txt, tabSize, whiteSpaceRc, whiteSpaceRcVisible); + } if (_leftPaneWidth > 0) { Rect leftPaneRect = visibleRect; leftPaneRect.right = leftPaneRect.left; @@ -3779,6 +3789,7 @@ class EditBox : EditWidgetBase { font.drawText(buf, rc.left - _scrollPos.x, rc.top + lineOffset * _lineHeight, curWrap, textColor, tabSize); } + previousWraps += to!int(wrappedLine.length - 1); } else { From 435c10c662438f1c87401eb89ec5b894be3b1101 Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Fri, 12 Jan 2018 11:14:57 -0500 Subject: [PATCH 23/24] Added comments, renamed variable --- src/dlangui/core/editable.d | 4 +++ src/dlangui/widgets/editors.d | 46 +++++++++++++++++++++++------------ 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/dlangui/core/editable.d b/src/dlangui/core/editable.d index 16de7294..acbb2ea2 100644 --- a/src/dlangui/core/editable.d +++ b/src/dlangui/core/editable.d @@ -460,6 +460,7 @@ struct LineSpan { Width, } + ///Adds up either positions or widths to a wrapLine int accumulation(int wrapLine, bool wrapPointInfo) { int total; @@ -476,8 +477,11 @@ struct LineSpan { } } +///Holds info about a word wrapping point struct WrapPoint { + ///The relative wrapping position (related to TextPosition.pos) int wrapPos; + ///The associated calculated width of the wrapLine int wrapWidth; } diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index b2e550ac..70d16826 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -379,10 +379,12 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction return 1; } - //Override for EditBox + /// Override for EditBox void wordWrapRefresh(){return;} + /// To hold _scrollpos.x toggling between normal and word wrap mode int previousXScrollPos; + protected bool _wordWrap; /// true if word wrap mode is set @property bool wordWrap() { @@ -408,8 +410,10 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction return this; } + /// Characters at which content is split for word wrap mode dchar[] splitChars = [' ', '-', '\t']; + /// Divides up a string for word wrapping, sets info in _span dstring[] wrapLine(dstring str, int lineNumber) { FontRef font = font(); dstring[] words = explode(str, splitChars); @@ -456,6 +460,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction return buildingStrArr; } + /// Divide (and conquer) text into words dstring[] explode(dstring str, dchar[] splitChars) { dstring[] parts; @@ -493,7 +498,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction protected LineSpan[] _span; protected LineSpan[] _spanCache; - //Finds good visual wrapping point for string + /// Finds good visual wrapping point for string int findWrapPoint(dstring text) { int maxWidth = _clientRect.width; @@ -511,7 +516,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction } } - //Calls measureText for word wrap + /// Calls measureText for word wrap int measureWrappedText(dstring text) { FontRef font = font(); @@ -524,6 +529,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction return 0; } + /// Returns number of visible wraps up to a line (not including the first wrapLines themselves) int wrapsUpTo(int line) { int sum; @@ -535,6 +541,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction return sum; } + /// Returns LineSpan for line based on actual line number LineSpan getSpan(int lineNumber) { LineSpan lineSpan = LineSpan(lineNumber, 0, [WrapPoint(0,0)], []); @@ -546,6 +553,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction return lineSpan; } + /// Based on a TextPosition, finds which wrapLine it is on for its current line int findWrapLine(TextPosition textPos) { int curWrapLine = 0; @@ -564,8 +572,10 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction } } + /// Simple way of iterating through _span void lineSpanIterate(void delegate(LineSpan curSpan) iterator) { + //TODO: Rename iterator to iteration? foreach (currentSpan; _span) iterator(currentSpan); } @@ -1283,7 +1293,9 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction protected int _firstVisibleLine; + //In word wrap mode, set by caretRect so ensureCaretVisible will know when to scroll protected int caretHeightOffset; + /// returns cursor rectangle protected Rect caretRect() { Rect caretRc = textPosToClient(_caretPos); @@ -1452,6 +1464,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction invalidate(); } + /// Used instead of using clientToTextPos for mouse input when in word wrap mode protected TextPosition wordWrapMouseOffset(int x, int y) { if(_span.length == 0) @@ -2554,14 +2567,16 @@ class EditBox : EditWidgetBase { protected dstring _textToSetWidgetSize = "aaaaa/naaaaa"d; protected int[] _measuredTextToSetWidgetSizeWidths; + /// Set _needRewrap to true; override void wordWrapRefresh() { - needRewrap = true; + _needRewrap = true; } override @property int fontSize() const { return super.fontSize(); } override @property Widget fontSize(int size) { - needRewrap = true; + // Need to rewrap if fontSize changed + _needRewrap = true; return super.fontSize(size); } @@ -2618,7 +2633,7 @@ class EditBox : EditWidgetBase { super.layout(contentRc); if (_contentChanged) { measureVisibleText(); - needRewrap = true; + _needRewrap = true; _contentChanged = false; } @@ -3163,7 +3178,7 @@ class EditBox : EditWidgetBase { Log.i("Font size in editor ", id, " zoomed to ", newFontSize); fontSize = cast(ushort)newFontSize; updateFontProps(); - needRewrap = true; + _needRewrap = true; measureVisibleText(); updateScrollBars(); invalidate(); @@ -3415,6 +3430,7 @@ class EditBox : EditWidgetBase { } } + /// Used in place of directly calling buf.fillRect in word wrap mode void wordWrapFillRect(DrawBuf buf, int line, Rect lineToDivide, uint color) { Rect rc = lineToDivide; @@ -3689,13 +3705,14 @@ class EditBox : EditWidgetBase { } } + /// Clear _span void resetVisibleSpans() { //TODO: Don't erase spans which have not been modified, cache them _span = []; } - private bool needRewrap = true; + private bool _needRewrap = true; private int lastStartingLine; override protected void drawClient(DrawBuf buf) { @@ -3708,25 +3725,22 @@ class EditBox : EditWidgetBase { Rect rc = _clientRect; if (_contentChanged) - needRewrap = true; - + _needRewrap = true; if (lastStartingLine != _firstVisibleLine) { - needRewrap = true; + _needRewrap = true; lastStartingLine = _firstVisibleLine; } - if (rc.width <= 0 && _wordWrap) { + //Prevent drawClient from getting stuck in loop return; } - bool doRewrap = false; - - if (needRewrap && _wordWrap) + if (_needRewrap && _wordWrap) { resetVisibleSpans(); - needRewrap = false; + _needRewrap = false; doRewrap = true; } From cfff2982e8c525528dec6fff5c0e80c4487b3896 Mon Sep 17 00:00:00 2001 From: James Johnson <triplejam@protonmail.com> Date: Fri, 12 Jan 2018 12:00:38 -0500 Subject: [PATCH 24/24] Moved back to EditBox --- src/dlangui/widgets/editors.d | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 70d16826..5236eaf4 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -1290,8 +1290,6 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction handleAction(ACTION_EDITOR_SELECT_ALL); super.handleFocusChange(focused); } - - protected int _firstVisibleLine; //In word wrap mode, set by caretRect so ensureCaretVisible will know when to scroll protected int caretHeightOffset; @@ -2553,7 +2551,7 @@ class EditBox : EditWidgetBase { } } - //protected int _firstVisibleLine; + protected int _firstVisibleLine; protected int _maxLineWidth; protected int _numVisibleLines; // number of lines visible in client area