mirror of https://github.com/buggins/dlangui.git
ML parser, continue
This commit is contained in:
parent
e497b6bb36
commit
bec083326b
|
@ -426,6 +426,7 @@
|
||||||
<File path="src\dlangui\widgets\layouts.d" />
|
<File path="src\dlangui\widgets\layouts.d" />
|
||||||
<File path="src\dlangui\widgets\lists.d" />
|
<File path="src\dlangui\widgets\lists.d" />
|
||||||
<File path="src\dlangui\widgets\menu.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\popup.d" />
|
||||||
<File path="src\dlangui\widgets\scroll.d" />
|
<File path="src\dlangui\widgets\scroll.d" />
|
||||||
<File path="src\dlangui\widgets\srcedit.d" />
|
<File path="src\dlangui\widgets\srcedit.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 TextWidget(null, "Text widget3 with very long text"d)).textColor(0x004000));
|
||||||
layout.addChild(new VSpacer()); // vertical spacer to fill extra space
|
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("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("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; });
|
layout.childById("BTN3").onClickListener = (delegate (Widget w) { Log.d("onClick ", w.id); return true; });
|
||||||
|
|
|
@ -2,6 +2,7 @@ module dlangui.core.parser;
|
||||||
|
|
||||||
import dlangui.core.linestream;
|
import dlangui.core.linestream;
|
||||||
import dlangui.widgets.widget;
|
import dlangui.widgets.widget;
|
||||||
|
import dlangui.widgets.metadata;
|
||||||
import std.conv : to;
|
import std.conv : to;
|
||||||
|
|
||||||
class ParserException : Exception {
|
class ParserException : Exception {
|
||||||
|
@ -313,7 +314,7 @@ class Tokenizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ref const(Token) parseOp(TokenType op) {
|
protected ref const(Token) parseOp(TokenType op) {
|
||||||
_token.type = TokenType.error;
|
_token.type = op;
|
||||||
skipChar();
|
skipChar();
|
||||||
return _token;
|
return _token;
|
||||||
}
|
}
|
||||||
|
@ -380,26 +381,41 @@ class MLParser {
|
||||||
|
|
||||||
protected Token _token;
|
protected Token _token;
|
||||||
|
|
||||||
|
|
||||||
|
protected void nextToken() {
|
||||||
|
_token = _tokenizer.nextToken();
|
||||||
|
Log.d("parsed token: ", _token.type, " ", _token.line, ":", _token.pos, " ", _token.text);
|
||||||
|
}
|
||||||
|
|
||||||
protected void skipWhitespaceAndEols() {
|
protected void skipWhitespaceAndEols() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
_token = _tokenizer.nextToken();
|
nextToken();
|
||||||
if (_token.type != TokenType.eol && _token.type != TokenType.eof && _token.type != TokenType.whitespace && _token.type != TokenType.comment)
|
if (_token.type != TokenType.eol && _token.type != TokenType.whitespace && _token.type != TokenType.comment)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (_token.type == TokenType.error)
|
if (_token.type == TokenType.error)
|
||||||
_tokenizer.emitError("error while parsing ML code");
|
_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) {
|
protected void error(string msg) {
|
||||||
_tokenizer.emitError(msg);
|
_tokenizer.emitError(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget createWidget(string name) {
|
Widget createWidget(string name) {
|
||||||
WidgetFactory factory = getWidgetFactory(name);
|
auto metadata = findWidgetMetadata(name);
|
||||||
if (!factory)
|
if (!metadata)
|
||||||
error("Cannot create widget " ~ name ~ " : unknown class");
|
error("Cannot create widget " ~ name ~ " : unregistered widget class");
|
||||||
return factory();
|
return metadata.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createContext(string name) {
|
protected void createContext(string name) {
|
||||||
|
@ -419,6 +435,11 @@ class MLParser {
|
||||||
if (!_context)
|
if (!_context)
|
||||||
_tokenizer.emitError("No context widget is specified!");
|
_tokenizer.emitError("No context widget is specified!");
|
||||||
skipWhitespaceAndEols();
|
skipWhitespaceAndEols();
|
||||||
|
if (_token.type != TokenType.curlyClose) // {
|
||||||
|
_tokenizer.emitError("} is expected");
|
||||||
|
skipWhitespaceAndEols();
|
||||||
|
if (_token.type != TokenType.eof) // {
|
||||||
|
_tokenizer.emitError("end of file expected");
|
||||||
return _context;
|
return _context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,10 +448,12 @@ class MLParser {
|
||||||
_tokenizer = null;
|
_tokenizer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse DlangUI ML code
|
}
|
||||||
static Widget parse(string code, string filename = "", Widget context = null) {
|
|
||||||
|
|
||||||
|
/// Parse DlangUI ML code
|
||||||
|
public Widget parseML(string code, string filename = "", Widget context = null) {
|
||||||
MLParser parser = new MLParser(code, filename);
|
MLParser parser = new MLParser(code, filename);
|
||||||
scope(exit) destroy(parser);
|
scope(exit) destroy(parser);
|
||||||
return parser.parse();
|
return parser.parse();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1029,3 +1029,5 @@ class CanvasWidget : Widget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import dlangui.widgets.metadata;
|
||||||
|
mixin(registerWidgets!(Widget, TextWidget, Button, ImageWidget, ImageButton, ImageTextButton, RadioButton, CheckBox, ScrollBar)());
|
||||||
|
|
|
@ -840,3 +840,6 @@ class TableLayout : WidgetGroupDefaultDrawing {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import dlangui.widgets.metadata;
|
||||||
|
mixin(registerWidgets!(VerticalLayout, HorizontalLayout, TableLayout, FrameLayout)());
|
||||||
|
|
|
@ -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 ~ "}";
|
||||||
|
}
|
|
@ -1439,6 +1439,73 @@ class Widget {
|
||||||
// override
|
// 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. */
|
/** 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;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue