ML parser, continue

This commit is contained in:
Vadim Lopatin 2015-03-31 18:33:06 +03:00
parent e497b6bb36
commit bec083326b
7 changed files with 170 additions and 37 deletions

View File

@ -426,6 +426,7 @@
<File path="src\dlangui\widgets\layouts.d" />
<File path="src\dlangui\widgets\lists.d" />
<File path="src\dlangui\widgets\menu.d" />
<File path="src\dlangui\widgets\metadata.d" />
<File path="src\dlangui\widgets\popup.d" />
<File path="src\dlangui\widgets\scroll.d" />
<File path="src\dlangui\widgets\srcedit.d" />

View File

@ -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; });

View File

@ -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();
}

View File

@ -1029,3 +1029,5 @@ class CanvasWidget : Widget {
}
}
import dlangui.widgets.metadata;
mixin(registerWidgets!(Widget, TextWidget, Button, ImageWidget, ImageButton, ImageTextButton, RadioButton, CheckBox, ScrollBar)());

View File

@ -840,3 +840,6 @@ class TableLayout : WidgetGroupDefaultDrawing {
}
}
import dlangui.widgets.metadata;
mixin(registerWidgets!(VerticalLayout, HorizontalLayout, TableLayout, FrameLayout)());

View File

@ -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 ~ "}";
}

View File

@ -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;
}