Added property tree widget and browser dialog
This commit is contained in:
parent
f1e099641f
commit
f569a5ac29
4 changed files with 286 additions and 1 deletions
|
@ -43,6 +43,7 @@ loadWidget("Label");
|
|||
loadWidget("LineEdit");
|
||||
loadWidget("List");
|
||||
loadWidget("MenuBar");
|
||||
loadWidget("PropertyTree");
|
||||
loadWidget("PropertyWidgets");
|
||||
loadWidget("ScrollArea");
|
||||
loadWidget("Rule");
|
||||
|
@ -54,6 +55,7 @@ loadWidget("ComboBox");
|
|||
loadDialog("InputDialog");
|
||||
loadDialog("MessageBox");
|
||||
loadDialog("WidgetsFactoryDialog");
|
||||
loadDialog("PropertyTreeBrowser");
|
||||
|
||||
var style = DefaultStyle.new("AmbianceClassic", "Humanity");
|
||||
var WindowButton = {
|
||||
|
|
133
Nasal/canvas/gui/dialogs/PropertyTreeBrowser.nas
Normal file
133
Nasal/canvas/gui/dialogs/PropertyTreeBrowser.nas
Normal file
|
@ -0,0 +1,133 @@
|
|||
var PropertyTreeBrowser = {
|
||||
new: func(node = nil) {
|
||||
if (node == nil) {
|
||||
node = props.globals.getNode(props.globals.getValue("/sim/gui/dialogs/property-browser/selected"));
|
||||
}
|
||||
var m = {
|
||||
parents: [PropertyTreeBrowser],
|
||||
};
|
||||
|
||||
m.resetTitleTimer = maketimer(5, func {
|
||||
m.window.setTitle(m.propertyTree.getNode().getPath() ~ " - Property browser");
|
||||
m.resetTitleTimer.stop();
|
||||
});
|
||||
m.simulatedTime = 0;
|
||||
m.singleShot = 1;
|
||||
|
||||
m.window = canvas.Window.new([400, 550], "dialog")
|
||||
.setTitle((node != nil ? node.getPath() : "/") ~ " - Property browser")
|
||||
.set("resize", 1);
|
||||
m.window.onClose = func m.onClose();
|
||||
m.root = m.window.getCanvas(1)
|
||||
.set("background", style.getColor("bg_color"))
|
||||
.createGroup();
|
||||
m.layout = VBoxLayout.new();
|
||||
m.layout.setContentsMargin(10);
|
||||
m.window.setLayout(m.layout);
|
||||
|
||||
m.propertyTree = gui.widgets.PropertyTree.new(m.root);
|
||||
if (node != nil) {
|
||||
m.propertyTree.setNode(node);
|
||||
}
|
||||
m.propertyTree._view._root.addEventListener("click", func {
|
||||
props.globals.setValue("/sim/gui/dialogs/property-browser/selected", m.propertyTree.getNode().getPath());
|
||||
m.window.setTitle(m.propertyTree.getNode().getPath() ~ " - Property browser");
|
||||
var selected = m.propertyTree.getSelectedItems();
|
||||
if (!size(selected)) {
|
||||
return;
|
||||
}
|
||||
var node = selected[0].getData("node");
|
||||
if (size(node.getChildren()) == 0) {
|
||||
var value = nil;
|
||||
var type = node.getType();
|
||||
if (type == "BOOL") {
|
||||
value = node.getBoolValue() ? "true" : "false";
|
||||
m.window.setTitle("Hint: hold Ctrl while clicking to toggle bool value");
|
||||
m.resetTitleTimer.restart(5);
|
||||
} elsif (type == "STRING") {
|
||||
value = node.getValue();
|
||||
} elsif (type == "NONE") {
|
||||
value = "";
|
||||
} elsif (type != "ALIAS") {
|
||||
value = node.getValue() ~ "";
|
||||
}
|
||||
m.valueEntry.setText(value);
|
||||
} else {
|
||||
m.window.setTitle(m.propertyTree.getNode().getPath() ~ " - Property browser");
|
||||
m.valueEntry.clear();
|
||||
}
|
||||
});
|
||||
m.propertyTree.setLayoutSizeHint([m.propertyTree._MAX_SIZE, m.propertyTree._MAX_SIZE]);
|
||||
m.layout.addItem(m.propertyTree);
|
||||
|
||||
m.showAttrsCheckbox = gui.widgets.CheckBox.new(m.root, canvas.style, {})
|
||||
.setText("Show attributes and listener count")
|
||||
.listen("toggled", func(e) {
|
||||
m.propertyTree.showAttrs = e.detail.checked;
|
||||
});
|
||||
m.layout.addItem(m.showAttrsCheckbox);
|
||||
|
||||
m.valueLayout = HBoxLayout.new();
|
||||
m.layout.addItem(m.valueLayout);
|
||||
m.valueEntry = gui.widgets.LineEdit.new(m.root, canvas.style, {});
|
||||
m.valueLayout.addItem(m.valueEntry);
|
||||
m.valueButton = gui.widgets.Button.new(m.root, canvas.style, {})
|
||||
.setText("Set")
|
||||
.setFixedSize(50, 28)
|
||||
.listen("clicked", func {
|
||||
var selected = m.propertyTree.getSelectedItems();
|
||||
if (size(selected) == 0) {
|
||||
return;
|
||||
}
|
||||
var node = selected[0].getData("node");
|
||||
node.setValue(m.valueEntry.text());
|
||||
});
|
||||
m.valueLayout.addItem(m.valueButton);
|
||||
|
||||
m.buttonsLayout = HBoxLayout.new();
|
||||
m.layout.addItem(m.buttonsLayout);
|
||||
|
||||
m.cloneButton = gui.widgets.Button.new(m.root, canvas.style, {})
|
||||
.setText("Clone")
|
||||
.listen("clicked", func m.clone());
|
||||
m.cloneButton.setAlignment(AlignLeft);
|
||||
m.buttonsLayout.addItem(m.cloneButton);
|
||||
|
||||
m.closeButton = gui.widgets.Button.new(m.root, canvas.style, {})
|
||||
.setText("Close")
|
||||
.listen("clicked", func m.onClose());
|
||||
m.closeButton.setAlignment(AlignRight);
|
||||
m.buttonsLayout.addItem(m.closeButton);
|
||||
|
||||
m.show();
|
||||
|
||||
return m;
|
||||
},
|
||||
|
||||
clone: func {
|
||||
PropertyTreeBrowser.new(me.propertyTree.getNode());
|
||||
},
|
||||
|
||||
onClose: func {
|
||||
if (me.window._destroy_on_close) {
|
||||
me.del();
|
||||
} else {
|
||||
me.hide();
|
||||
}
|
||||
},
|
||||
|
||||
show: func {
|
||||
me.window.show();
|
||||
me.propertyTree.show();
|
||||
},
|
||||
|
||||
hide: func {
|
||||
me.propertyTree.hide();
|
||||
me.window.hide();
|
||||
},
|
||||
|
||||
del: func {
|
||||
me.propertyTree.del();
|
||||
me.window.del();
|
||||
},
|
||||
};
|
131
Nasal/canvas/gui/widgets/PropertyTree.nas
Normal file
131
Nasal/canvas/gui/widgets/PropertyTree.nas
Normal file
|
@ -0,0 +1,131 @@
|
|||
gui.widgets.PropertyTree = {
|
||||
AttributeMapping: {
|
||||
"archive": "A",
|
||||
"alias": "L",
|
||||
"preserve": "P",
|
||||
"readable": "R",
|
||||
"tied": "T",
|
||||
"trace-read": "Tr",
|
||||
"trace-write": "Tw",
|
||||
"userarchive": "U",
|
||||
"writable": "W",
|
||||
},
|
||||
|
||||
new: func(parent, style = nil, cfg = nil) {
|
||||
var m = gui.widgets.List.new(parent, style, cfg);
|
||||
m.parents = [gui.widgets.PropertyTree] ~ m.parents;
|
||||
m.showAttrs = 0;
|
||||
m._node = m._cfg.get("node", props.globals);
|
||||
m.rebuildList();
|
||||
m.listen("selection-changed", func {
|
||||
var selected = m.getSelectedItems();
|
||||
if (!size(selected)) {
|
||||
return;
|
||||
}
|
||||
var node = selected[0].getData("node");
|
||||
if (size(node.getChildren()) > 0) {
|
||||
m.setNode(node);
|
||||
}
|
||||
});
|
||||
m.updateTimer = maketimer(0, func m.update());
|
||||
m.updateTimer.simulatedTime = 0;
|
||||
m.updateTimer.start();
|
||||
|
||||
return m;
|
||||
},
|
||||
|
||||
show: func {
|
||||
call(me.parents[1].show, [], me);
|
||||
me.updateTimer.start();
|
||||
},
|
||||
|
||||
hide: func {
|
||||
call(me.parents[1].hide, [], me);
|
||||
me.updateTimer.stop();
|
||||
},
|
||||
|
||||
getNode: func {
|
||||
return me._node;
|
||||
},
|
||||
|
||||
setNode: func(node) {
|
||||
me._node = node;
|
||||
me.rebuildList();
|
||||
return me;
|
||||
},
|
||||
|
||||
rebuildList: func {
|
||||
me.clear();
|
||||
if (me._node.getParent()) {
|
||||
var item = me.createItem("../")
|
||||
.setData("node", me._node.getParent());
|
||||
}
|
||||
foreach (var c; sort(me._node.getChildren(), func(a, b) cmp(a.getName(), b.getName()))) {
|
||||
if (size(c.getChildren())) {
|
||||
var index = c.getIndex();
|
||||
var name = c.getName() ~ (index > 0 ? "[" ~ index ~ "]" : "");
|
||||
|
||||
var item = me.createItem(name ~ "/");
|
||||
} else {
|
||||
var item = me.createItem("");
|
||||
item._view._root.addEventListener("click", func(e) me.itemClicked(e));
|
||||
}
|
||||
item.setData("node", c);
|
||||
}
|
||||
},
|
||||
|
||||
itemClicked: func(e) {
|
||||
if (!e.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
var selected = me.getSelectedItems();
|
||||
if (!size(selected)) {
|
||||
return;
|
||||
}
|
||||
var node = selected[0].getData("node");
|
||||
if (node.getType() == "BOOL") {
|
||||
node.toggleBoolValue();
|
||||
}
|
||||
},
|
||||
|
||||
update: func {
|
||||
for (var i = 0; i < me.count(); i += 1) {
|
||||
var item = me.getItem(i);
|
||||
var node = item.getData("node");
|
||||
if (size(node.getChildren()) == 0) {
|
||||
var type = node.getType();
|
||||
var index = node.getIndex();
|
||||
var name = node.getName() ~ (index > 0 ? "[" ~ index ~ "]" : "");
|
||||
var value = nil;
|
||||
if (type == "BOOL") {
|
||||
value = node.getBoolValue() ? "true" : "false";
|
||||
} elsif (type == "STRING" or type == "UNSPECIFIED") {
|
||||
value = "'" ~ string.replace(node.getValue(), "\n", "\\n") ~ "'";
|
||||
} elsif (type != "ALIAS" and type != "NONE") {
|
||||
value = node.getValue() ~ "";
|
||||
}
|
||||
if (value != nil) {
|
||||
var attrString = "";
|
||||
if (me.showAttrs) {
|
||||
attrString ~= " ";
|
||||
foreach (var attr; sort(keys(me.AttributeMapping), func(a, b) cmp(a, b))) {
|
||||
if (node.getAttribute(attr)) {
|
||||
attrString ~= me.AttributeMapping[attr];
|
||||
}
|
||||
}
|
||||
attrString ~= " " ~ node.getAttribute("listeners");
|
||||
}
|
||||
item.setText(node.getName() ~ " = " ~ value ~ " (" ~ string.lc(node.getType()) ~ attrString ~ ")");
|
||||
} else {
|
||||
item.setText(node.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
call(me.parents[1].update, [], me);
|
||||
},
|
||||
|
||||
del: func {
|
||||
me.updateTimer.stop();
|
||||
},
|
||||
};
|
||||
|
|
@ -235,10 +235,13 @@
|
|||
</group>
|
||||
|
||||
<group>
|
||||
<layout>hbox</layout>
|
||||
<layout>table</layout>
|
||||
<halign>left</halign>
|
||||
|
||||
<button>
|
||||
<row>0</row>
|
||||
<col>0</col>
|
||||
<halign>fill</halign>
|
||||
<legend>New Canvas Map</legend>
|
||||
<binding>
|
||||
<command>nasal</command>
|
||||
|
@ -246,6 +249,9 @@
|
|||
</binding>
|
||||
</button>
|
||||
<button>
|
||||
<row>0</row>
|
||||
<col>1</col>
|
||||
<halign>fill</halign>
|
||||
<legend>Canvas widgets factory</legend>
|
||||
<binding>
|
||||
<command>nasal</command>
|
||||
|
@ -253,6 +259,19 @@
|
|||
</binding>
|
||||
</button>
|
||||
<button>
|
||||
<row>0</row>
|
||||
<col>2</col>
|
||||
<halign>fill</halign>
|
||||
<legend>Canvas property tree browser</legend>
|
||||
<binding>
|
||||
<command>nasal</command>
|
||||
<script>globals.propertyTreeBrowserInstance = canvas.PropertyTreeBrowser.new();</script>
|
||||
</binding>
|
||||
</button>
|
||||
<button>
|
||||
<row>1</row>
|
||||
<col>0</col>
|
||||
<halign>fill</halign>
|
||||
<legend>Reload Nasal canvas module</legend>
|
||||
<binding>
|
||||
<command>nasal-reload</command>
|
||||
|
|
Loading…
Add table
Reference in a new issue