Tree widget, continue development

This commit is contained in:
Vadim Lopatin 2014-12-01 12:29:34 +03:00
parent d06ad1a2f1
commit 88a288c6b2
5 changed files with 155 additions and 17 deletions

View File

@ -623,6 +623,15 @@ extern (C) int UIAppMain(string[] args) {
// tree view example
TreeWidget tree = new TreeWidget("TREE1");
tree.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
TreeItem tree1 = tree.items.newChild("group1", "Group 1"d);
tree1.newChild("g1_1", "Group 1 item 1"d);
tree1.newChild("g1_2", "Group 1 item 2"d);
tree1.newChild("g1_3", "Group 1 item 3"d);
TreeItem tree2 = tree.items.newChild("group2", "Group 2"d);
tree2.newChild("g2_1", "Group 2 item 1"d);
tree2.newChild("g2_2", "Group 2 item 2"d);
tree2.newChild("g2_3", "Group 2 item 3"d);
tree2.newChild("g2_4", "Group 2 item 4"d);
tabs.addTab(tree, "Tree"d);

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -3,6 +3,7 @@ module dlangui.widgets.tree;
import dlangui.widgets.widget;
import dlangui.widgets.controls;
import dlangui.widgets.scroll;
import dlangui.widgets.layouts;
import std.conv;
import std.algorithm;
@ -16,6 +17,36 @@ class TreeItem {
protected ObjectList!TreeItem _children;
protected bool _expanded;
this(string id) {
_id = id;
_expanded = true;
}
this(string id, dstring label, string iconRes = null) {
_id = id;
_expanded = true;
_iconRes = iconRes;
_text = label;
}
this(string id, UIString label, string iconRes = null) {
_id = id;
_expanded = true;
_iconRes = iconRes;
_text = label;
}
this(string id, string labelRes, string iconRes = null) {
_id = id;
_expanded = true;
_iconRes = iconRes;
_text = labelRes;
}
/// create and add new child item
TreeItem newChild(string id, dstring label, string iconRes = null) {
TreeItem res = new TreeItem(id, label, iconRes);
addChild(res);
return res;
}
@property TreeItem parent() { return _parent; }
@property protected TreeItem parent(TreeItem p) { _parent = p; return this; }
@property string id() { return _id; }
@ -31,11 +62,16 @@ class TreeItem {
}
@property bool expanded() { return _expanded; }
@property protected TreeItem expanded(bool expanded) { _expanded = expanded; return this; }
/** Returns true if this item and all parents are expanded. */
bool isFullyExpanded() {
if (!_expanded)
return false;
return isVisible();
}
/** Returns true if all parents are expanded. */
bool isVisible() {
if (_parent)
return _parent.isFullyExpanded();
return _parent.isVisible();
return false;
}
void expand() {
@ -72,6 +108,9 @@ class TreeItem {
return _parent.topParent;
}
/// returns true if item has at least one child
@property bool hasChildren() { return childCount > 0; }
/// returns number of children of this widget
@property int childCount() { return _children.count; }
/// returns child by index
@ -100,7 +139,11 @@ class TreeItem {
}
/// returns index of widget in child list, -1 if passed widget is not a child of this widget
int childIndex(TreeItem item) { return _children.indexOf(item); }
/// notify listeners
protected void onUpdate(TreeItem item) {
if (_parent)
_parent.onUpdate(item);
}
}
interface OnTreeContentChangeListener {
@ -109,36 +152,114 @@ interface OnTreeContentChangeListener {
class TreeItems : TreeItem {
// signal handler OnTreeContentChangeListener
Listener!OnTreeContentChangeListener listener;
Signal!OnTreeContentChangeListener listener;
this() {
super("tree");
}
/// notify listeners
override protected void onUpdate(TreeItem item) {
if (listener.assigned)
listener(this);
}
}
class TreeWidgetBase : ScrollWidgetBase {
class TreeItemWidget : HorizontalLayout {
TreeItem _item;
TextWidget _tab;
ImageWidget _expander;
ImageWidget _icon;
TextWidget _label;
this(TreeItem item) {
super(item.id);
_item = item;
_tab = new TextWidget("tab");
dchar[] tabText;
dchar[] singleTab = [' ', ' ', ' ', ' '];
for (int i = 1; i < _item.level; i++)
tabText ~= singleTab;
_tab.text = cast(dstring)tabText;
_expander = new ImageWidget("expander", _item.hasChildren && _item.expanded ? "arrow_right_down_black" : "arrow_right_hollow");
if (!_item.hasChildren)
_expander.visibility = Visibility.Gone;
if (_item.iconRes.length > 0)
_icon = new ImageWidget("icon", _item.iconRes);
_label = new TextWidget("label", _item.text);
addChild(_tab);
addChild(_expander);
if (_icon)
addChild(_icon);
addChild(_label);
}
}
class TreeWidgetBase : ScrollWidget, OnTreeContentChangeListener {
protected TreeItems _tree;
@property ref TreeItems items() { return _tree; }
protected bool _needUpdateWidgets;
this(string ID = null, ScrollBarMode hscrollbarMode = ScrollBarMode.Visible, ScrollBarMode vscrollbarMode = ScrollBarMode.Visible) {
super(ID, hscrollbarMode, vscrollbarMode);
contentWidget = new VerticalLayout("TREE_CONTENT");
_tree = new TreeItems();
_tree.listener.connect(this);
_needUpdateWidgets = true;
}
/// process horizontal scrollbar event
override bool onHScroll(ScrollEvent event) {
return true;
~this() {
if (_tree) {
destroy(_tree);
_tree = null;
}
}
/// process vertical scrollbar event
override bool onVScroll(ScrollEvent event) {
return true;
/** Override to use custom tree item widgets. */
protected Widget createItemWidget(TreeItem item) {
return new TreeItemWidget(item);
}
/// update horizontal scrollbar widget position
override protected void updateHScrollBar() {
// override it
protected void addWidgets(TreeItem item) {
if (item.level > 0)
_contentWidget.addChild(createItemWidget(item));
for (int i = 0; i < item.childCount; i++)
addWidgets(item.child(i));
}
/// update verticat scrollbar widget position
override protected void updateVScrollBar() {
// override it
protected void updateWidgets() {
_contentWidget.removeAllChildren();
addWidgets(_tree);
_needUpdateWidgets = false;
}
/// 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;
}
if (_needUpdateWidgets)
updateWidgets();
super.layout(rc);
}
/// 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;
}
if (_needUpdateWidgets)
updateWidgets();
super.measure(parentWidth, parentHeight);
}
/// listener
override void onTreeContentChange(TreeItems source) {
_needUpdateWidgets = true;
requestLayout();
}
}
class TreeWidget : TreeWidgetBase {

View File

@ -1207,7 +1207,10 @@ class Widget {
/// sets window (to be used for top level widget from Window implementation). TODO: hide it from API?
@property void window(Window window) { _window = window; }
void removeAllChildren() {
// override
}
}
/// object list holder, owning its objects - on destroy of holder, all own objects will be destroyed
@ -1316,4 +1319,9 @@ class WidgetGroup : 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 void removeAllChildren() {
_children.clear();
}
}