mirror of https://github.com/adamdruppe/arsd.git
171 lines
4.5 KiB
D
171 lines
4.5 KiB
D
/++
|
|
A small extension module to [arsd.minigui] that adds
|
|
functions for creating widgets and windows from short
|
|
XML descriptions.
|
|
|
|
If you choose to use this, it will require [arsd.dom]
|
|
to be compiled into your project too.
|
|
|
|
---
|
|
import arsd.minigui_xml;
|
|
Window window = createWindowFromXml(`
|
|
<MainWindow>
|
|
<Button label="Hi!" />
|
|
</MainWindow>
|
|
`);
|
|
---
|
|
|
|
|
|
To add custom widgets to the minigui_xml factory, you need
|
|
to register them with FIXME.
|
|
|
|
You can attach some events right in the XML using attributes.
|
|
The attribute names are `onEVENTNAME` or `ondirectEVENTNAME`
|
|
and the values are one of the following three value types:
|
|
|
|
$(LIST
|
|
* If it starts with `&`, it is a delegate you need
|
|
to register using the FIXME function.
|
|
|
|
* If it starts with `(`, it is a string passed to
|
|
the [arsd.dom.querySelector] function to get an
|
|
element reference
|
|
|
|
* Otherwise, it tries to call a script function (if
|
|
scripting is available).
|
|
)
|
|
|
|
Keep in mind
|
|
For example, to make a page widget that changes based on a
|
|
drop down selection, you may:
|
|
|
|
```xml
|
|
<DropDownSelection onchange="$(+PageWidget).setCurrentTab">
|
|
<option>Foo</option>
|
|
<option>Bar</option>
|
|
</DropDownSelection>
|
|
<PageWidget name="mypage">
|
|
<!-- contents elided -->
|
|
</PageWidget>
|
|
```
|
|
|
|
That will create a select widget that when it changes, it will
|
|
look for the next PageWidget sibling (that's the meaning of `+PageWidget`,
|
|
see css selector syntax for more) and call its `setCurrentTab`
|
|
method.
|
|
|
|
Since the function knows `setCurrentTab` takes an integer, it will
|
|
automatically pull the `intValue` member out of the event and pass
|
|
it to the method.
|
|
|
|
The given XML is the same as the following D:
|
|
|
|
---
|
|
auto select = new DropDownSelection(parent);
|
|
select.addOption("Foo");
|
|
select.addOption("Bar");
|
|
auto page = new PageWidget(parent);
|
|
page.name = "mypage";
|
|
|
|
select.addEventListener("change", (Event event) {
|
|
page.setCurrentTab(event.intValue);
|
|
});
|
|
---
|
|
+/
|
|
module arsd.minigui_xml;
|
|
|
|
public import arsd.minigui;
|
|
|
|
import arsd.dom;
|
|
|
|
private template ident(T...) {
|
|
static if(is(T[0]))
|
|
alias ident = T[0];
|
|
else
|
|
alias ident = void;
|
|
}
|
|
|
|
private
|
|
Widget delegate(string[string] args, Widget parent)[string] widgetFactoryFunctions;
|
|
|
|
private
|
|
void loadMiniguiPublicClasses() {
|
|
if(widgetFactoryFunctions !is null)
|
|
return;
|
|
|
|
import std.traits;
|
|
import std.conv;
|
|
|
|
foreach(memberName; __traits(allMembers, mixin("arsd.minigui"))) static if(!__traits(isDeprecated, __traits(getMember, mixin("arsd.minigui"), memberName))) {
|
|
alias Member = ident!(__traits(getMember, mixin("arsd.minigui"), memberName));
|
|
static if(is(Member == class) && !isAbstractClass!Member && is(Member : Widget) && __traits(getProtection, Member) != "private") {
|
|
widgetFactoryFunctions[memberName] = (string[string] args, Widget parent) {
|
|
static if(is(Member : Dialog)) {
|
|
return new Member();
|
|
} else static if(is(Member : Window)) {
|
|
return new Member("test");
|
|
} else {
|
|
auto paramNames = ParameterIdentifierTuple!(__traits(getMember, Member, "__ctor"));
|
|
Parameters!(__traits(getMember, Member, "__ctor")) params;
|
|
|
|
foreach(idx, param; params[0 .. $-1]) {
|
|
if(auto arg = paramNames[idx] in args) {
|
|
static if(is(typeof(param) == MemoryImage)) {
|
|
|
|
} else static if(is(typeof(param) == Color)) {
|
|
params[idx] = Color.fromString(*arg);
|
|
} else
|
|
params[idx] = to!(typeof(param))(*arg);
|
|
}
|
|
}
|
|
|
|
params[$-1] = parent;
|
|
|
|
auto widget = new Member(params);
|
|
|
|
if(auto st = "statusTip" in args)
|
|
widget.statusTip = *st;
|
|
if(auto st = "name" in args)
|
|
widget.name = *st;
|
|
return widget;
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
///
|
|
Widget makeWidgetFromString(string xml, Widget parent) {
|
|
auto document = new Document(xml, true, true);
|
|
auto r = document.root;
|
|
return miniguiWidgetFromXml(r, parent);
|
|
}
|
|
|
|
///
|
|
Window createWindowFromXml(string xml) {
|
|
return createWindowFromXml(new Document(xml, true, true));
|
|
}
|
|
///
|
|
Window createWindowFromXml(Document document) {
|
|
auto r = document.root;
|
|
return cast(Window) miniguiWidgetFromXml(r, null);
|
|
}
|
|
///
|
|
Widget miniguiWidgetFromXml(Element element, Widget parent) {
|
|
if(widgetFactoryFunctions is null)
|
|
loadMiniguiPublicClasses();
|
|
if(auto factory = element.tagName in widgetFactoryFunctions) {
|
|
auto p = (*factory)(element.attributes, parent);
|
|
foreach(child; element.children)
|
|
if(child.tagName != "#text")
|
|
miniguiWidgetFromXml(child, p);
|
|
return p;
|
|
} else {
|
|
import std.stdio;
|
|
writeln("Unknown class: ", element.tagName);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|