diff --git a/examples/dmledit/src/dmledit.d b/examples/dmledit/src/dmledit.d index bb52f93e..7165385b 100644 --- a/examples/dmledit/src/dmledit.d +++ b/examples/dmledit/src/dmledit.d @@ -1,6 +1,8 @@ module dmledit; import dlangui; +import dlangui.dialogs.filedlg; +import dlangui.dialogs.dialog; mixin APP_ENTRY_POINT; @@ -15,6 +17,8 @@ enum IDEActions : int { FileClose, FileExit, EditPreferences, + DebugStart, + HelpAbout, } // actions @@ -33,6 +37,8 @@ const Action ACTION_EDIT_UNINDENT = (new Action(EditorActions.Unindent, "MENU_ED const Action ACTION_EDIT_TOGGLE_LINE_COMMENT = (new Action(EditorActions.ToggleLineComment, "MENU_EDIT_TOGGLE_LINE_COMMENT"c, null, KeyCode.KEY_DIVIDE, KeyFlag.Control)).disableByDefault(); const Action ACTION_EDIT_TOGGLE_BLOCK_COMMENT = (new Action(EditorActions.ToggleBlockComment, "MENU_EDIT_TOGGLE_BLOCK_COMMENT"c, null, KeyCode.KEY_DIVIDE, KeyFlag.Control|KeyFlag.Shift)).disableByDefault(); const Action ACTION_EDIT_PREFERENCES = (new Action(IDEActions.EditPreferences, "MENU_EDIT_PREFERENCES"c, null)).disableByDefault(); +const Action ACTION_DEBUG_START = new Action(IDEActions.DebugStart, "MENU_DEBUG_START_DEBUGGING"c, "debug-run"c, KeyCode.F5, 0); +const Action ACTION_HELP_ABOUT = new Action(IDEActions.HelpAbout, "MENU_HELP_ABOUT"c); class EditFrame : AppFrame { @@ -44,19 +50,18 @@ class EditFrame : AppFrame { } /// create main menu override protected MainMenu createMainMenu() { - return new MainMenu(new MenuItem()); mainMenuItems = new MenuItem(); MenuItem fileItem = new MenuItem(new Action(1, "MENU_FILE")); fileItem.add(ACTION_FILE_NEW, ACTION_FILE_OPEN, ACTION_FILE_EXIT); - + mainMenuItems.add(fileItem); MenuItem editItem = new MenuItem(new Action(2, "MENU_EDIT")); editItem.add(ACTION_EDIT_COPY, ACTION_EDIT_PASTE, ACTION_EDIT_CUT, ACTION_EDIT_UNDO, ACTION_EDIT_REDO, ACTION_EDIT_INDENT, ACTION_EDIT_UNINDENT, ACTION_EDIT_TOGGLE_LINE_COMMENT, ACTION_EDIT_TOGGLE_BLOCK_COMMENT); editItem.add(ACTION_EDIT_PREFERENCES); - + mainMenuItems.add(editItem); MainMenu mainMenu = new MainMenu(mainMenuItems); return mainMenu; } @@ -67,7 +72,7 @@ class EditFrame : AppFrame { ToolBarHost res = new ToolBarHost(); ToolBar tb; tb = res.getOrAddToolbar("Standard"); - tb.addButtons(ACTION_FILE_NEW, ACTION_FILE_OPEN, ACTION_FILE_SAVE); + tb.addButtons(ACTION_FILE_NEW, ACTION_FILE_OPEN, ACTION_FILE_SAVE, ACTION_SEPARATOR, ACTION_DEBUG_START); tb = res.getOrAddToolbar("Edit"); tb.addButtons(ACTION_EDIT_COPY, ACTION_EDIT_PASTE, ACTION_EDIT_CUT, ACTION_SEPARATOR, @@ -75,20 +80,117 @@ class EditFrame : AppFrame { return res; } + string _filename; + void openSourceFile(string filename) { + // TODO + _filename = filename; + } + + bool onCanClose() { + // todo + return true; + } + + FileDialog createFileDialog(UIString caption) { + FileDialog dlg = new FileDialog(caption, window, null); + dlg.filetypeIcons[".d"] = "text-dml"; + return dlg; + } + + /// override to handle specific actions + override bool handleAction(const Action a) { + if (a) { + switch (a.id) { + case IDEActions.FileExit: + if (onCanClose()) + window.close(); + return true; + case IDEActions.HelpAbout: + window.showMessageBox(UIString("About DlangUI ML Editor"d), + UIString("DLangIDE\n(C) Vadim Lopatin, 2015\nhttp://github.com/buggins/dlangui\nSimple editor for DML code"d)); + return true; + case IDEActions.FileOpen: + UIString caption; + caption = "Open DML File"d; + FileDialog dlg = createFileDialog(caption); + dlg.addFilter(FileFilterEntry(UIString("DML files"d), "*.dml")); + dlg.addFilter(FileFilterEntry(UIString("All files"d), "*.*")); + dlg.onDialogResult = delegate(Dialog dlg, const Action result) { + if (result.id == ACTION_OPEN.id) { + string filename = result.stringParam; + openSourceFile(filename); + } + }; + dlg.show(); + return true; + case IDEActions.DebugStart: + updatePreview(); + return true; + case IDEActions.EditPreferences: + //showPreferences(); + return true; + default: + return super.handleAction(a); + } + } + return false; + } + + void updatePreview() { + dstring dsource = _editor.text; + string source = toUTF8(dsource); + try { + Widget w = parseML(source); + statusLine.setStatusText("No errors"d); + _preview.contentWidget = w; + } catch (ParserException e) { + statusLine.setStatusText(toUTF32("ERROR: " ~ e.msg)); + _editor.setCaretPos(e.line, e.pos); + } + } + + protected SourceEdit _editor; + protected ScrollWidget _preview; /// create app body widget override protected Widget createBody() { VerticalLayout bodyWidget = new VerticalLayout(); bodyWidget.layoutWidth = FILL_PARENT; bodyWidget.layoutHeight = FILL_PARENT; HorizontalLayout hlayout = new HorizontalLayout(); - hlayout.layoutWidth = makePercentSize(50); + hlayout.layoutWidth = FILL_PARENT; hlayout.layoutHeight = FILL_PARENT; - SourceEdit editor = new SourceEdit(); - hlayout.addChild(editor); - ScrollWidget preview = new ScrollWidget(); - preview.layoutWidth = FILL_PARENT; - preview.layoutHeight = FILL_PARENT; - hlayout.addChild(preview); + _editor = new SourceEdit(); + hlayout.addChild(_editor); + _editor.text = q{ +VerticalLayout { + id: vlayout + margins: Rect { left: 5; right: 3; top: 2; bottom: 4 } + padding: Rect { 5, 4, 3, 2 } // same as Rect { left: 5; top: 4; right: 3; bottom: 2 } + TextWidget { + /* this widget can be accessed via id myLabel1 + e.g. w.childById!TextWidget("myLabel1") + */ + id: myLabel1 + text: "Some text"; padding: 5 + enabled: false + } + TextWidget { + id: myLabel2 + text: "More text"; margins: 5 + enabled: true + } + CheckBox{ id: cb1; text: "Some checkbox" } + HorizontalLayout { + RadioButton{ id: rb1; text: "Radio Button 1" } + RadioButton{ id: rb1; text: "Radio Button 2" } + } +} + }; + _preview = new ScrollWidget(); + _preview.layoutWidth = makePercentSize(50); + _preview.layoutHeight = FILL_PARENT; + _preview.backgroundImageId = "tx_fabric.tiled"; + hlayout.addChild(_preview); bodyWidget.addChild(hlayout); return bodyWidget; } diff --git a/examples/dmledit/views/res/i18n/en.ini b/examples/dmledit/views/res/i18n/en.ini index f71127d3..55e3afdc 100644 --- a/examples/dmledit/views/res/i18n/en.ini +++ b/examples/dmledit/views/res/i18n/en.ini @@ -1,5 +1,6 @@ EXIT=Exit MENU_FILE=&File +MENU_FILE_NEW=&New MENU_FILE_OPEN=&Open MENU_FILE_OPEN_RECENT=Open recent MENU_FILE_SAVE=&Save @@ -12,6 +13,8 @@ MENU_EDIT_UNDO=&Undo MENU_EDIT_REDO=&Redo MENU_EDIT_INDENT=Indent block MENU_EDIT_UNINDENT=Unindent block +MENU_EDIT_TOGGLE_LINE_COMMENT=Toggle line comment +MENU_EDIT_TOGGLE_BLOCK_COMMENT=Toggle block comment MENU_EDIT_PREFERENCES=&Preferences MENU_VIEW=&View MENU_VIEW_LANGUAGE=Interface &Language diff --git a/examples/dmledit/views/res/mdpi/debug-run.png b/examples/dmledit/views/res/mdpi/debug-run.png new file mode 100644 index 00000000..eee3e905 Binary files /dev/null and b/examples/dmledit/views/res/mdpi/debug-run.png differ diff --git a/examples/dmledit/views/res/mdpi/text-dml.png b/examples/dmledit/views/res/mdpi/text-dml.png new file mode 100644 index 00000000..7a97a453 Binary files /dev/null and b/examples/dmledit/views/res/mdpi/text-dml.png differ diff --git a/examples/dmledit/views/res/mdpi/tx_fabric.jpg b/examples/dmledit/views/res/mdpi/tx_fabric.jpg new file mode 100644 index 00000000..6c33894a Binary files /dev/null and b/examples/dmledit/views/res/mdpi/tx_fabric.jpg differ diff --git a/examples/dmledit/views/resources.list b/examples/dmledit/views/resources.list index d7e0641a..d8a1b540 100644 --- a/examples/dmledit/views/resources.list +++ b/examples/dmledit/views/resources.list @@ -1,6 +1,7 @@ res/i18n/en.ini res/i18n/ru.ini res/mdpi/cr3_logo.png +res/mdpi/debug-run.png res/mdpi/document-close.png res/mdpi/document-new.png res/mdpi/document-open-recent.png @@ -15,3 +16,5 @@ res/mdpi/edit-paste.png res/mdpi/edit-redo.png res/mdpi/edit-undo.png res/mdpi/edit-unindent.png +res/mdpi/text-dml.png +res/mdpi/tx_fabric.jpg diff --git a/src/dlangui/core/parser.d b/src/dlangui/core/parser.d index 3a81982b..5765ffa0 100644 --- a/src/dlangui/core/parser.d +++ b/src/dlangui/core/parser.d @@ -584,19 +584,21 @@ class MLParser { } protected void setStringProperty(string propName, string value) { - if (propName.equal("id")) { + if (propName.equal("id") || propName.equal("styleId") || propName.equal("backgroundImageId")) { if (!_currentWidget.setStringProperty(propName, value)) - error("cannot set id property for widget"); + error("cannot set " ~ propName ~ " property for widget"); return; } dstring v = toUTF32(value); - if (!_currentWidget.setDstringProperty(propName, v)) - error("unknown string property " ~ propName); + if (!_currentWidget.setDstringProperty(propName, v)) { + if (!_currentWidget.setStringProperty(propName, value)) + error("unknown string property " ~ propName); + } } protected void setIdentProperty(string propName, string value) { - if (propName.equal("id")) { + if (propName.equal("id") || propName.equal("styleId") || propName.equal("backgroundImageId")) { if (!_currentWidget.setStringProperty(propName, value)) error("cannot set id property for widget"); return; diff --git a/src/dlangui/widgets/editors.d b/src/dlangui/widgets/editors.d index 025aa163..c1527894 100644 --- a/src/dlangui/widgets/editors.d +++ b/src/dlangui/widgets/editors.d @@ -1475,7 +1475,20 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction return super.onMouseEvent(event); } + /// returns caret position + @property TextPosition caretPos() { + return _caretPos; + } + /// change caret position and ensure it is visible + void setCaretPos(int line, int column, bool makeVisible = true) + { + _caretPos = TextPosition(line,column); + correctCaretPos(); + invalidate(); + if (makeVisible) + ensureCaretVisible(); + } } interface EditorActionHandler { diff --git a/src/dlangui/widgets/widget.d b/src/dlangui/widgets/widget.d index f2dab4cd..d508a76b 100644 --- a/src/dlangui/widgets/widget.d +++ b/src/dlangui/widgets/widget.d @@ -1228,7 +1228,7 @@ class Widget { else if (!isSpecialSize(lh)) dy = lh; if (isPercentSize(lw) && parentWidth != SIZE_UNSPECIFIED) - dy = fromPercentSize(lw, parentWidth); + dx = fromPercentSize(lw, parentWidth); else if (!isSpecialSize(lw)) dx = lw; // apply min/max width and height constraints @@ -1479,7 +1479,7 @@ class Widget { /// set string property value, for ML loaders bool setStringProperty(string name, string value) { - mixin(generatePropertySetters("id")); + mixin(generatePropertySetters("id", "styleId", "backgroundImageId")); if (name.equal("text")) { text = UIString(value); return true;