diff --git a/dlangui-msvc.visualdproj b/dlangui-msvc.visualdproj index 6fc6c1e8..b8eed368 100644 --- a/dlangui-msvc.visualdproj +++ b/dlangui-msvc.visualdproj @@ -8,7 +8,7 @@ 0 0 0 - 0 + 1 0 0 0 @@ -317,7 +317,7 @@ 0 0 0 - 0 + 1 0 0 0 @@ -1276,6 +1276,7 @@ + diff --git a/src/dlangui/core/types.d b/src/dlangui/core/types.d index 260f38cb..21187060 100644 --- a/src/dlangui/core/types.d +++ b/src/dlangui/core/types.d @@ -50,12 +50,18 @@ struct Point { int x; int y; - Point opBinary(string op)(Point v) if (op == "+") { + Point opBinary(string op)(Point v) const if (op == "+") { return Point(x + v.x, y + v.y); } - Point opBinary(string op)(Point v) if (op == "-") { + Point opBinary(string op)(int n) const if (op == "*") { + return Point(x * n, y * n); + } + Point opBinary(string op)(Point v) const if (op == "-") { return Point(x - v.x, y - v.y); } + Point opUnary(string op)() const if (op == "-") { + return Point(-x, -y); + } int opCmp(ref const Point b) const { if (x == b.x) return y - b.y; return x - b.x; diff --git a/src/dlangui/platforms/common/startup.d b/src/dlangui/platforms/common/startup.d index ba145a56..70190234 100644 --- a/src/dlangui/platforms/common/startup.d +++ b/src/dlangui/platforms/common/startup.d @@ -416,41 +416,7 @@ extern (C) void initResourceManagers() { Log.d("initResourceManagers() -- finished"); } -/// register standard widgets to use in DML -void registerStandardWidgets() { - Log.d("Registering standard widgets for DML"); - import dlangui.widgets.metadata; - import dlangui.widgets.widget; - import dlangui.widgets.layouts; - import dlangui.widgets.controls; - import dlangui.widgets.scrollbar; - import dlangui.widgets.lists; - import dlangui.widgets.combobox; - import dlangui.widgets.editors; - import dlangui.widgets.grid; - import dlangui.widgets.groupbox; - import dlangui.widgets.progressbar; - import dlangui.dialogs.filedlg; - import dlangui.widgets.menu; - import dlangui.widgets.tree; - import dlangui.widgets.tabs; - mixin(registerWidgets!(FileNameEditLine, DirEditLine, //dlangui.dialogs.filedlg - ComboBox, ComboEdit, //dlangui.widgets.combobox - Widget, TextWidget, MultilineTextWidget, Button, ImageWidget, ImageButton, ImageCheckButton, ImageTextButton, - SwitchButton, RadioButton, CheckBox, HSpacer, VSpacer, CanvasWidget, // dlangui.widgets.controls - ScrollBar, SliderWidget, // dlangui.widgets.scrollbar - EditLine, EditBox, LogWidget,//dlangui.widgets.editors - GroupBox, // dlangui.widgets.groupbox - ProgressBarWidget, // dlangui.widgets.progressbar - StringGridWidget, //dlangui.widgets.grid - VerticalLayout, HorizontalLayout, TableLayout, FrameLayout, // dlangui.widgets.layouts - ListWidget, StringListWidget,//dlangui.widgets.lists - MainMenu, //dlangui.widgets.menu - TreeWidget, // dlangui.widgets.tree - TabWidget, // dlangui.widgets.tabs - )("void registerWidgets")); - registerWidgets(); -} + /// call this from shared static this() extern (C) void initSharedResourceManagers() { @@ -466,6 +432,9 @@ shared static this() { //initSharedResourceManagers(); } +/// register standard widgets to use in DML +extern(C) void registerStandardWidgets(); + /// call this when all resources are supposed to be freed to report counts of non-freed resources by type extern (C) void releaseResourcesOnAppExit() { diff --git a/src/dlangui/widgets/dmlwidgets.d b/src/dlangui/widgets/dmlwidgets.d new file mode 100644 index 00000000..edff07ac --- /dev/null +++ b/src/dlangui/widgets/dmlwidgets.d @@ -0,0 +1,117 @@ +module dlangui.widgets.dmlwidgets; + +/// register standard widgets to use in DML +extern(C) void registerStandardWidgets() { + import dlangui.core.config; + import dlangui.core.logger; + + Log.d("Registering standard widgets for DML"); + + import dlangui.widgets.metadata; + import dlangui.widgets.widget; + + mixin(registerWidgetMetadataClass!Widget); + + import dlangui.widgets.layouts; + mixin(registerWidgetMetadataClass!VerticalLayout); + mixin(registerWidgetMetadataClass!HorizontalLayout); + mixin(registerWidgetMetadataClass!TableLayout); + mixin(registerWidgetMetadataClass!FrameLayout); // dlangui.widgets.layouts + + import dlangui.widgets.controls; + + mixin(registerWidgetMetadataClass!TextWidget); + mixin(registerWidgetMetadataClass!MultilineTextWidget); + mixin(registerWidgetMetadataClass!Button); + mixin(registerWidgetMetadataClass!ImageWidget); + mixin(registerWidgetMetadataClass!ImageButton); + mixin(registerWidgetMetadataClass!ImageCheckButton); + mixin(registerWidgetMetadataClass!ImageTextButton); + mixin(registerWidgetMetadataClass!SwitchButton); + mixin(registerWidgetMetadataClass!RadioButton); + mixin(registerWidgetMetadataClass!CheckBox); + mixin(registerWidgetMetadataClass!HSpacer); + mixin(registerWidgetMetadataClass!VSpacer); + mixin(registerWidgetMetadataClass!CanvasWidget); // dlangui.widgets.controls + + import dlangui.widgets.scrollbar; + + mixin(registerWidgetMetadataClass!ScrollBar); + mixin(registerWidgetMetadataClass!SliderWidget); // dlangui.widgets.scrollbar + + import dlangui.widgets.lists; + + mixin(registerWidgetMetadataClass!ListWidget); + mixin(registerWidgetMetadataClass!StringListWidget);//dlangui.widgets.lists + + + import dlangui.widgets.editors; + + mixin(registerWidgetMetadataClass!EditLine); + mixin(registerWidgetMetadataClass!EditBox); + mixin(registerWidgetMetadataClass!LogWidget);//dlangui.widgets.editors + + import dlangui.widgets.combobox; + mixin(registerWidgetMetadataClass!ComboBox); + mixin(registerWidgetMetadataClass!ComboEdit); //dlangui.widgets.combobox + + import dlangui.widgets.grid; + + mixin(registerWidgetMetadataClass!StringGridWidget); //dlangui.widgets.grid + + import dlangui.widgets.groupbox; + + mixin(registerWidgetMetadataClass!GroupBox); // dlangui.widgets.groupbox + + import dlangui.widgets.progressbar; + + mixin(registerWidgetMetadataClass!ProgressBarWidget); // dlangui.widgets.progressbar + + import dlangui.widgets.menu; + + mixin(registerWidgetMetadataClass!MainMenu); //dlangui.widgets.menu + + import dlangui.widgets.tree; + + mixin(registerWidgetMetadataClass!TreeWidget); // dlangui.widgets.tree + + import dlangui.widgets.tabs; + + mixin(registerWidgetMetadataClass!TabWidget); // dlangui.widgets.tabs + + import dlangui.dialogs.filedlg; + + mixin(registerWidgetMetadataClass!FileNameEditLine); + mixin(registerWidgetMetadataClass!DirEditLine); + + /* + mixin (registerWidgets!("void registerWidgets1", + FileNameEditLine, DirEditLine, //dlangui.dialogs.filedlg + ComboBox, ComboEdit, //dlangui.widgets.combobox + // )()); + //mixin(registerWidgets!("void registerWidgets2", + Widget, TextWidget, MultilineTextWidget, Button, ImageWidget, ImageButton, ImageCheckButton, ImageTextButton, + )); + mixin(registerWidgets!("void registerWidgets3", + SwitchButton, RadioButton, CheckBox, HSpacer, VSpacer, CanvasWidget, // dlangui.widgets.controls + ScrollBar, SliderWidget, // dlangui.widgets.scrollbar + EditLine, EditBox, LogWidget,//dlangui.widgets.editors + )); + mixin(registerWidgets!("void registerWidgets4", + GroupBox, // dlangui.widgets.groupbox + ProgressBarWidget, // dlangui.widgets.progressbar + StringGridWidget, //dlangui.widgets.grid + VerticalLayout, HorizontalLayout, TableLayout, FrameLayout, // dlangui.widgets.layouts + MainMenu, //dlangui.widgets.menu + TreeWidget, // dlangui.widgets.tree + TabWidget, // dlangui.widgets.tabs + )); + + + registerWidgets1(); + //registerWidgets2(); + registerWidgets3(); + registerWidgets4(); + */ +} + diff --git a/src/dlangui/widgets/lists.d b/src/dlangui/widgets/lists.d index e46ae548..e102a76f 100644 --- a/src/dlangui/widgets/lists.d +++ b/src/dlangui/widgets/lists.d @@ -1402,7 +1402,8 @@ class ListWidget : WidgetGroup, OnScrollHandler, OnAdapterChangeHandler { class StringListWidget : ListWidget { import std.conv : to; - import std.datetime : dto = to, StopWatch; + import std.datetime.stopwatch : StopWatch; + import core.time : dur; private dstring _searchString; private StopWatch _stopWatch; @@ -1479,9 +1480,10 @@ class StringListWidget : ListWidget { if (event.action == KeyAction.Text) { if ( !_stopWatch.running) { _stopWatch.start; } - auto timePassed = _stopWatch.peek.dto!("seconds", float)(); // dtop is std.datetime.to + auto timePassed = _stopWatch.peek; //.to!("seconds", float)(); // dtop is std.datetime.to - if (timePassed > 0.5) _searchString = ""d; + if (timePassed > dur!"msecs"(500)) + _searchString = ""d; _searchString ~= to!dchar(event.text.toUTF8); _stopWatch.reset; diff --git a/src/dlangui/widgets/metadata.d b/src/dlangui/widgets/metadata.d index 86c630e8..793bd49e 100644 --- a/src/dlangui/widgets/metadata.d +++ b/src/dlangui/widgets/metadata.d @@ -83,53 +83,136 @@ template isMarkupType(T) is(T==StringListValue[]); } -string generatePropertiesMetadata(alias T)() { - version (GENERATE_PROPERTY_METADATA) { - import std.algorithm.searching; +private bool hasPropertyAnnotation(alias ti)() { + bool res = false; + foreach ( attr; __traits(getFunctionAttributes, ti)) { + static if (attr == "@property") { + res = true; + } + } + return res; +} +/* +string markupPropertyGetterType(alias overload)() { + static if (__traits(getProtection, overload) == "public") { import std.traits; - import std.meta; - char[] str; - str ~= "["; - foreach(m; __traits(allMembers, T)) { - static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){ - // skip non-public members, only functions that takes 0 or 1 arguments, add only types that parseable in markup - static if (__traits(getProtection, __traits(getMember, T, m)) == "public") { - static if (isFunction!(__traits(getMember, T, m))) { - immutable int fnArity = arity!(__traits(getMember, T, m)); - static if (fnArity == 0 || fnArity == 1) { - // TODO: filter out templates, signals and such - // iterates class members and process @property functions (note: foreach {if}) - foreach ( attr; __traits(getFunctionAttributes, __traits(getMember, T, m))) if (attr == "@property") { - alias ret = ReturnType!(__traits(getMember, T, m)); - alias params = Parameters!(__traits(getMember, T, m)); - string typestring; - static if (fnArity == 0 && !__traits(isTemplate,ret) && isMarkupType!ret) - typestring = ret.stringof; - else static if (fnArity == 1 && !__traits(isTemplate,params[0]) && isMarkupType!(params[0])) - typestring = params[0].stringof; - if (typestring is null) - continue; - str ~= "WidgetPropertyMetadata( typeid(" ~ typestring ~ "), " ~ m.stringof ~ " ), "; - } + static if (is(typeof(overload) == function) && hasPropertyAnnotation!overload) { + alias ret = ReturnType!overload; + //alias params = Parameters!overload; + alias params = ParameterTypeTuple!overload; + static if (params.length == 0 && isMarkupType!ret && !isTemplate!ret) { + return ret.stringof; + } else { + return null; + } + } else { + return null; + } + } +} + +string markupPropertySetterType(alias overload)() { + static if (__traits(getProtection, overload) == "public") { + import std.traits; + static if (is(typeof(overload) == function) && hasPropertyAnnotation!overload) { + //alias params = Parameters!overload; + alias params = ParameterTypeTuple!overload; + static if (params.length == 1 && isMarkupType!(params[0]) && !isTemplate!(params[0])) { + return params[0].stringof; + } else { + return null; + } + } else { + return null; + } + } +} +*/ + +private template isPublicPropertyFunction(alias overload) { + static if (__traits(getProtection, overload) == "public") { + static if (hasPropertyAnnotation!overload) { + enum isPublicPropertyFunction = true; + } else { + enum isPublicPropertyFunction = false; + } + } else { + enum isPublicPropertyFunction = false; + } + //pragma(msg, is(typeof(overload) == function).stringof); + //enum isPublicPropertyFunction = (__traits(getProtection, overload) == "public") && is(typeof(overload) == function);// && hasPropertyAnnotation!overload; +} + +private template markupPropertyType(alias overload) { + import std.traits : ReturnType, ParameterTypeTuple; + alias ret = ReturnType!overload; + alias params = ParameterTypeTuple!overload; + static if (params.length == 0 && isMarkupType!ret /* && !isTemplate!ret*/) { + enum string markupPropertyType = ret.stringof; + } else static if (params.length == 1 && isMarkupType!(params[0]) /* && !isTemplate!(params[0])*/) { + enum string markupPropertyType = params[0].stringof; + } else { + enum string markupPropertyType = null; + } +} + +private string[] generatePropertyTypeList(alias T)() { + import std.meta; + string[] properties; + properties ~= "["; + foreach(m; __traits(allMembers, T)) { + static if (__traits(compiles, (typeof(__traits(getMember, T, m))))){ + //static if (is (typeof(__traits(getMember, T, m)) == function)) { + static if (__traits(isVirtualFunction, __traits(getMember, T, m))) {// + import std.traits : MemberFunctionsTuple; + alias overloads = typeof(__traits(getVirtualFunctions, T, m)); + static if (overloads.length == 2) { + static if (isPublicPropertyFunction!(__traits(getVirtualFunctions, T, m)[0]) && isPublicPropertyFunction!(__traits(getVirtualFunctions, T, m)[1])) { + //pragma(msg, m ~ " isPublicPropertyFunction0=" ~ isPublicPropertyFunction!(__traits(getVirtualFunctions, T, m)[0]).stringof); + //pragma(msg, m ~ " isPublicPropertyFunction1=" ~ isPublicPropertyFunction!(__traits(getVirtualFunctions, T, m)[1]).stringof); + immutable getterType = markupPropertyType!(__traits(getVirtualFunctions, T, m)[0]); + immutable setterType = markupPropertyType!(__traits(getVirtualFunctions, T, m)[1]); + static if (getterType && setterType && getterType == setterType) { + //pragma(msg, "markup property found: " ~ getterType ~ " " ~ m.stringof); + properties ~= "WidgetPropertyMetadata( typeid(" ~ getterType ~ "), " ~ m.stringof ~ " ), "; } } } } } - str ~= "]"; - return cast(string)str; + } + properties ~= "]"; + return properties; +} + +string joinStrings(string[] lines) { + if (lines.length == 0) + return ""; + if (lines.length == 1) + return lines[0]; + else + return joinStrings(lines[0 .. $/2]) ~ joinStrings(lines[$/2 .. $]); +} + +private string generatePropertiesMetadata(alias T)() if (is(T : Widget)) { + version (GENERATE_PROPERTY_METADATA) { + //import std.algorithm.searching; + //import std.traits : MemberFunctionsTuple; + //import std.meta; + auto properties = generatePropertyTypeList!T; + return joinStrings(properties); } else { return "[]"; } } -string generateMetadataClass(alias t)() { +string generateMetadataClass(alias t)() if (is(t : Widget)) { //pragma(msg, moduleName!t); import std.traits; //pragma(msg, getSignalList!t); //pragma(msg, generatePropertiesMetadata!t); immutable string metadataClassName = t.stringof ~ "Metadata"; - return "class " ~ metadataClassName ~ " : WidgetMetadataDef { \n" ~ + return "static class " ~ metadataClassName ~ " : WidgetMetadataDef { \n" ~ " override Widget create() {\n" ~ " return new " ~ moduleName!t ~ "." ~ t.stringof ~ "();\n" ~ " }\n" ~ @@ -142,33 +225,73 @@ string generateMetadataClass(alias t)() { " override string fullName() {\n" ~ " return \"" ~ moduleName!t ~ "." ~ t.stringof ~ "\";\n" ~ " }\n" ~ - " override WidgetPropertyMetadata[] properties() {" ~ + " override WidgetPropertyMetadata[] properties() {\n" ~ " return " ~ generatePropertiesMetadata!t ~ ";\n" ~ " }\n" ~ "}\n"; } -string generateRegisterMetadataClass(alias t)() { +string generateRegisterMetadataClass(alias t)() if (is(t : Widget)) { immutable string metadataClassName = t.stringof ~ "Metadata"; - return "registerWidgetMetadata(\"" ~ t.stringof ~ "\", new " ~ metadataClassName ~ "());\n"; + //pragma(msg, metadataClassName); + return "registerWidgetMetadata(\"" ~ t.stringof ~ "\", new " ~ t.stringof ~ "Metadata" ~ "());\n"; } -string registerWidgets(T...)(string registerFunctionName = "__gshared static this") { - string classDefs; - string registerDefs; +template registerWidgetMetadataClass(alias t) if (is(t : Widget)) { + //pragma(msg, t.stringof); + //pragma(msg, generateMetadataClass!t); + immutable string classDef = generateMetadataClass!t; + immutable string registerDef = "registerWidgetMetadata(\"" ~ t.stringof ~ "\", new " ~ t.stringof ~ "Metadata" ~ "());\n"; + enum registerWidgetMetadataClass = classDef ~ registerDef; + //mixin(classDef); + + //pragma(msg, "registerWidgetMetadata(\"" ~ t.stringof ~ "\", new " ~ t.stringof ~ "Metadata" ~ "());\n"); + //mixin("registerWidgetMetadata(\"" ~ t.stringof ~ "\", new " ~ t.stringof ~ "Metadata" ~ "());\n"); +} + +string registerWidgetsFunction(string registerFunctionName = "__gshared static this", T...)() { + pragma(msg, registerFunctionName); + pragma(msg, T); + string[] registerDefs; foreach(t; T) { - //pragma(msg, t.stringof); + 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; + static if (is(t : Widget)) { + //pragma(msg, classdef); + immutable string registerdef = generateRegisterMetadataClass!t; + pragma(msg, registerdef); + registerDefs ~= registerdef; + } else { + pragma(msg, "Skipping non-widget class: " ~ t.stringof); + } //registerWidgetMetadata(T.stringof, new Metadata()); } - return classDefs ~ "\n" ~ registerFunctionName ~ "() {\n" ~ registerDefs ~ "}"; + return registerFunctionName ~ "() {\n" ~ joinStrings(registerDefs) ~ "}\n"; +} + +string registerWidgets(string registerFunctionName = "__gshared static this", T...)() { + pragma(msg, registerFunctionName); + pragma(msg, T); + string[] classDefs; + string[] registerDefs; + foreach(t; T) { + pragma(msg, t.stringof); + //pragma(msg, moduleName!t); + // + static if (is(t : Widget)) { + immutable string classdef = generateMetadataClass!t; + //pragma(msg, classdef); + immutable string registerdef = generateRegisterMetadataClass!t; + pragma(msg, registerdef); + classDefs ~= classdef; + registerDefs ~= registerdef; + } else { + pragma(msg, "Skipping non-widget class: " ~ t.stringof); + } + //registerWidgetMetadata(T.stringof, new Metadata()); + } + return joinStrings(classDefs) ~ "\n" ~ registerFunctionName ~ "() {\n" ~ joinStrings(registerDefs) ~ "}\n"; } /// returns true if passed name is identifier of registered widget class diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d index e769f82a..3ac0e600 100644 --- a/src/dlangui/widgets/widget.d +++ b/src/dlangui/widgets/widget.d @@ -637,6 +637,13 @@ public: /// sets layout weight (while resizing to fill parent, widget will be resized proportionally to this value) @property Widget layoutWeight(int value) { ownStyle.layoutWeight = value; return this; } + /// sets layoutWidth=FILL_PARENT and layoutHeight=FILL_PARENT + Widget fillParent() { return layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); } + /// sets layoutWidth=FILL_PARENT + Widget fillHorizontal() { return layoutWidth(FILL_PARENT); } + /// sets layoutHeight=FILL_PARENT + Widget fillVertical() { return layoutHeight(FILL_PARENT); } + /// returns widget visibility (Visible, Invisible, Gone) @property Visibility visibility() { return _visibility; } /// sets widget visibility (Visible, Invisible, Gone)