diff --git a/dlanguilib.visualdproj b/dlanguilib.visualdproj
index 295152c1..c903befa 100644
--- a/dlanguilib.visualdproj
+++ b/dlanguilib.visualdproj
@@ -426,6 +426,7 @@
+
diff --git a/examples/example1/src/example1.d b/examples/example1/src/example1.d
index 92de05bb..7ec39a55 100644
--- a/examples/example1/src/example1.d
+++ b/examples/example1/src/example1.d
@@ -445,6 +445,15 @@ extern (C) int UIAppMain(string[] args) {
layout.addChild((new TextWidget(null, "Text widget3 with very long text"d)).textColor(0x004000));
layout.addChild(new VSpacer()); // vertical spacer to fill extra space
+ /*
+ import dlangui.core.parser;
+ Widget w = parseML(q{
+ TextWidget {
+ }
+ });
+ Log.d("id=", w.id);
+ */
+
layout.childById("BTN1").onClickListener = (delegate (Widget w) { Log.d("onClick ", w.id); return true; });
layout.childById("BTN2").onClickListener = (delegate (Widget w) { Log.d("onClick ", w.id); return true; });
layout.childById("BTN3").onClickListener = (delegate (Widget w) { Log.d("onClick ", w.id); return true; });
diff --git a/src/dlangui/core/parser.d b/src/dlangui/core/parser.d
index cabbf00f..1c334214 100644
--- a/src/dlangui/core/parser.d
+++ b/src/dlangui/core/parser.d
@@ -2,6 +2,7 @@ module dlangui.core.parser;
import dlangui.core.linestream;
import dlangui.widgets.widget;
+import dlangui.widgets.metadata;
import std.conv : to;
class ParserException : Exception {
@@ -313,7 +314,7 @@ class Tokenizer {
}
protected ref const(Token) parseOp(TokenType op) {
- _token.type = TokenType.error;
+ _token.type = op;
skipChar();
return _token;
}
@@ -380,26 +381,41 @@ class MLParser {
protected Token _token;
+
+ protected void nextToken() {
+ _token = _tokenizer.nextToken();
+ Log.d("parsed token: ", _token.type, " ", _token.line, ":", _token.pos, " ", _token.text);
+ }
+
protected void skipWhitespaceAndEols() {
for (;;) {
- _token = _tokenizer.nextToken();
- if (_token.type != TokenType.eol && _token.type != TokenType.eof && _token.type != TokenType.whitespace && _token.type != TokenType.comment)
+ nextToken();
+ if (_token.type != TokenType.eol && _token.type != TokenType.whitespace && _token.type != TokenType.comment)
break;
}
if (_token.type == TokenType.error)
_tokenizer.emitError("error while parsing ML code");
}
+ protected void skipWhitespace() {
+ for (;;) {
+ nextToken();
+ if (_token.type != TokenType.whitespace && _token.type != TokenType.comment)
+ break;
+ }
+ if (_token.type == TokenType.error)
+ _tokenizer.emitError("error while parsing ML code");
+ }
protected void error(string msg) {
_tokenizer.emitError(msg);
}
Widget createWidget(string name) {
- WidgetFactory factory = getWidgetFactory(name);
- if (!factory)
- error("Cannot create widget " ~ name ~ " : unknown class");
- return factory();
+ auto metadata = findWidgetMetadata(name);
+ if (!metadata)
+ error("Cannot create widget " ~ name ~ " : unregistered widget class");
+ return metadata.create();
}
protected void createContext(string name) {
@@ -419,6 +435,11 @@ class MLParser {
if (!_context)
_tokenizer.emitError("No context widget is specified!");
skipWhitespaceAndEols();
+ if (_token.type != TokenType.curlyClose) // {
+ _tokenizer.emitError("} is expected");
+ skipWhitespaceAndEols();
+ if (_token.type != TokenType.eof) // {
+ _tokenizer.emitError("end of file expected");
return _context;
}
@@ -427,10 +448,12 @@ class MLParser {
_tokenizer = null;
}
- /// Parse DlangUI ML code
- static Widget parse(string code, string filename = "", Widget context = null) {
- MLParser parser = new MLParser(code, filename);
- scope(exit) destroy(parser);
- return parser.parse();
- }
+}
+
+
+/// Parse DlangUI ML code
+public Widget parseML(string code, string filename = "", Widget context = null) {
+ MLParser parser = new MLParser(code, filename);
+ scope(exit) destroy(parser);
+ return parser.parse();
}
diff --git a/src/dlangui/widgets/controls.d b/src/dlangui/widgets/controls.d
index 8fe66470..49de599c 100644
--- a/src/dlangui/widgets/controls.d
+++ b/src/dlangui/widgets/controls.d
@@ -1029,3 +1029,5 @@ class CanvasWidget : Widget {
}
}
+import dlangui.widgets.metadata;
+mixin(registerWidgets!(Widget, TextWidget, Button, ImageWidget, ImageButton, ImageTextButton, RadioButton, CheckBox, ScrollBar)());
diff --git a/src/dlangui/widgets/layouts.d b/src/dlangui/widgets/layouts.d
index f0628c40..9640882d 100644
--- a/src/dlangui/widgets/layouts.d
+++ b/src/dlangui/widgets/layouts.d
@@ -840,3 +840,6 @@ class TableLayout : WidgetGroupDefaultDrawing {
}
}
+
+import dlangui.widgets.metadata;
+mixin(registerWidgets!(VerticalLayout, HorizontalLayout, TableLayout, FrameLayout)());
diff --git a/src/dlangui/widgets/metadata.d b/src/dlangui/widgets/metadata.d
new file mode 100644
index 00000000..7f07ffbf
--- /dev/null
+++ b/src/dlangui/widgets/metadata.d
@@ -0,0 +1,52 @@
+module dlangui.widgets.metadata;
+
+import dlangui.widgets.widget;
+
+interface WidgetMetadataDef {
+ Widget create();
+}
+
+private __gshared WidgetMetadataDef[string] _registeredWidgets;
+
+WidgetMetadataDef findWidgetMetadata(string name) {
+ if (auto p = name in _registeredWidgets)
+ return *p;
+ return null;
+}
+
+void registerWidgetMetadata(string name, WidgetMetadataDef metadata) {
+ _registeredWidgets[name] = metadata;
+}
+
+string generateMetadataClass(alias t)() {
+ import std.traits;
+ immutable string metadataClassName = t.stringof ~ "Metadata";
+ return "class " ~ metadataClassName ~ " : WidgetMetadataDef { \n" ~
+ " override Widget create() {\n" ~
+ " return new " ~ moduleName!t ~ "." ~ t.stringof ~ "();\n" ~
+ " }\n" ~
+ "}\n";
+}
+
+string generateRegisterMetadataClass(alias t)() {
+ immutable string metadataClassName = t.stringof ~ "Metadata";
+ return "registerWidgetMetadata(\"" ~ t.stringof ~ "\", new " ~ metadataClassName ~ "());\n";
+}
+
+string registerWidgets(T...)() {
+ string classDefs;
+ string registerDefs;
+ foreach(t; T) {
+ //pragma(msg, t.stringof);
+ //pragma(msg, moduleName!t);
+ //
+ immutable string classdef = generateMetadataClass!t;
+ //pragma(msg, classdef);
+ immutable string registerdef = generateRegisterMetadataClass!t;
+ //pragma(msg, registerdef);
+ classDefs ~= classdef;
+ registerDefs ~= registerdef;
+ //registerWidgetMetadata(T.stringof, new Metadata());
+ }
+ return classDefs ~ "\n__gshared static this() {\n" ~ registerDefs ~ "}";
+}
diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d
index 88ccdff9..90ddc6c8 100644
--- a/src/dlangui/widgets/widget.d
+++ b/src/dlangui/widgets/widget.d
@@ -1439,6 +1439,73 @@ class Widget {
// override
}
+ /// set string property value, for ML loaders
+ bool setProperty(string name, string value) {
+ if (name.equal("text")) {
+ text = UIString(value);
+ return true;
+ }
+ return false;
+ }
+
+ /// set string property value, for ML loaders
+ bool setProperty(string name, UIString value) {
+ if (name.equal("text")) {
+ text = value;
+ return true;
+ }
+ return false;
+ }
+
+ /// set int property value, for ML loaders
+ bool setProperty(string name, int value) {
+ if (name.equal("minWidth")) {
+ minWidth = value;
+ return true;
+ }
+ if (name.equal("maxWidth")) {
+ maxWidth = value;
+ return true;
+ }
+ if (name.equal("minHeight")) {
+ minHeight = value;
+ return true;
+ }
+ if (name.equal("maxHeight")) {
+ maxHeight = value;
+ return true;
+ }
+ if (name.equal("layoutWidth")) {
+ layoutWidth = value;
+ return true;
+ }
+ if (name.equal("layoutHeight")) {
+ layoutHeight = value;
+ return true;
+ }
+ if (name.equal("textColor")) {
+ textColor = cast(uint)value;
+ return true;
+ }
+ if (name.equal("backgroundColor")) {
+ backgroundColor = cast(uint)value;
+ return true;
+ }
+ return false;
+ }
+
+ /// set int property value, for ML loaders
+ bool setProperty(string name, Rect value) {
+ if (name.equal("margins")) {
+ margins = value;
+ return true;
+ }
+ if (name.equal("padding")) {
+ padding = value;
+ return true;
+ }
+ return false;
+ }
}
/** Widget list holder. */
@@ -1596,28 +1663,4 @@ mixin template ActionTooltipSupport() {
}
}
-alias WidgetFactory = Widget function();
-private __gshared WidgetFactory[string] _widgetFactories;
-
-WidgetFactory getWidgetFactory(string name) {
- return _widgetFactories[name];
-}
-
-void registerWidgetFactory(string name, WidgetFactory factory) {
- _widgetFactories[name] = factory;
-}
-
-void registerWidgetFactories(T...)() {
- foreach(t; T) {
- //pragma(msg, t.stringof);
- immutable string code = "WidgetFactory f = function() { return new " ~ t.stringof ~ "(); };";
- //pragma(msg, code);
- mixin(code);
- registerWidgetFactory(T.stringof, f);
- }
-}
-
-__gshared static this() {
- registerWidgetFactories!Widget;
-}