spreadsheet example

This commit is contained in:
Vadim Lopatin 2015-11-30 13:40:58 +03:00
parent 768d418eec
commit a7decf99ea
5 changed files with 185 additions and 27 deletions

View File

@ -9,6 +9,8 @@ import dlangui.widgets.tabs;
import dlangui.widgets.editors; import dlangui.widgets.editors;
import dlangui.widgets.grid; import dlangui.widgets.grid;
import std.algorithm : min;
/// standard style id for Tab with Up alignment /// standard style id for Tab with Up alignment
immutable string STYLE_TAB_SHEET_DOWN = "TAB_SHEET_DOWN"; immutable string STYLE_TAB_SHEET_DOWN = "TAB_SHEET_DOWN";
/// standard style id for button of Tab with Up alignment /// standard style id for button of Tab with Up alignment
@ -21,6 +23,7 @@ class SheetTabs : TabControl {
this(string ID = null) { this(string ID = null) {
super(ID, Align.Bottom); super(ID, Align.Bottom);
setStyles(STYLE_TAB_SHEET_DOWN, STYLE_TAB_SHEET_DOWN_BUTTON, STYLE_TAB_SHEET_DOWN_BUTTON_TEXT); setStyles(STYLE_TAB_SHEET_DOWN, STYLE_TAB_SHEET_DOWN_BUTTON, STYLE_TAB_SHEET_DOWN_BUTTON_TEXT);
_moreButton.visibility = Visibility.Gone;
} }
} }
@ -38,19 +41,36 @@ class SheetEditControl : HorizontalLayout {
} }
} }
class SpreadSheetWidget : VerticalLayout { class SpreadSheetView : StringGridWidget {
this(string ID = null) {
super(ID);
layoutWidth = FILL_PARENT;
layoutHeight = FILL_PARENT;
resize(50, 50);
}
}
class SpreadSheetWidget : WidgetGroupDefaultDrawing {
SheetEditControl _editControl; SheetEditControl _editControl;
StringGridWidget _grid;
SheetTabs _tabs; SheetTabs _tabs;
ScrollBar _hScroll1;
ScrollBar _hScroll2;
ScrollBar _vScroll1;
ScrollBar _vScroll2;
SpreadSheetView _viewTopLeft;
SpreadSheetView _viewTopRight;
SpreadSheetView _viewBottomLeft;
SpreadSheetView _viewBottomRight;
SpreadSheetView[4] _views;
ScrollBar[4] _scrollbars;
this(string ID = "spreadsheet") { this(string ID = "spreadsheet") {
_editControl = new SheetEditControl(); _editControl = new SheetEditControl();
_editControl.layoutWidth = FILL_PARENT; _editControl.layoutWidth = FILL_PARENT;
_grid = new StringGridWidget("grid");
_grid.layoutWidth = FILL_PARENT;
_grid.layoutHeight = FILL_PARENT;
_grid.resize(50, 50);
_tabs = new SheetTabs(); _tabs = new SheetTabs();
_tabs.layoutWidth = FILL_PARENT; _tabs.layoutWidth = FILL_PARENT;
_tabs.addTab("Sheet1", "Sheet1"d); _tabs.addTab("Sheet1", "Sheet1"d);
@ -58,10 +78,93 @@ class SpreadSheetWidget : VerticalLayout {
_tabs.addTab("Sheet3", "Sheet3"d); _tabs.addTab("Sheet3", "Sheet3"d);
layoutWidth = FILL_PARENT; layoutWidth = FILL_PARENT;
layoutHeight = FILL_PARENT; layoutHeight = FILL_PARENT;
backgroundColor = 0xFFE0E0E0; backgroundColor = 0xdce2e8;
minHeight = 100; minHeight = 100;
addChild(_editControl);
addChild(_grid); _hScroll1 = new ScrollBar("hscroll1", Orientation.Horizontal);
addChild(_tabs); _hScroll2 = new ScrollBar("hscroll2", Orientation.Horizontal);
_vScroll1 = new ScrollBar("vscroll1", Orientation.Vertical);
_vScroll2 = new ScrollBar("vscroll2", Orientation.Vertical);
_scrollbars[0] = _hScroll1;
_scrollbars[1] = _vScroll1;
_scrollbars[2] = _hScroll2;
_scrollbars[3] = _vScroll2;
_viewTopLeft = new SpreadSheetView("sheetViewTopLeft");
_viewTopRight = new SpreadSheetView("sheetViewTopRight");
_viewBottomLeft = new SpreadSheetView("sheetViewBottomLeft");
_viewBottomRight = new SpreadSheetView("sheetViewBottomRight");
_viewTopRight.headerCols = 0;
_viewBottomLeft.headerRows = 0;
_viewBottomRight.headerCols = 0;
_viewBottomRight.headerRows = 0;
_views[0] = _viewTopLeft;
_views[1] = _viewTopRight;
_views[2] = _viewBottomLeft;
_views[3] = _viewBottomRight;
_viewTopLeft.hscrollbar = _hScroll1;
_viewTopLeft.vscrollbar = _vScroll1;
_viewTopRight.hscrollbar = _hScroll2;
_viewTopRight.vscrollbar = _vScroll1;
_viewBottomLeft.hscrollbar = _hScroll1;
_viewBottomLeft.vscrollbar = _vScroll2;
_viewBottomRight.hscrollbar = _hScroll2;
_viewBottomRight.vscrollbar = _vScroll2;
addChildren([_hScroll1, _vScroll1, _hScroll2, _vScroll2,
_viewTopLeft, _viewTopRight, _viewBottomLeft, _viewBottomRight,
_editControl, _tabs
]);
}
/// 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;
}
_measuredWidth = parentWidth;
_measuredHeight = parentHeight;
foreach(view; _views)
view.measure(parentWidth, parentHeight);
foreach(sb; _scrollbars)
sb.measure(parentWidth, parentHeight);
_editControl.measure(parentWidth, parentHeight);
_tabs.measure(parentWidth, parentHeight);
}
/// 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);
int editHeight = _editControl.measuredHeight;
_editControl.layout(Rect(rc.left, rc.top, rc.right, rc.top + editHeight));
rc.top += editHeight;
int splitWidth = 4;
int splitHeight = 4;
int hscrollHeight = _hScroll1.measuredHeight;
int vscrollWidth = _vScroll1.measuredWidth;
int tabsHeight = _tabs.measuredHeight;
int bottomSize = min(hscrollHeight, tabsHeight);
int splitx = (rc.width - vscrollWidth - splitWidth) / 2;
int splity = (rc.height - hscrollHeight - splitHeight) / 2;
_viewTopLeft.layout(Rect(rc.left, rc.top, rc.left + splitx, rc.top + splity));
_viewTopRight.layout(Rect(rc.left + splitx + splitWidth, rc.top, rc.right - vscrollWidth, rc.top + splity));
_viewBottomLeft.layout(Rect(rc.left, rc.top + splity + splitHeight, rc.left + splitx, rc.bottom - bottomSize));
_viewBottomRight.layout(Rect(rc.left + splitx + splitWidth, rc.top + splity + splitHeight, rc.right - vscrollWidth, rc.bottom - bottomSize));
int tabsWidth = splitx / 2;
_tabs.layout(Rect(rc.left, rc.bottom - bottomSize, rc.left + tabsWidth, rc.bottom - bottomSize + tabsHeight));
_hScroll1.layout(Rect(rc.left + tabsWidth + splitWidth, rc.bottom - hscrollHeight, rc.left + splitx, rc.bottom));
_hScroll2.layout(Rect(rc.left + splitx + splitWidth, rc.bottom - hscrollHeight, rc.right - vscrollWidth, rc.bottom));
_vScroll1.layout(Rect(rc.right - vscrollWidth, rc.top, rc.right, rc.top + splity));
_vScroll2.layout(Rect(rc.right - vscrollWidth, rc.top + splity + splitHeight, rc.right, rc.bottom - bottomSize));
} }
} }

View File

@ -2,9 +2,9 @@
<theme <theme
id="theme_custom" id="theme_custom"
parent="theme_default" parent="theme_default"
fontSize="16" fontSize="12px"
> >
<style id="TAB_SHEET_DOWN_BUTTON" <style id="TAB_SHEET_DOWN"
backgroundImageId="tab_sheet_down_background" backgroundImageId="tab_sheet_down_background"
layoutWidth="FILL_PARENT" layoutWidth="FILL_PARENT"
> >
@ -13,12 +13,12 @@
<style id="TAB_SHEET_DOWN_BUTTON_TEXT" <style id="TAB_SHEET_DOWN_BUTTON_TEXT"
textColor="#000000" textColor="#000000"
align="Center" align="Center"
fontSize="12px" fontSize="10px"
> >
<state state_selected="true" state_focused="true" textColor="#000000"/> <state state_selected="true" state_focused="true" textColor="#000000"/>
<state state_selected="true" textColor="#000000"/> <state state_selected="true" textColor="#000000"/>
<state state_focused="true" textColor="#000000"/> <state state_focused="true" textColor="#000000"/>
<state state_hovered="true" textColor="#808000"/> <state state_hovered="true" textColor="#800000"/>
</style> </style>
<style id="TAB_SHEET_DOWN_BUTTON" <style id="TAB_SHEET_DOWN_BUTTON"
backgroundImageId="tab_sheet_down" backgroundImageId="tab_sheet_down"

View File

@ -81,7 +81,9 @@ enum ScrollBarMode {
/** always visible */ /** always visible */
Visible, Visible,
/** automatically show/hide scrollbar depending on content size */ /** automatically show/hide scrollbar depending on content size */
Auto Auto,
/** Scrollbar is provided by external control outside this widget */
External,
} }
/** /**
@ -149,6 +151,35 @@ class ScrollWidgetBase : WidgetGroup, OnScrollHandler {
} }
} }
public @property ScrollBar hscrollbar() { return _hscrollbar; }
public @property ScrollBar vscrollbar() { return _vscrollbar; }
public @property void hscrollbar(ScrollBar hscroll) {
if (_hscrollbar) {
removeChild(_hscrollbar);
destroy(_hscrollbar);
_hscrollbar = null;
_hscrollbarMode = ScrollBarMode.Invisible;
}
if (_hscrollbar) {
_hscrollbar = hscroll;
_hscrollbarMode = ScrollBarMode.External;
}
}
public @property void vscrollbar(ScrollBar vscroll) {
if (_vscrollbar) {
removeChild(_vscrollbar);
destroy(_vscrollbar);
_vscrollbar = null;
_vscrollbarMode = ScrollBarMode.Invisible;
}
if (_vscrollbar) {
_vscrollbar = vscroll;
_vscrollbarMode = ScrollBarMode.External;
}
}
/// update horizontal scrollbar widget position /// update horizontal scrollbar widget position
protected void updateHScrollBar() { protected void updateHScrollBar() {
// default implementation: use _fullScrollableArea, _visibleScrollableArea: override it if necessary // default implementation: use _fullScrollableArea, _visibleScrollableArea: override it if necessary
@ -228,17 +259,17 @@ class ScrollWidgetBase : WidgetGroup, OnScrollHandler {
pwidth -= m.left + m.right + p.left + p.right; pwidth -= m.left + m.right + p.left + p.right;
if (parentHeight != SIZE_UNSPECIFIED) if (parentHeight != SIZE_UNSPECIFIED)
pheight -= m.top + m.bottom + p.top + p.bottom; pheight -= m.top + m.bottom + p.top + p.bottom;
if (_hscrollbar) { if (_hscrollbar && _hscrollbarMode == ScrollBarMode.Visible) {
_hscrollbar.measure(pwidth, pheight); _hscrollbar.measure(pwidth, pheight);
} }
if (_vscrollbar) { if (_vscrollbar && _vscrollbarMode == ScrollBarMode.Visible) {
_vscrollbar.measure(pwidth, pheight); _vscrollbar.measure(pwidth, pheight);
} }
Point sz = fullContentSize(); Point sz = fullContentSize();
if (_hscrollbar) { if (_hscrollbar && _hscrollbarMode == ScrollBarMode.Visible) {
sz.y += _hscrollbar.measuredHeight; sz.y += _hscrollbar.measuredHeight;
} }
if (_vscrollbar) { if (_vscrollbar && _vscrollbarMode == ScrollBarMode.Visible) {
sz.x += _vscrollbar.measuredWidth; sz.x += _vscrollbar.measuredWidth;
} }
measuredContent(parentWidth, parentHeight, sz.x, sz.y); measuredContent(parentWidth, parentHeight, sz.x, sz.y);
@ -258,8 +289,8 @@ class ScrollWidgetBase : WidgetGroup, OnScrollHandler {
applyMargins(rc); applyMargins(rc);
applyPadding(rc); applyPadding(rc);
Point sz = fullContentSize(); Point sz = fullContentSize();
bool needHscroll = _hscrollbarMode != ScrollBarMode.Invisible && sz.x > rc.width; bool needHscroll = _hscrollbarMode != ScrollBarMode.External && _hscrollbarMode != ScrollBarMode.Invisible && sz.x > rc.width;
bool needVscroll = _vscrollbarMode != ScrollBarMode.Invisible && sz.y > rc.height; bool needVscroll = _vscrollbarMode != ScrollBarMode.External && _vscrollbarMode != ScrollBarMode.Invisible && sz.y > rc.height;
if (needVscroll && _vscrollbarMode != ScrollBarMode.Invisible) if (needVscroll && _vscrollbarMode != ScrollBarMode.Invisible)
needHscroll = sz.x > rc.width - _vscrollbar.measuredWidth; needHscroll = sz.x > rc.width - _vscrollbar.measuredWidth;
if (needHscroll && _hscrollbarMode != ScrollBarMode.Invisible) if (needHscroll && _hscrollbarMode != ScrollBarMode.Invisible)

View File

@ -429,9 +429,11 @@ class TabControl : WidgetGroupDefaultDrawing {
pheight -= m.top + m.bottom + p.top + p.bottom; pheight -= m.top + m.bottom + p.top + p.bottom;
// measure children // measure children
Point sz; Point sz;
_moreButton.measure(pwidth, pheight); if (_moreButton.visibility == Visibility.Visible) {
sz.x = _moreButton.measuredWidth; _moreButton.measure(pwidth, pheight);
sz.y = _moreButton.measuredHeight; sz.x = _moreButton.measuredWidth;
sz.y = _moreButton.measuredHeight;
}
pwidth -= sz.x; pwidth -= sz.x;
for (int i = 1; i < _children.count; i++) { for (int i = 1; i < _children.count; i++) {
Widget tab = _children.get(i); Widget tab = _children.get(i);
@ -458,9 +460,11 @@ class TabControl : WidgetGroupDefaultDrawing {
applyPadding(rc); applyPadding(rc);
// more button // more button
Rect moreRc = rc; Rect moreRc = rc;
moreRc.left = rc.right - _moreButton.measuredWidth; if (_moreButton.visibility == Visibility.Visible) {
_moreButton.layout(moreRc); moreRc.left = rc.right - _moreButton.measuredWidth;
rc.right -= _moreButton.measuredWidth; _moreButton.layout(moreRc);
rc.right -= _moreButton.measuredWidth;
}
// tabs // tabs
int maxw = rc.width; int maxw = rc.width;
// measure and update visibility // measure and update visibility

View File

@ -1419,10 +1419,19 @@ class Widget {
Widget child(int index) { return null; } Widget child(int index) { return null; }
/// adds child, returns added item /// adds child, returns added item
Widget addChild(Widget item) { assert(false, "addChild: children not suported for this widget type"); } Widget addChild(Widget item) { assert(false, "addChild: children not suported for this widget type"); }
/// adds child, returns added item
Widget addChildren(Widget[] items) {
foreach(item; items) {
addChild(item);
}
return this;
}
/// removes child, returns removed item /// removes child, returns removed item
Widget removeChild(int index) { assert(false, "removeChild: children not suported for this widget type"); } Widget removeChild(int index) { assert(false, "removeChild: children not suported for this widget type"); }
/// removes child by ID, returns removed item /// removes child by ID, returns removed item
Widget removeChild(string id) { assert(false, "removeChild: children not suported for this widget type"); } Widget removeChild(string id) { assert(false, "removeChild: children not suported for this widget type"); }
/// removes child, returns removed item
Widget removeChild(Widget child) { assert(false, "removeChild: children not suported for this widget type"); }
/// returns index of widget in child list, -1 if passed widget is not a child of this widget /// returns index of widget in child list, -1 if passed widget is not a child of this widget
int childIndex(Widget item) { return -1; } int childIndex(Widget item) { return -1; }
@ -1639,6 +1648,17 @@ class WidgetGroup : Widget {
res.parent = null; res.parent = null;
return res; return res;
} }
/// removes child, returns removed item
override Widget removeChild(Widget child) {
Widget res = null;
int index = _children.indexOf(child);
if (index < 0)
return null;
res = _children.remove(index);
if (res !is null)
res.parent = null;
return res;
}
/// returns index of widget in child list, -1 if passed widget is not a child of this widget /// returns index of widget in child list, -1 if passed widget is not a child of this widget
override int childIndex(Widget item) { return _children.indexOf(item); } override int childIndex(Widget item) { return _children.indexOf(item); }