diff --git a/src/dlangui/core/editable.d b/src/dlangui/core/editable.d
index accfc9eb..8b56c789 100644
--- a/src/dlangui/core/editable.d
+++ b/src/dlangui/core/editable.d
@@ -868,6 +868,40 @@ class EditableContent {
return (pos + tabSize) / tabSize * tabSize;
}
+ /// to return information about line space positions
+ static struct LineWhiteSpace {
+ int firstNonSpaceIndex = -1;
+ int firstNonSpaceColumn = -1;
+ int lastNonSpaceIndex = -1;
+ int lastNonSpaceColumn = -1;
+ @property bool empty() { return firstNonSpaceColumn < 0; }
+ }
+
+ LineWhiteSpace getLineWhiteSpace(int lineIndex) {
+ LineWhiteSpace res;
+ if (lineIndex < 0 || lineIndex >= _lines.length)
+ return res;
+ dstring s = _lines[lineIndex];
+ int x = 0;
+ for (int i = 0; i < s.length; i++) {
+ dchar ch = s[i];
+ if (ch == '\t') {
+ x = (x + _tabSize) / _tabSize * _tabSize;
+ } else if (ch == ' ') {
+ x++;
+ } else {
+ if (res.firstNonSpaceIndex < 0) {
+ res.firstNonSpaceIndex = i;
+ res.firstNonSpaceColumn = x;
+ }
+ res.lastNonSpaceIndex = i;
+ res.lastNonSpaceColumn = x;
+ x++;
+ }
+ }
+ return res;
+ }
+
/// returns spaces/tabs for filling from the beginning of line to specified position
dstring fillSpace(int pos) {
dchar[] buf;
diff --git a/src/dlangui/graphics/drawbuf.d b/src/dlangui/graphics/drawbuf.d
index 06a6eb9e..7efc721a 100644
--- a/src/dlangui/graphics/drawbuf.d
+++ b/src/dlangui/graphics/drawbuf.d
@@ -34,6 +34,11 @@ struct NinePatch {
Rect padding;
}
+enum PatternType : int {
+ solid,
+ dotted,
+}
+
static if (ENABLE_OPENGL) {
/// non thread safe
private __gshared uint drawBufIdGenerator = 0;
@@ -278,6 +283,11 @@ class DrawBuf : RefCountedObject {
abstract void fill(uint color);
/// fill rectangle with solid color (clipping is applied)
abstract void fillRect(Rect rc, uint color);
+ /// fill rectangle with solid color and pattern (clipping is applied) 0=solid fill, 1 = dotted
+ void fillRectPattern(Rect rc, uint color, int pattern) {
+ // default implementation: does not support patterns
+ fillRect(rc, color);
+ }
/// draw pixel at (x, y) with specified color
abstract void drawPixel(int x, int y, uint color);
/// draw 8bit alpha image - usually font glyph using specified color (clipping is applied)
@@ -701,10 +711,10 @@ class ColorDrawBufBase : DrawBuf {
}
override void fillRect(Rect rc, uint color) {
+ uint alpha = color >> 24;
if (applyClipping(rc)) {
foreach(y; rc.top .. rc.bottom) {
uint * row = scanLine(y);
- uint alpha = color >> 24;
if (!alpha) {
row[rc.left .. rc.right] = color;
} else if (alpha < 254) {
@@ -717,6 +727,34 @@ class ColorDrawBufBase : DrawBuf {
}
}
+ /// fill rectangle with solid color and pattern (clipping is applied) 0=solid fill, 1 = dotted
+ override void fillRectPattern(Rect rc, uint color, int pattern) {
+ uint alpha = color >> 24;
+ if (alpha == 255) // fully transparent
+ return;
+ if (applyClipping(rc)) {
+ foreach(y; rc.top .. rc.bottom) {
+ uint * row = scanLine(y);
+ if (!alpha) {
+ if (pattern == 1) {
+ foreach(x; rc.left .. rc.right) {
+ if ((x ^ y) & 1)
+ row[x] = color;
+ }
+ } else {
+ row[rc.left .. rc.right] = color;
+ }
+ } else if (alpha < 254) {
+ foreach(x; rc.left .. rc.right) {
+ // apply blending
+ if (pattern != 1 || ((x ^ y) & 1) != 0)
+ row[x] = blendARGB(row[x], color, alpha);
+ }
+ }
+ }
+ }
+ }
+
/// draw pixel at (x, y) with specified color
override void drawPixel(int x, int y, uint color) {
if (!_clipRect.isPointInside(x, y))
diff --git a/src/dlangui/graphics/gldrawbuf.d b/src/dlangui/graphics/gldrawbuf.d
index 71df709a..f55c545a 100644
--- a/src/dlangui/graphics/gldrawbuf.d
+++ b/src/dlangui/graphics/gldrawbuf.d
@@ -112,6 +112,19 @@ class GLDrawBuf : DrawBuf, GLConfigCallback {
if (!isFullyTransparentColor(color) && applyClipping(rc))
_scene.add(new SolidRectSceneItem(rc, color));
}
+
+ /// fill rectangle with solid color and pattern (clipping is applied) 0=solid fill, 1 = dotted
+ override void fillRectPattern(Rect rc, uint color, int pattern) {
+ if (pattern == PatternType.solid)
+ fillRect(rc, color);
+ else {
+ assert(_scene !is null);
+ color = applyAlpha(color);
+ if (!isFullyTransparentColor(color) && applyClipping(rc))
+ _scene.add(new PatternRectSceneItem(rc, color, pattern));
+ }
+ }
+
/// draw pixel at (x, y) with specified color
override void drawPixel(int x, int y, uint color) {
assert(_scene !is null);
@@ -718,6 +731,30 @@ public:
}
}
+private class PatternRectSceneItem : SceneItem {
+private:
+ Rect _rc;
+ uint _color;
+ int _pattern;
+
+public:
+ this(Rect rc, uint color, int pattern) {
+ _rc = rc;
+ _color = color;
+ _pattern = pattern;
+ }
+ override void draw() {
+ // TODO: support patterns
+ // TODO: optimize
+ for (int y = _rc.top; y < _rc.bottom; y++) {
+ for (int x = _rc.left; x < _rc.right; x++)
+ if ((x ^ y) & 1) {
+ glSupport.drawSolidFillRect(Rect(x, y, x + 1, y + 1), _color, _color, _color, _color);
+ }
+ }
+ }
+}
+
private class TextureSceneItem : SceneItem {
private:
uint objectId;
diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d
index 94e9d60d..1b9bc3f3 100644
--- a/src/dlangui/widgets/editors.d
+++ b/src/dlangui/widgets/editors.d
@@ -252,9 +252,9 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
protected uint _selectionColorNormal = 0xD060A0FF;
protected uint _leftPaneBackgroundColor = 0xF4F4F4;
protected uint _leftPaneBackgroundColor2 = 0xFFFFFF;
- protected uint _leftPaneBackgroundColor3 = 0xE0E0E0;
+ protected uint _leftPaneBackgroundColor3 = 0xF8F8F8;
protected uint _leftPaneLineNumberColor = 0x4060D0;
- protected uint _leftPaneLineNumberBackgroundColor = 0xF0F0F0;
+ protected uint _leftPaneLineNumberBackgroundColor = 0xF4F4F4;
protected uint _colorIconBreakpoint = 0xFF0000;
protected uint _colorIconBookmark = 0x0000FF;
protected uint _colorIconError = 0x80FF0000;
@@ -278,7 +278,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
@property bool showTabPositionMarks() { return _showTabPositionMarks; }
@property EditWidgetBase showTabPositionMarks(bool flg) {
if (flg != _showTabPositionMarks) {
- _showTabPositionMarks = flg;
+ _showTabPositionMarks = flg;
invalidate();
}
return this;
@@ -2680,6 +2680,47 @@ class EditBox : EditWidgetBase {
}
}
+ /// find max tab mark column position for line
+ protected int findMaxTabMarkColumn(int lineIndex) {
+ if (lineIndex < 0 || lineIndex >= content.length)
+ return -1;
+ int maxSpace = -1;
+ auto space = content.getLineWhiteSpace(lineIndex);
+ maxSpace = space.firstNonSpaceColumn;
+ if (maxSpace >= 0)
+ return maxSpace;
+ for(int i = lineIndex - 1; i >= 0; i--) {
+ space = content.getLineWhiteSpace(i);
+ if (!space.empty) {
+ maxSpace = space.firstNonSpaceColumn;
+ break;
+ }
+ }
+ for(int i = lineIndex + 1; i < content.length; i++) {
+ space = content.getLineWhiteSpace(i);
+ if (!space.empty) {
+ if (maxSpace < 0 || maxSpace < space.firstNonSpaceColumn)
+ maxSpace = space.firstNonSpaceColumn;
+ break;
+ }
+ }
+ return maxSpace;
+ }
+
+ void drawTabPositionMarks(DrawBuf buf, ref FontRef font, int lineIndex, Rect lineRect) {
+ int maxCol = findMaxTabMarkColumn(lineIndex);
+ if (maxCol > 0) {
+ int spaceWidth = font.charWidth(' ');
+ Rect rc = lineRect;
+ uint color = addAlpha(textColor, 0xC0);
+ for (int i = 0; i < maxCol; i += tabSize) {
+ rc.left = lineRect.left + i * spaceWidth;
+ rc.right = rc.left + 1;
+ buf.fillRectPattern(rc, color, PatternType.dotted);
+ }
+ }
+ }
+
void drawWhiteSpaceMarks(DrawBuf buf, ref FontRef font, dstring txt, int tabSize, Rect lineRect, Rect visibleRect) {
// _showTabPositionMarks
// _showWhiteSpaceMarks
@@ -2715,42 +2756,30 @@ class EditBox : EditWidgetBase {
rc.right = lineRect.left + textSizeBuffer[i];
int h = rc.height;
if (rc.intersects(visibleRect)) {
- if (_showTabPositionMarks && i < firstNonSpace) {
- if (spaceIndex % ts == 0) {
- // draw mark
- buf.fillRect(Rect(rc.left, rc.top, rc.left + 1, rc.bottom), color);
- }
- if (ch == ' ')
- spaceIndex++;
- else if (ch == '\t')
- spaceIndex = (spaceIndex + ts) / ts * ts;
- }
- if (_showWhiteSpaceMarks) {
- // draw space mark
- if (ch == ' ') {
- // space
- int sz = h / 6;
- if (sz < 1)
- sz = 1;
- rc.top += h / 2 - sz / 2;
- rc.bottom = rc.top + sz;
- rc.left += rc.width / 2 - sz / 2;
- rc.right = rc.left + sz;
- buf.fillRect(rc, color);
- } else if (ch == '\t') {
- // tab
- Point p1 = Point(rc.left + 1, rc.top + h / 2);
- Point p2 = p1;
- p2.x = rc.right - 1;
- int sz = h / 4;
- if (sz < 2)
- sz = 2;
- if (sz > p2.x - p1.x)
- sz = p2.x - p1.x;
- buf.drawLine(p1, p2, color);
- buf.drawLine(p2, Point(p2.x - sz, p2.y - sz), color);
- buf.drawLine(p2, Point(p2.x - sz, p2.y + sz), color);
- }
+ // draw space mark
+ if (ch == ' ') {
+ // space
+ int sz = h / 6;
+ if (sz < 1)
+ sz = 1;
+ rc.top += h / 2 - sz / 2;
+ rc.bottom = rc.top + sz;
+ rc.left += rc.width / 2 - sz / 2;
+ rc.right = rc.left + sz;
+ buf.fillRect(rc, color);
+ } else if (ch == '\t') {
+ // tab
+ Point p1 = Point(rc.left + 1, rc.top + h / 2);
+ Point p2 = p1;
+ p2.x = rc.right - 1;
+ int sz = h / 4;
+ if (sz < 2)
+ sz = 2;
+ if (sz > p2.x - p1.x)
+ sz = p2.x - p1.x;
+ buf.drawLine(p1, p2, color);
+ buf.drawLine(p2, Point(p2.x - sz, p2.y - sz), color);
+ buf.drawLine(p2, Point(p2.x - sz, p2.y + sz), color);
}
}
}
@@ -2778,9 +2807,11 @@ class EditBox : EditWidgetBase {
visibleRect.left = _clientRect.left;
visibleRect.right = _clientRect.right;
drawLineBackground(buf, _firstVisibleLine + i, lineRect, visibleRect);
+ if (_showTabPositionMarks)
+ drawTabPositionMarks(buf, font, _firstVisibleLine + i, lineRect);
if (!txt.length)
continue;
- if (_showWhiteSpaceMarks || _showTabPositionMarks)
+ if (_showWhiteSpaceMarks)
drawWhiteSpaceMarks(buf, font, txt, tabSize, lineRect, visibleRect);
if (_leftPaneWidth > 0) {
Rect leftPaneRect = visibleRect;
diff --git a/views/res/theme_default.xml b/views/res/theme_default.xml
index c266e32d..44b2b700 100644
--- a/views/res/theme_default.xml
+++ b/views/res/theme_default.xml
@@ -14,9 +14,9 @@
-
+
-
+