refactor: use ScrollWidget as base for editors

This commit is contained in:
Vadim Lopatin 2014-11-28 13:36:49 +03:00
parent 257496b6f8
commit 04c30ae566
4 changed files with 239 additions and 244 deletions

View File

@ -24,6 +24,7 @@ module dlangui.widgets.editors;
import dlangui.widgets.widget; import dlangui.widgets.widget;
import dlangui.widgets.controls; import dlangui.widgets.controls;
import dlangui.widgets.scroll;
import dlangui.core.signals; import dlangui.core.signals;
import dlangui.core.collections; import dlangui.core.collections;
import dlangui.platforms.common.platform; import dlangui.platforms.common.platform;
@ -807,9 +808,8 @@ class EditableContent {
} }
/// base for all editor widgets /// base for all editor widgets
class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandler { class EditWidgetBase : ScrollWidget, EditableContentListener, MenuItemActionHandler {
protected EditableContent _content; protected EditableContent _content;
protected Rect _clientRc;
protected int _lineHeight; protected int _lineHeight;
protected Point _scrollPos; protected Point _scrollPos;
@ -830,8 +830,8 @@ class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandl
protected uint _selectionColorNormal = 0xD060A0FF; protected uint _selectionColorNormal = 0xD060A0FF;
this(string ID) { this(string ID, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) {
super(ID); super(ID, hscrollbarMode, vscrollbarMode);
focusable = true; focusable = true;
acceleratorMap.add( [ acceleratorMap.add( [
new Action(EditorActions.Up, KeyCode.UP, 0), new Action(EditorActions.Up, KeyCode.UP, 0),
@ -922,6 +922,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandl
return false; return false;
return true; return true;
} }
/// override to change popup menu items state /// override to change popup menu items state
override bool isActionEnabled(const Action action) { override bool isActionEnabled(const Action action) {
switch (action.id) { switch (action.id) {
@ -1130,7 +1131,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandl
caretRc.right += _spaceWidth; caretRc.right += _spaceWidth;
} }
} }
caretRc.offset(_clientRc.left, _clientRc.top); caretRc.offset(_clientRect.left, _clientRect.top);
return caretRc; return caretRc;
} }
@ -1139,7 +1140,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandl
if (focused) { if (focused) {
// draw caret // draw caret
Rect caretRc = caretRect(); Rect caretRc = caretRect();
if (caretRc.intersects(_clientRc)) { if (caretRc.intersects(_clientRect)) {
Rect rc1 = caretRc; Rect rc1 = caretRc;
rc1.right = rc1.left + 1; rc1.right = rc1.left + 1;
caretRc.left++; caretRc.left++;
@ -1669,12 +1670,12 @@ class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandl
// support onClick // support onClick
if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) { if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) {
setFocus(); setFocus();
updateCaretPositionByMouse(event.x - _clientRc.left, event.y - _clientRc.top, false); updateCaretPositionByMouse(event.x - _clientRect.left, event.y - _clientRect.top, false);
invalidate(); invalidate();
return true; return true;
} }
if (event.action == MouseAction.Move && (event.flags & MouseButton.Left) != 0) { if (event.action == MouseAction.Move && (event.flags & MouseButton.Left) != 0) {
updateCaretPositionByMouse(event.x - _clientRc.left, event.y - _clientRc.top, true); updateCaretPositionByMouse(event.x - _clientRect.left, event.y - _clientRect.top, true);
return true; return true;
} }
if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) { if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) {
@ -1713,7 +1714,7 @@ class EditWidgetBase : WidgetGroup, EditableContentListener, MenuItemActionHandl
class EditLine : EditWidgetBase { class EditLine : EditWidgetBase {
this(string ID, dstring initialContent = null) { this(string ID, dstring initialContent = null) {
super(ID); super(ID, ScrollBarMode.Invisible, ScrollBarMode.Invisible);
_content = new EditableContent(false); _content = new EditableContent(false);
_content.contentChangeListeners = this; _content.contentChangeListeners = this;
wantTabs = false; wantTabs = false;
@ -1727,7 +1728,7 @@ class EditLine : EditWidgetBase {
override protected Rect textPosToClient(TextPosition p) { override protected Rect textPosToClient(TextPosition p) {
Rect res; Rect res;
res.bottom = _clientRc.height; res.bottom = _clientRect.height;
if (p.pos == 0) if (p.pos == 0)
res.left = 0; res.left = 0;
else if (p.pos >= _measuredText.length) else if (p.pos >= _measuredText.length)
@ -1760,13 +1761,13 @@ class EditLine : EditWidgetBase {
Rect rc = textPosToClient(_caretPos); Rect rc = textPosToClient(_caretPos);
if (rc.left < 0) { if (rc.left < 0) {
// scroll left // scroll left
_scrollPos.x -= -rc.left + _clientRc.width / 10; _scrollPos.x -= -rc.left + _clientRect.width / 10;
if (_scrollPos.x < 0) if (_scrollPos.x < 0)
_scrollPos.x = 0; _scrollPos.x = 0;
invalidate(); invalidate();
} else if (rc.left >= _clientRc.width - 10) { } else if (rc.left >= _clientRect.width - 10) {
// scroll right // scroll right
_scrollPos.x += (rc.left - _clientRc.width) + _spaceWidth * 4; _scrollPos.x += (rc.left - _clientRect.width) + _spaceWidth * 4;
invalidate(); invalidate();
} }
updateScrollbars(); updateScrollbars();
@ -1819,16 +1820,16 @@ class EditLine : EditWidgetBase {
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout). /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
override void layout(Rect rc) { override void layout(Rect rc) {
_needLayout = false;
if (visibility == Visibility.Gone) { if (visibility == Visibility.Gone) {
return; return;
} }
_needLayout = false;
Point sz = Point(rc.width, measuredHeight); Point sz = Point(rc.width, measuredHeight);
applyAlign(rc, sz); applyAlign(rc, sz);
_pos = rc; _pos = rc;
_clientRc = rc; _clientRect = rc;
applyMargins(_clientRc); applyMargins(_clientRect);
applyPadding(_clientRc); applyPadding(_clientRect);
} }
@ -1838,8 +1839,8 @@ class EditLine : EditWidgetBase {
// line inside selection // line inside selection
Rect startrc = textPosToClient(_selectionRange.start); Rect startrc = textPosToClient(_selectionRange.start);
Rect endrc = textPosToClient(_selectionRange.end); Rect endrc = textPosToClient(_selectionRange.end);
int startx = startrc.left + _clientRc.left; int startx = startrc.left + _clientRect.left;
int endx = endrc.left + _clientRc.left; int endx = endrc.left + _clientRect.left;
Rect rc = lineRect; Rect rc = lineRect;
rc.left = startx; rc.left = startx;
rc.right = endx; rc.right = endx;
@ -1863,12 +1864,12 @@ class EditLine : EditWidgetBase {
dstring txt = text; dstring txt = text;
Point sz = font.textSize(txt); Point sz = font.textSize(txt);
//applyAlign(rc, sz); //applyAlign(rc, sz);
Rect lineRect = _clientRc; Rect lineRect = _clientRect;
lineRect.left = _clientRc.left - _scrollPos.x; lineRect.left = _clientRect.left - _scrollPos.x;
lineRect.right = lineRect.left + calcLineWidth(txt); lineRect.right = lineRect.left + calcLineWidth(txt);
Rect visibleRect = lineRect; Rect visibleRect = lineRect;
visibleRect.left = _clientRc.left; visibleRect.left = _clientRect.left;
visibleRect.right = _clientRc.right; visibleRect.right = _clientRect.right;
drawLineBackground(buf, lineRect, visibleRect); drawLineBackground(buf, lineRect, visibleRect);
font.drawText(buf, rc.left - _scrollPos.x, rc.top, txt, textColor, tabSize); font.drawText(buf, rc.left - _scrollPos.x, rc.top, txt, textColor, tabSize);
@ -1879,22 +1880,13 @@ class EditLine : EditWidgetBase {
/// single line editor /// single line editor
class EditBox : EditWidgetBase, OnScrollHandler { class EditBox : EditWidgetBase {
protected ScrollBar _hscrollbar; this(string ID, dstring initialContent = null, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) {
protected ScrollBar _vscrollbar; super(ID, hscrollbarMode, vscrollbarMode);
this(string ID, dstring initialContent = null) {
super(ID);
_content = new EditableContent(true); // multiline _content = new EditableContent(true); // multiline
_content.contentChangeListeners = this; _content.contentChangeListeners = this;
styleId = "EDIT_BOX"; styleId = "EDIT_BOX";
text = initialContent; text = initialContent;
_hscrollbar = new ScrollBar("hscrollbar", Orientation.Horizontal);
_vscrollbar = new ScrollBar("vscrollbar", Orientation.Vertical);
_hscrollbar.onScrollEventListener = this;
_vscrollbar.onScrollEventListener = this;
addChild(_hscrollbar);
addChild(_vscrollbar);
} }
protected int _firstVisibleLine; protected int _firstVisibleLine;
@ -1939,7 +1931,7 @@ class EditBox : EditWidgetBase, OnScrollHandler {
Point sz; Point sz;
FontRef font = font(); FontRef font = font();
_lineHeight = font.height; _lineHeight = font.height;
_numVisibleLines = (_clientRc.height + _lineHeight - 1) / _lineHeight; _numVisibleLines = (_clientRect.height + _lineHeight - 1) / _lineHeight;
if (_firstVisibleLine + _numVisibleLines > _content.length) if (_firstVisibleLine + _numVisibleLines > _content.length)
_numVisibleLines = _content.length - _firstVisibleLine; _numVisibleLines = _content.length - _firstVisibleLine;
_visibleLines.length = _numVisibleLines; _visibleLines.length = _numVisibleLines;
@ -1958,21 +1950,25 @@ class EditBox : EditWidgetBase, OnScrollHandler {
return sz; return sz;
} }
override protected void updateScrollbars() { /// update horizontal scrollbar widget position
int visibleLines = _clientRc.height / _lineHeight; // fully visible lines override protected void updateHScrollBar() {
_hscrollbar.setRange(0, _maxLineWidth + _clientRect.width / 4);
_hscrollbar.pageSize = _clientRect.width;
_hscrollbar.position = _scrollPos.x;
}
/// update verticat scrollbar widget position
override protected void updateVScrollBar() {
int visibleLines = _clientRect.height / _lineHeight; // fully visible lines
if (visibleLines < 1) if (visibleLines < 1)
visibleLines = 1; visibleLines = 1;
_vscrollbar.setRange(0, _content.length - 1); _vscrollbar.setRange(0, _content.length - 1);
_vscrollbar.pageSize = visibleLines; _vscrollbar.pageSize = visibleLines;
_vscrollbar.position = _firstVisibleLine; _vscrollbar.position = _firstVisibleLine;
_hscrollbar.setRange(0, _maxLineWidth + _clientRc.width / 4);
_hscrollbar.pageSize = _clientRc.width;
_hscrollbar.position = _scrollPos.x;
} }
/// handle scroll event /// process horizontal scrollbar event
override bool onScrollEvent(AbstractSlider source, ScrollEvent event) { override bool onHScroll(ScrollEvent event) {
if (source.compareId("hscrollbar")) {
if (event.action == ScrollAction.SliderMoved || event.action == ScrollAction.SliderReleased) { if (event.action == ScrollAction.SliderMoved || event.action == ScrollAction.SliderReleased) {
if (_scrollPos.x != event.position) { if (_scrollPos.x != event.position) {
_scrollPos.x = event.position; _scrollPos.x = event.position;
@ -1988,7 +1984,10 @@ class EditBox : EditWidgetBase, OnScrollHandler {
handleAction(new Action(EditorActions.ScrollRight)); handleAction(new Action(EditorActions.ScrollRight));
} }
return true; return true;
} else if (source.compareId("vscrollbar")) { }
/// process vertical scrollbar event
override bool onVScroll(ScrollEvent event) {
if (event.action == ScrollAction.SliderMoved || event.action == ScrollAction.SliderReleased) { if (event.action == ScrollAction.SliderMoved || event.action == ScrollAction.SliderReleased) {
if (_firstVisibleLine != event.position) { if (_firstVisibleLine != event.position) {
_firstVisibleLine = event.position; _firstVisibleLine = event.position;
@ -2006,16 +2005,13 @@ class EditBox : EditWidgetBase, OnScrollHandler {
} }
return true; return true;
} }
return false;
}
override protected void ensureCaretVisible() { override protected void ensureCaretVisible() {
if (_caretPos.line >= _content.length) if (_caretPos.line >= _content.length)
_caretPos.line = _content.length - 1; _caretPos.line = _content.length - 1;
if (_caretPos.line < 0) if (_caretPos.line < 0)
_caretPos.line = 0; _caretPos.line = 0;
int visibleLines = _clientRc.height / _lineHeight; // fully visible lines int visibleLines = _clientRect.height / _lineHeight; // fully visible lines
if (visibleLines < 1) if (visibleLines < 1)
visibleLines = 1; visibleLines = 1;
if (_caretPos.line < _firstVisibleLine) { if (_caretPos.line < _firstVisibleLine) {
@ -2033,13 +2029,13 @@ class EditBox : EditWidgetBase, OnScrollHandler {
Rect rc = textPosToClient(_caretPos); Rect rc = textPosToClient(_caretPos);
if (rc.left < 0) { if (rc.left < 0) {
// scroll left // scroll left
_scrollPos.x -= -rc.left + _clientRc.width / 4; _scrollPos.x -= -rc.left + _clientRect.width / 4;
if (_scrollPos.x < 0) if (_scrollPos.x < 0)
_scrollPos.x = 0; _scrollPos.x = 0;
invalidate(); invalidate();
} else if (rc.left >= _clientRc.width - 10) { } else if (rc.left >= _clientRect.width - 10) {
// scroll right // scroll right
_scrollPos.x += (rc.left - _clientRc.width) + _clientRc.width / 4; _scrollPos.x += (rc.left - _clientRect.width) + _clientRect.width / 4;
invalidate(); invalidate();
} }
updateScrollbars(); updateScrollbars();
@ -2081,9 +2077,12 @@ class EditBox : EditWidgetBase, OnScrollHandler {
} }
} }
res.pos = cast(int)_visibleLines[lineIndex].length; res.pos = cast(int)_visibleLines[lineIndex].length;
} else { } else if (_visibleLines.length > 0) {
res.line = _firstVisibleLine + cast(int)_visibleLines.length - 1; res.line = _firstVisibleLine + cast(int)_visibleLines.length - 1;
res.pos = cast(int)_visibleLines[$ - 1].length; res.pos = cast(int)_visibleLines[$ - 1].length;
} else {
res.line = 0;
res.pos = 0;
} }
return res; return res;
} }
@ -2135,7 +2134,7 @@ class EditBox : EditWidgetBase, OnScrollHandler {
case EditorActions.SelectPageEnd: case EditorActions.SelectPageEnd:
{ {
ensureCaretVisible(); ensureCaretVisible();
int fullLines = _clientRc.height / _lineHeight; int fullLines = _clientRect.height / _lineHeight;
int newpos = _firstVisibleLine + fullLines - 1; int newpos = _firstVisibleLine + fullLines - 1;
if (newpos >= _content.length) if (newpos >= _content.length)
newpos = _content.length - 1; newpos = _content.length - 1;
@ -2147,7 +2146,7 @@ class EditBox : EditWidgetBase, OnScrollHandler {
case EditorActions.SelectPageUp: case EditorActions.SelectPageUp:
{ {
ensureCaretVisible(); ensureCaretVisible();
int fullLines = _clientRc.height / _lineHeight; int fullLines = _clientRect.height / _lineHeight;
int newpos = _firstVisibleLine - fullLines; int newpos = _firstVisibleLine - fullLines;
if (newpos < 0) { if (newpos < 0) {
_firstVisibleLine = 0; _firstVisibleLine = 0;
@ -2166,7 +2165,7 @@ class EditBox : EditWidgetBase, OnScrollHandler {
case EditorActions.SelectPageDown: case EditorActions.SelectPageDown:
{ {
ensureCaretVisible(); ensureCaretVisible();
int fullLines = _clientRc.height / _lineHeight; int fullLines = _clientRect.height / _lineHeight;
int newpos = _firstVisibleLine + fullLines; int newpos = _firstVisibleLine + fullLines;
if (newpos >= _content.length) { if (newpos >= _content.length) {
_caretPos.line = _content.length - 1; _caretPos.line = _content.length - 1;
@ -2194,10 +2193,10 @@ class EditBox : EditWidgetBase, OnScrollHandler {
return true; return true;
case EditorActions.ScrollRight: case EditorActions.ScrollRight:
{ {
if (_scrollPos.x < _maxLineWidth - _clientRc.width) { if (_scrollPos.x < _maxLineWidth - _clientRect.width) {
int newpos = _scrollPos.x + _spaceWidth * 4; int newpos = _scrollPos.x + _spaceWidth * 4;
if (newpos > _maxLineWidth - _clientRc.width) if (newpos > _maxLineWidth - _clientRect.width)
newpos = _maxLineWidth - _clientRc.width; newpos = _maxLineWidth - _clientRect.width;
_scrollPos.x = newpos; _scrollPos.x = newpos;
updateScrollbars(); updateScrollbars();
invalidate(); invalidate();
@ -2218,7 +2217,7 @@ class EditBox : EditWidgetBase, OnScrollHandler {
return true; return true;
case EditorActions.ScrollPageUp: case EditorActions.ScrollPageUp:
{ {
int fullLines = _clientRc.height / _lineHeight; int fullLines = _clientRect.height / _lineHeight;
if (_firstVisibleLine > 0) { if (_firstVisibleLine > 0) {
_firstVisibleLine -= fullLines * 3 / 4; _firstVisibleLine -= fullLines * 3 / 4;
if (_firstVisibleLine < 0) if (_firstVisibleLine < 0)
@ -2231,7 +2230,7 @@ class EditBox : EditWidgetBase, OnScrollHandler {
return true; return true;
case EditorActions.ScrollLineDown: case EditorActions.ScrollLineDown:
{ {
int fullLines = _clientRc.height / _lineHeight; int fullLines = _clientRect.height / _lineHeight;
if (_firstVisibleLine + fullLines < _content.length) { if (_firstVisibleLine + fullLines < _content.length) {
_firstVisibleLine += 3; _firstVisibleLine += 3;
if (_firstVisibleLine > _content.length - fullLines) if (_firstVisibleLine > _content.length - fullLines)
@ -2246,7 +2245,7 @@ class EditBox : EditWidgetBase, OnScrollHandler {
return true; return true;
case EditorActions.ScrollPageDown: case EditorActions.ScrollPageDown:
{ {
int fullLines = _clientRc.height / _lineHeight; int fullLines = _clientRect.height / _lineHeight;
if (_firstVisibleLine + fullLines < _content.length) { if (_firstVisibleLine + fullLines < _content.length) {
_firstVisibleLine += fullLines * 3 / 4; _firstVisibleLine += fullLines * 3 / 4;
if (_firstVisibleLine > _content.length - fullLines) if (_firstVisibleLine > _content.length - fullLines)
@ -2295,55 +2294,25 @@ class EditBox : EditWidgetBase, OnScrollHandler {
return super.handleAction(a); return super.handleAction(a);
} }
/// calculate full content size in pixels
override Point fullContentSize() {
Point textSz = measureVisibleText();
int maxy = _lineHeight * 5; // limit measured height
if (textSz.y > maxy)
textSz.y = maxy;
return textSz;
}
/// measure /// measure
override void measure(int parentWidth, int parentHeight) { override void measure(int parentWidth, int parentHeight) {
if (visibility == Visibility.Gone) { if (visibility == Visibility.Gone) {
return; return;
} }
_hscrollbar.measure(parentWidth, parentHeight);
_vscrollbar.measure(parentWidth, parentHeight);
int hsbheight = _hscrollbar.measuredHeight;
int vsbwidth = _vscrollbar.measuredWidth;
updateFontProps(); updateFontProps();
updateMaxLineWidth(); updateMaxLineWidth();
super.measure(parentWidth, parentHeight);
Point textSz = measureVisibleText(); // do we need to add vsbwidth, hsbheight ???
int maxy = _lineHeight * 5; // limit measured height //measuredContent(parentWidth, parentHeight, textSz.x + vsbwidth, textSz.y + hsbheight);
if (textSz.y > maxy)
textSz.y = maxy;
measuredContent(parentWidth, parentHeight, textSz.x + vsbwidth, textSz.y + hsbheight);
}
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
override void layout(Rect rc) {
_needLayout = false;
if (visibility == Visibility.Gone) {
return;
}
_pos = rc;
applyMargins(rc);
applyPadding(rc);
int hsbheight = _hscrollbar.measuredHeight;
int vsbwidth = _vscrollbar.measuredWidth;
Rect sbrc = rc;
sbrc.left = sbrc.right - vsbwidth;
sbrc.bottom -= hsbheight;
_vscrollbar.layout(sbrc);
sbrc = rc;
sbrc.right -= vsbwidth;
sbrc.top = sbrc.bottom - hsbheight;
_hscrollbar.layout(sbrc);
// calc client rectangle
_clientRc = rc;
_clientRc.right -= vsbwidth;
_clientRc.bottom -= hsbheight;
Point textSz = measureVisibleText();
updateScrollbars();
} }
/// override to custom highlight of line background /// override to custom highlight of line background
@ -2356,8 +2325,8 @@ class EditBox : EditWidgetBase, OnScrollHandler {
// line inside selection // line inside selection
Rect startrc = textPosToClient(_selectionRange.start); Rect startrc = textPosToClient(_selectionRange.start);
Rect endrc = textPosToClient(_selectionRange.end); Rect endrc = textPosToClient(_selectionRange.end);
int startx = lineIndex == _selectionRange.start.line ? startrc.left + _clientRc.left : lineRect.left; int startx = lineIndex == _selectionRange.start.line ? startrc.left + _clientRect.left : lineRect.left;
int endx = lineIndex == _selectionRange.end.line ? endrc.left + _clientRc.left : lineRect.right + _spaceWidth; int endx = lineIndex == _selectionRange.end.line ? endrc.left + _clientRect.left : lineRect.right + _spaceWidth;
Rect rc = lineRect; Rect rc = lineRect;
rc.left = startx; rc.left = startx;
rc.right = endx; rc.right = endx;
@ -2373,15 +2342,8 @@ class EditBox : EditWidgetBase, OnScrollHandler {
} }
} }
override protected void drawClient(DrawBuf buf) {
/// draw content Rect rc = _clientRect;
override void onDraw(DrawBuf buf) {
if (visibility != Visibility.Visible)
return;
super.onDraw(buf);
_hscrollbar.onDraw(buf);
_vscrollbar.onDraw(buf);
Rect rc = _clientRc;
auto saver = ClipRectSaver(buf, rc, alpha); auto saver = ClipRectSaver(buf, rc, alpha);
FontRef font = font(); FontRef font = font();
@ -2391,13 +2353,13 @@ class EditBox : EditWidgetBase, OnScrollHandler {
for (int i = 0; i < _visibleLines.length; i++) { for (int i = 0; i < _visibleLines.length; i++) {
dstring txt = _visibleLines[i]; dstring txt = _visibleLines[i];
Rect lineRect = rc; Rect lineRect = rc;
lineRect.left = _clientRc.left - _scrollPos.x; lineRect.left = _clientRect.left - _scrollPos.x;
lineRect.right = lineRect.left + calcLineWidth(_content[_firstVisibleLine + i]); lineRect.right = lineRect.left + calcLineWidth(_content[_firstVisibleLine + i]);
lineRect.top = _clientRc.top + i * _lineHeight; lineRect.top = _clientRect.top + i * _lineHeight;
lineRect.bottom = lineRect.top + _lineHeight; lineRect.bottom = lineRect.top + _lineHeight;
Rect visibleRect = lineRect; Rect visibleRect = lineRect;
visibleRect.left = _clientRc.left; visibleRect.left = _clientRect.left;
visibleRect.right = _clientRc.right; visibleRect.right = _clientRect.right;
drawLineBackground(buf, _firstVisibleLine + i, lineRect, visibleRect); drawLineBackground(buf, _firstVisibleLine + i, lineRect, visibleRect);
if (txt.length > 0) { if (txt.length > 0) {
font.drawText(buf, rc.left - _scrollPos.x, rc.top + i * _lineHeight, txt, textColor, tabSize); font.drawText(buf, rc.left - _scrollPos.x, rc.top + i * _lineHeight, txt, textColor, tabSize);

View File

@ -179,8 +179,6 @@ class GridWidgetBase : ScrollWidget {
protected int _col; protected int _col;
/// selected cell row /// selected cell row
protected int _row; protected int _row;
/// inner area, excluding additional controls like scrollbars
protected Rect _clientRect;
/// when true, allows to select only whole row /// when true, allows to select only whole row
protected bool _rowSelect; protected bool _rowSelect;
/// default column width - for newly added columns /// default column width - for newly added columns
@ -852,7 +850,8 @@ class GridWidgetBase : ScrollWidget {
} }
} }
Point fullContentSize() { /// calculate full content size in pixels
override Point fullContentSize() {
Point sz; Point sz;
for (int i = 0; i < _cols; i++) for (int i = 0; i < _cols; i++)
sz.x += _colWidths[i]; sz.x += _colWidths[i];
@ -861,62 +860,7 @@ class GridWidgetBase : ScrollWidget {
return sz; return sz;
} }
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout). override protected void drawClient(DrawBuf buf) {
override void measure(int parentWidth, int parentHeight) {
Rect m = margins;
Rect p = padding;
// calc size constraints for children
int pwidth = parentWidth;
int pheight = parentHeight;
if (parentWidth != SIZE_UNSPECIFIED)
pwidth -= m.left + m.right + p.left + p.right;
if (parentHeight != SIZE_UNSPECIFIED)
pheight -= m.top + m.bottom + p.top + p.bottom;
_hscrollbar.measure(pwidth, pheight);
_vscrollbar.measure(pwidth, pheight);
Point sz = fullContentSize();
measuredContent(parentWidth, parentHeight, sz.x, sz.y);
}
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
override void layout(Rect rc) {
if (visibility == Visibility.Gone) {
return;
}
_pos = rc;
_needLayout = false;
applyMargins(rc);
applyPadding(rc);
Point sz = fullContentSize();
bool needHscroll = sz.x > rc.width;
bool needVscroll = sz.y > rc.height;
if (needVscroll)
needHscroll = sz.x > rc.width - _vscrollbar.measuredWidth;
if (needHscroll)
needVscroll = sz.y > rc.height - _hscrollbar.measuredHeight;
if (needVscroll)
needHscroll = sz.x > rc.width - _vscrollbar.measuredWidth;
// scrollbars
Rect vsbrc = rc;
vsbrc.left = vsbrc.right - _vscrollbar.measuredWidth;
vsbrc.bottom = vsbrc.bottom - _hscrollbar.measuredHeight;
Rect hsbrc = rc;
hsbrc.right = hsbrc.right - _vscrollbar.measuredWidth;
hsbrc.top = hsbrc.bottom - _hscrollbar.measuredHeight;
_vscrollbar.layout(vsbrc);
_hscrollbar.layout(hsbrc);
_vscrollbar.visibility = needVscroll ? Visibility.Visible : Visibility.Gone;
_hscrollbar.visibility = needHscroll ? Visibility.Visible : Visibility.Gone;
// client area
_clientRect = rc;
if (needVscroll)
_clientRect.right = vsbrc.left;
if (needHscroll)
_clientRect.bottom = hsbrc.top;
updateScrollBars();
}
protected void drawClient(DrawBuf buf) {
auto saver = ClipRectSaver(buf, _clientRect, 0); auto saver = ClipRectSaver(buf, _clientRect, 0);
//buf.fillRect(_clientRect, 0x80A08080); //buf.fillRect(_clientRect, 0x80A08080);
Rect rc; Rect rc;
@ -961,23 +905,6 @@ class GridWidgetBase : ScrollWidget {
} }
} }
} }
/// Draw widget at its position to buffer
override void onDraw(DrawBuf buf) {
if (visibility != Visibility.Visible)
return;
Rect rc = _pos;
applyMargins(rc);
auto saver = ClipRectSaver(buf, rc, alpha);
DrawableRef bg = backgroundDrawable;
if (!bg.isNull) {
bg.drawTo(buf, rc, state);
}
applyPadding(rc);
_hscrollbar.onDraw(buf);
_vscrollbar.onDraw(buf);
drawClient(buf);
_needDraw = false;
}
/// draw data cell content /// draw data cell content
protected void drawCell(DrawBuf buf, Rect rc, int col, int row) { protected void drawCell(DrawBuf buf, Rect rc, int col, int row) {
@ -1051,8 +978,8 @@ class GridWidgetBase : ScrollWidget {
autoFitRowHeights(); autoFitRowHeights();
} }
this(string ID = null) { this(string ID = null, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) {
super(ID); super(ID, hscrollbarMode, vscrollbarMode);
_headerCols = 1; _headerCols = 1;
_headerRows = 1; _headerRows = 1;
_defRowHeight = 20; _defRowHeight = 20;

View File

@ -4,21 +4,41 @@ import dlangui.widgets.widget;
import dlangui.widgets.controls; import dlangui.widgets.controls;
import std.conv; import std.conv;
/** Scroll bar visibility mode. */
enum ScrollBarMode {
/** always invisible */
Invisible,
/** always visible */
Visible,
/** automatically show/hide scrollbar depending on content size */
Auto
}
class ScrollWidget : WidgetGroup, OnScrollHandler { class ScrollWidget : WidgetGroup, OnScrollHandler {
protected ScrollBarMode _vscrollbarMode;
protected ScrollBarMode _hscrollbarMode;
/// vertical scrollbar control /// vertical scrollbar control
protected ScrollBar _vscrollbar; protected ScrollBar _vscrollbar;
/// horizontal scrollbar control /// horizontal scrollbar control
protected ScrollBar _hscrollbar; protected ScrollBar _hscrollbar;
/// inner area, excluding additional controls like scrollbars
protected Rect _clientRect;
this(string ID = null) { this(string ID = null, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) {
super(ID); super(ID);
_hscrollbarMode = hscrollbarMode;
_vscrollbarMode = vscrollbarMode;
if (_vscrollbarMode != ScrollBarMode.Invisible) {
_vscrollbar = new ScrollBar("vscrollbar", Orientation.Vertical); _vscrollbar = new ScrollBar("vscrollbar", Orientation.Vertical);
_hscrollbar = new ScrollBar("hscrollbar", Orientation.Horizontal);
_hscrollbar.onScrollEventListener = this;
_vscrollbar.onScrollEventListener = this; _vscrollbar.onScrollEventListener = this;
addChild(_vscrollbar); addChild(_vscrollbar);
}
if (_hscrollbarMode != ScrollBarMode.Invisible) {
_hscrollbar = new ScrollBar("hscrollbar", Orientation.Horizontal);
_hscrollbar.onScrollEventListener = this;
addChild(_hscrollbar); addChild(_hscrollbar);
} }
}
/// process horizontal scrollbar event /// process horizontal scrollbar event
bool onHScroll(ScrollEvent event) { bool onHScroll(ScrollEvent event) {
@ -60,5 +80,101 @@ class ScrollWidget : WidgetGroup, OnScrollHandler {
} }
} }
protected void drawClient(DrawBuf buf) {
// override it
}
/// Draw widget at its position to buffer
override void onDraw(DrawBuf buf) {
if (visibility != Visibility.Visible)
return;
Rect rc = _pos;
applyMargins(rc);
auto saver = ClipRectSaver(buf, rc, alpha);
DrawableRef bg = backgroundDrawable;
if (!bg.isNull) {
bg.drawTo(buf, rc, state);
}
applyPadding(rc);
if (_hscrollbar)
_hscrollbar.onDraw(buf);
if (_vscrollbar)
_vscrollbar.onDraw(buf);
drawClient(buf);
_needDraw = false;
}
/// calculate full content size in pixels
Point fullContentSize() {
// override it
Point sz;
return sz;
}
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
override void measure(int parentWidth, int parentHeight) {
if (visibility == Visibility.Gone) {
return;
}
Rect m = margins;
Rect p = padding;
// calc size constraints for children
int pwidth = parentWidth;
int pheight = parentHeight;
if (parentWidth != SIZE_UNSPECIFIED)
pwidth -= m.left + m.right + p.left + p.right;
if (parentHeight != SIZE_UNSPECIFIED)
pheight -= m.top + m.bottom + p.top + p.bottom;
if (_hscrollbar)
_hscrollbar.measure(pwidth, pheight);
if (_vscrollbar)
_vscrollbar.measure(pwidth, pheight);
Point sz = fullContentSize();
measuredContent(parentWidth, parentHeight, sz.x, sz.y);
}
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
override void layout(Rect rc) {
if (visibility == Visibility.Gone) {
return;
}
_pos = rc;
_needLayout = false;
applyMargins(rc);
applyPadding(rc);
Point sz = fullContentSize();
bool needHscroll = _hscrollbarMode != ScrollBarMode.Invisible && sz.x > rc.width;
bool needVscroll = _vscrollbarMode != ScrollBarMode.Invisible && sz.y > rc.height;
if (needVscroll && _vscrollbarMode != ScrollBarMode.Invisible)
needHscroll = sz.x > rc.width - _vscrollbar.measuredWidth;
if (needHscroll && _hscrollbarMode != ScrollBarMode.Invisible)
needVscroll = sz.y > rc.height - _hscrollbar.measuredHeight;
if (needVscroll && _vscrollbarMode != ScrollBarMode.Invisible)
needHscroll = sz.x > rc.width - _vscrollbar.measuredWidth;
needVscroll = needVscroll || (_vscrollbarMode == ScrollBarMode.Visible);
needHscroll = needHscroll || (_hscrollbarMode == ScrollBarMode.Visible);
// scrollbars
Rect vsbrc = rc;
vsbrc.left = vsbrc.right - (needVscroll ? _vscrollbar.measuredWidth : 0);
vsbrc.bottom = vsbrc.bottom - (needHscroll ? _hscrollbar.measuredHeight : 0);
Rect hsbrc = rc;
hsbrc.right = hsbrc.right - (needVscroll ? _vscrollbar.measuredWidth : 0);
hsbrc.top = hsbrc.bottom - (needHscroll ? _hscrollbar.measuredHeight : 0);
if (_vscrollbar) {
_vscrollbar.layout(vsbrc);
_vscrollbar.visibility = needVscroll ? Visibility.Visible : Visibility.Gone;
}
if (_hscrollbar) {
_hscrollbar.layout(hsbrc);
_hscrollbar.visibility = needHscroll ? Visibility.Visible : Visibility.Gone;
}
// client area
_clientRect = rc;
if (needVscroll)
_clientRect.right = vsbrc.left;
if (needHscroll)
_clientRect.bottom = hsbrc.top;
updateScrollBars();
}
} }

View File

@ -6,19 +6,9 @@ import dlangui.widgets.scroll;
import std.conv; import std.conv;
class TreeWidgetBase : ScrollWidget { class TreeWidgetBase : ScrollWidget {
/// vertical scrollbar control
protected ScrollBar _vscrollbar;
/// horizontal scrollbar control
protected ScrollBar _hscrollbar;
this(string ID = null) { this(string ID = null, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) {
super(ID); super(ID, hscrollbarMode, vscrollbarMode);
_vscrollbar = new ScrollBar("vscrollbar", Orientation.Vertical);
_hscrollbar = new ScrollBar("hscrollbar", Orientation.Horizontal);
_hscrollbar.onScrollEventListener = this;
_vscrollbar.onScrollEventListener = this;
addChild(_vscrollbar);
addChild(_hscrollbar);
} }
/// process horizontal scrollbar event /// process horizontal scrollbar event