1 // Written in the D programming language.
2 
3 /**
4 This app is a demo for most of DlangUI library features.
5 
6 Synopsis:
7 
8 ----
9     dub run dlangui:example1
10 ----
11 
12 Copyright: Vadim Lopatin, 2014
13 License:   Boost License 1.0
14 Authors:   Vadim Lopatin, coolreader.org@gmail.com
15  */
16 module main;
17 
18 import dlangui;
19 import dlangui.dialogs.dialog;
20 import dlangui.dialogs.filedlg;
21 import dlangui.dialogs.msgbox;
22 import std.stdio;
23 import std.conv;
24 import std.utf;
25 import std.algorithm;
26 import std.path;
27 
28 
29 mixin APP_ENTRY_POINT;
30 
31 class TimerTest : HorizontalLayout {
32     ulong timerId;
33     TextWidget _counter;
34     int _value;
35     Button _start;
36     Button _stop;
37     override bool onTimer(ulong id) {
38         _value++;
39         _counter.text = to!dstring(_value);
40         return true;
41     }
42     this() {
43         addChild(new TextWidget(null, "Timer test."d));
44         _counter = new TextWidget(null, "0"d);
45         _counter.fontSize(32);
46         _start = new Button(null, "Start timer"d);
47         _stop = new Button(null, "Stop timer"d);
48         _stop.enabled = false;
49         _start.click = delegate(Widget src) {
50             _start.enabled = false;
51             _stop.enabled = true;
52             timerId = setTimer(1000);
53             return true;
54         };
55         _stop.click = delegate(Widget src) {
56             _start.enabled = true;
57             _stop.enabled = false;
58             cancelTimer(timerId);
59             return true;
60         };
61         addChild(_start);
62         addChild(_stop);
63         addChild(_counter);
64     }
65 }
66 
67 static if (BACKEND_GUI) {
68     class AnimatedDrawable : Drawable {
69         DrawableRef background;
70         this() {
71             background = drawableCache.get("tx_fabric.tiled");
72         }
73         void drawAnimatedRect(DrawBuf buf, uint p, Rect rc, int speedx, int speedy, int sz) {
74             int x = (p * speedx % rc.width);
75             int y = (p * speedy % rc.height);
76             if (x < 0)
77                 x += rc.width;
78             if (y < 0)
79                 y += rc.height;
80             uint a = 64 + ((p / 2) & 0x7F);
81             uint r = 128 + ((p / 7) & 0x7F);
82             uint g = 128 + ((p / 5) & 0x7F);
83             uint b = 128 + ((p / 3) & 0x7F);
84             uint color = (a << 24) | (r << 16) | (g << 8) | b;
85             buf.fillRect(Rect(rc.left + x, rc.top + y, rc.left + x + sz, rc.top + y + sz), color);
86         }
87         void drawAnimatedIcon(DrawBuf buf, uint p, Rect rc, int speedx, int speedy, string resourceId) {
88             int x = (p * speedx % rc.width);
89             int y = (p * speedy % rc.height);
90             if (x < 0)
91                 x += rc.width;
92             if (y < 0)
93                 y += rc.height;
94             DrawBufRef image = drawableCache.getImage(resourceId);
95             buf.drawImage(x, y, image.get);
96         }
97         override void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0) {
98             background.drawTo(buf, rc, state, cast(int)(animationProgress / 695430), cast(int)(animationProgress / 1500000));
99             drawAnimatedRect(buf, cast(uint)(animationProgress / 295430), rc, 2, 3, 100);
100             drawAnimatedRect(buf, cast(uint)(animationProgress / 312400) + 100, rc, 3, 2, 130);
101             drawAnimatedIcon(buf, cast(uint)(animationProgress / 212400) + 200, rc, -2, 1, "dlangui-logo1");
102             drawAnimatedRect(buf, cast(uint)(animationProgress / 512400) + 300, rc, 2, -2, 200);
103             drawAnimatedRect(buf, cast(uint)(animationProgress / 214230) + 800, rc, 1, 2, 390);
104             drawAnimatedIcon(buf, cast(uint)(animationProgress / 123320) + 900, rc, 1, 2, "cr3_logo");
105             drawAnimatedRect(buf, cast(uint)(animationProgress / 100000) + 100, rc, -1, -1, 120);
106         }
107         @property override int width() {
108             return 1;
109         }
110         @property override int height() {
111             return 1;
112         }
113         ulong animationProgress;
114         void animate(long interval) {
115             animationProgress += interval;
116         }
117 
118     }
119 }
120 
121 class TextEditorWidget : VerticalLayout {
122     EditBox _edit;
123     this(string ID) {
124         super(ID);
125         _edit = new EditBox("editor");
126         _edit.layoutWidth = FILL_PARENT;
127         _edit.layoutHeight = FILL_PARENT;
128         addChild(_edit);
129     }
130 }
131 
132 static if (BACKEND_GUI) {
133     class SampleAnimationWidget : VerticalLayout {
134         AnimatedDrawable drawable;
135         DrawableRef drawableRef;
136         this(string ID) {
137             super(ID);
138             drawable = new AnimatedDrawable();
139             drawableRef = drawable;
140             padding = Rect(20, 20, 20, 20);
141             addChild(new TextWidget(null, "This is TextWidget on top of animated background"d));
142             addChild(new EditLine(null, "This is EditLine on top of animated background"d));
143             addChild(new Button(null, "This is Button on top of animated background"d));
144             addChild(new VSpacer());
145         }
146 
147         /// background drawable
148         @property override DrawableRef backgroundDrawable() const {
149             return (cast(SampleAnimationWidget)this).drawableRef;
150         }
151 
152         /// returns true is widget is being animated - need to call animate() and redraw
153         @property override bool animating() { return true; }
154         /// animates window; interval is time left from previous draw, in hnsecs (1/10000000 of second)
155         override void animate(long interval) {
156             drawable.animate(interval);
157             invalidate();
158         }
159     }
160 }
161 
162 Widget createEditorSettingsControl(EditWidgetBase editor) {
163     HorizontalLayout res = new HorizontalLayout("editor_options");
164     res.addChild((new CheckBox("wantTabs", "wantTabs"d)).checked(editor.wantTabs).addOnCheckChangeListener(delegate(Widget, bool checked) { editor.wantTabs = checked; return true;}));
165     res.addChild((new CheckBox("useSpacesForTabs", "useSpacesForTabs"d)).checked(editor.useSpacesForTabs).addOnCheckChangeListener(delegate(Widget, bool checked) { editor.useSpacesForTabs = checked; return true;}));
166     res.addChild((new CheckBox("readOnly", "readOnly"d)).checked(editor.readOnly).addOnCheckChangeListener(delegate(Widget, bool checked) { editor.readOnly = checked; return true;}));
167     res.addChild((new CheckBox("showLineNumbers", "showLineNumbers"d)).checked(editor.showLineNumbers).addOnCheckChangeListener(delegate(Widget, bool checked) { editor.showLineNumbers = checked; return true;}));
168     res.addChild((new CheckBox("fixedFont", "fixedFont"d)).checked(editor.fontFamily == FontFamily.MonoSpace).addOnCheckChangeListener(delegate(Widget, bool checked) {
169         if (checked)
170             editor.fontFamily(FontFamily.MonoSpace).fontFace("Courier New");
171         else
172             editor.fontFamily(FontFamily.SansSerif).fontFace("Arial");
173         return true;
174     }));
175     res.addChild((new CheckBox("tabSize", "Tab size 8"d)).checked(editor.tabSize == 8).addOnCheckChangeListener(delegate(Widget, bool checked) {
176         if (checked)
177             editor.tabSize(8);
178         else
179             editor.tabSize(4);
180         return true;
181     }));
182     return res;
183 }
184 
185 enum : int {
186     ACTION_FILE_OPEN = 5500,
187     ACTION_FILE_SAVE,
188     ACTION_FILE_CLOSE,
189     ACTION_FILE_EXIT,
190 }
191 
192 debug(SDLSettings) {
193     import dlangui.core.settings;
194     void testSDL(string fn) {
195         Log.d("Loading SDL from ", fn);
196         Setting s = new Setting();
197         if (s.load(fn)) {
198             Log.d("JSON:\n", s.toJSON(true));
199         } else {
200             Log.e("failed to read SDL from ", fn);
201         }
202     }
203     void testSDLSettings() {
204         testSDL(`C:\Users\vlopatin\AppData\Roaming\.dlangide\settings.json`);
205         testSDL("dub.json");
206         testSDL("test1.sdl");
207     }
208 }
209 
210 /// entry point for dlangui based application
211 extern (C) int UIAppMain(string[] args) {
212 
213     debug(SDLSettings) {
214         testSDLSettings();
215     }
216 
217     // always use trace, even for release builds
218     //Log.setLogLevel(LogLevel.Trace);
219     //Log.setFileLogger(new std.stdio.File("ui.log", "w"));
220 
221     // resource directory search paths
222     // not required if only embedded resources are used
223     //string[] resourceDirs = [
224     //    appendPath(exePath, "../../../res/"),   // for Visual D and DUB builds
225     //    appendPath(exePath, "../../../res/mdpi/"),   // for Visual D and DUB builds
226     //    appendPath(exePath, "../../../../res/"),// for Mono-D builds
227     //    appendPath(exePath, "../../../../res/mdpi/"),// for Mono-D builds
228     //    appendPath(exePath, "res/"), // when res dir is located at the same directory as executable
229     //    appendPath(exePath, "../res/"), // when res dir is located at project directory
230     //    appendPath(exePath, "../../res/"), // when res dir is located at the same directory as executable
231     //    appendPath(exePath, "res/mdpi/"), // when res dir is located at the same directory as executable
232     //    appendPath(exePath, "../res/mdpi/"), // when res dir is located at project directory
233     //    appendPath(exePath, "../../res/mdpi/") // when res dir is located at the same directory as executable
234     //];
235     // setup resource directories - will use only existing directories
236     //Platform.instance.resourceDirs = resourceDirs;
237 
238     // embed resources listed in views/resources.list into executable
239     embeddedResourceList.addResources(embedResourcesFromList!("resources.list")());
240 
241     //version (USE_OPENGL) {
242     //    // you can turn on subpixel font rendering (ClearType) here
243         //FontManager.subpixelRenderingMode = SubpixelRenderingMode.None; //
244     //} else {
245         // you can turn on subpixel font rendering (ClearType) here
246         FontManager.subpixelRenderingMode = SubpixelRenderingMode.BGR; //SubpixelRenderingMode.None; //
247     //}
248 
249     // select translation file - for english language
250     Platform.instance.uiLanguage = "en";
251     // load theme from file "theme_default.xml"
252     Platform.instance.uiTheme = "theme_default";
253     //Platform.instance.uiTheme = "theme_dark";
254 
255     // you can override default hinting mode here (Normal, AutoHint, Disabled)
256     FontManager.hintingMode = HintingMode.Normal;
257     // you can override antialiasing setting here (0 means antialiasing always on, some big value = always off)
258     // fonts with size less than specified value will not be antialiased
259     FontManager.minAnitialiasedFontSize = 0; // 0 means always antialiased
260     //version (USE_OPENGL) {
261     //    // you can turn on subpixel font rendering (ClearType) here
262         FontManager.subpixelRenderingMode = SubpixelRenderingMode.None; //
263     //} else {
264         // you can turn on subpixel font rendering (ClearType) here
265     //FontManager.subpixelRenderingMode = SubpixelRenderingMode.BGR; //SubpixelRenderingMode.None; //
266     //}
267 
268     // create window
269     Window window = Platform.instance.createWindow("DlangUI Example 1", null, WindowFlag.Resizable, 800, 700);
270     // here you can see window or content resize mode
271     //Window window = Platform.instance.createWindow("DlangUI Example 1", null, WindowFlag.Resizable, 400, 400);
272     //window.windowOrContentResizeMode = WindowOrContentResizeMode.resizeWindow;
273     //window.windowOrContentResizeMode = WindowOrContentResizeMode.scrollWindow;
274     //window.windowOrContentResizeMode = WindowOrContentResizeMode.shrinkWidgets;
275     static if (true) {
276         VerticalLayout contentLayout = new VerticalLayout();
277 
278         TabWidget tabs = new TabWidget("TABS");
279         tabs.tabClose = delegate(string tabId) {
280             tabs.removeTab(tabId);
281         };
282 
283         //=========================================================================
284         // create main menu
285 
286         MenuItem mainMenuItems = new MenuItem();
287         MenuItem fileItem = new MenuItem(new Action(1, "MENU_FILE"c));
288         fileItem.add(new Action(ACTION_FILE_OPEN, "MENU_FILE_OPEN"c, "document-open", KeyCode.KEY_O, KeyFlag.Control));
289         fileItem.add(new Action(ACTION_FILE_SAVE, "MENU_FILE_SAVE"c, "document-save", KeyCode.KEY_S, KeyFlag.Control));
290         MenuItem openRecentItem = new MenuItem(new Action(13, "MENU_FILE_OPEN_RECENT", "document-open-recent"));
291         openRecentItem.add(new Action(100, "&1: File 1"d));
292         openRecentItem.add(new Action(101, "&2: File 2"d));
293         openRecentItem.add(new Action(102, "&3: File 3"d));
294         openRecentItem.add(new Action(103, "&4: File 4"d));
295         openRecentItem.add(new Action(104, "&5: File 5"d));
296         fileItem.add(openRecentItem);
297         fileItem.add(new Action(ACTION_FILE_EXIT, "MENU_FILE_EXIT"c, "document-close"c, KeyCode.KEY_X, KeyFlag.Alt));
298 
299         MenuItem editItem = new MenuItem(new Action(2, "MENU_EDIT"));
300         editItem.add(new Action(EditorActions.Copy, "MENU_EDIT_COPY"c, "edit-copy", KeyCode.KEY_C, KeyFlag.Control));
301         editItem.add(new Action(EditorActions.Paste, "MENU_EDIT_PASTE"c, "edit-paste", KeyCode.KEY_V, KeyFlag.Control));
302         editItem.add(new Action(EditorActions.Cut, "MENU_EDIT_CUT"c, "edit-cut", KeyCode.KEY_X, KeyFlag.Control));
303         editItem.add(new Action(EditorActions.Undo, "MENU_EDIT_UNDO"c, "edit-undo", KeyCode.KEY_Z, KeyFlag.Control));
304         editItem.add(new Action(EditorActions.Redo, "MENU_EDIT_REDO"c, "edit-redo", KeyCode.KEY_Y, KeyFlag.Control));
305         editItem.add(new Action(EditorActions.Indent, "MENU_EDIT_INDENT"c, "edit-indent", KeyCode.TAB, 0));
306         editItem.add(new Action(EditorActions.Unindent, "MENU_EDIT_UNINDENT"c, "edit-unindent", KeyCode.TAB, KeyFlag.Control));
307         editItem.add(new Action(20, "MENU_EDIT_PREFERENCES"));
308 
309         MenuItem editPopupItem = new MenuItem(null);
310         editPopupItem.add(new Action(EditorActions.Copy, "MENU_EDIT_COPY"c, "edit-copy", KeyCode.KEY_C, KeyFlag.Control));
311         editPopupItem.add(new Action(EditorActions.Paste, "MENU_EDIT_PASTE"c, "edit-paste", KeyCode.KEY_V, KeyFlag.Control));
312         editPopupItem.add(new Action(EditorActions.Cut, "MENU_EDIT_CUT"c, "edit-cut", KeyCode.KEY_X, KeyFlag.Control));
313         editPopupItem.add(new Action(EditorActions.Undo, "MENU_EDIT_UNDO"c, "edit-undo", KeyCode.KEY_Z, KeyFlag.Control));
314         editPopupItem.add(new Action(EditorActions.Redo, "MENU_EDIT_REDO"c, "edit-redo", KeyCode.KEY_Y, KeyFlag.Control));
315         editPopupItem.add(new Action(EditorActions.Indent, "MENU_EDIT_INDENT"c, "edit-indent", KeyCode.TAB, 0));
316         editPopupItem.add(new Action(EditorActions.Unindent, "MENU_EDIT_UNINDENT"c, "edit-unindent", KeyCode.TAB, KeyFlag.Control));
317 
318         MenuItem viewItem = new MenuItem(new Action(60, "MENU_VIEW"));
319         MenuItem langItem = new MenuItem(new Action(61, "MENU_VIEW_LANGUAGE"));
320         auto onLangChange = delegate (MenuItem item) {
321             if (!item.checked)
322                 return false;
323             if (item.id == 611) {
324                 // set interface language to english
325                 platform.instance.uiLanguage = "en";
326             } else if (item.id == 612) {
327                 // set interface language to russian
328                 platform.instance.uiLanguage = "ru";
329             }
330             return true;
331         };
332         MenuItem enLang = (new MenuItem(new Action(611, "MENU_VIEW_LANGUAGE_EN"))).type(MenuItemType.Radio).checked(true);
333         MenuItem ruLang = (new MenuItem(new Action(612, "MENU_VIEW_LANGUAGE_RU"))).type(MenuItemType.Radio);
334         enLang.menuItemClick = onLangChange;
335         ruLang.menuItemClick = onLangChange;
336         langItem.add(enLang);
337         langItem.add(ruLang);
338         viewItem.add(langItem);
339         MenuItem themeItem = new MenuItem(new Action(62, "MENU_VIEW_THEME"));
340         MenuItem theme1 = (new MenuItem(new Action(621, "MENU_VIEW_THEME_DEFAULT"))).type(MenuItemType.Radio).checked(true);
341         MenuItem theme2 = (new MenuItem(new Action(622, "MENU_VIEW_THEME_DARK"))).type(MenuItemType.Radio);
342         MenuItem theme3 = (new MenuItem(new Action(623, "MENU_VIEW_THEME_CUSTOM1"))).type(MenuItemType.Radio);
343         auto onThemeChange = delegate (MenuItem item) {
344             if (!item.checked)
345                 return false;
346             if (item.id == 621) {
347                 platform.instance.uiTheme = "theme_default";
348             } else if (item.id == 622) {
349                 platform.instance.uiTheme = "theme_dark";
350             } else if (item.id == 623) {
351                 platform.instance.uiTheme = "theme_custom1";
352             }
353             return true;
354         };
355         theme1.menuItemClick = onThemeChange;
356         theme2.menuItemClick = onThemeChange;
357         theme3.menuItemClick = onThemeChange;
358         themeItem.add(theme1);
359         themeItem.add(theme2);
360         themeItem.add(theme3);
361         viewItem.add(themeItem);
362 
363         MenuItem windowItem = new MenuItem(new Action(3, "MENU_WINDOW"c));
364         windowItem.add(new Action(30, "MENU_WINDOW_PREFERENCES"));
365         windowItem.add(new Action(31, UIString.fromId("MENU_WINDOW_MINIMIZE")));
366         windowItem.add(new Action(32, UIString.fromId("MENU_WINDOW_MAXIMIZE")));
367         windowItem.add(new Action(33, UIString.fromId("MENU_WINDOW_RESTORE")));
368         MenuItem helpItem = new MenuItem(new Action(4, "MENU_HELP"c));
369         helpItem.add(new Action(40, "MENU_HELP_VIEW_HELP"));
370         MenuItem aboutItem = new MenuItem(new Action(41, "MENU_HELP_ABOUT"));
371         helpItem.add(aboutItem);
372         mainMenuItems.add(fileItem);
373         mainMenuItems.add(editItem);
374         mainMenuItems.add(viewItem);
375         mainMenuItems.add(windowItem);
376         mainMenuItems.add(helpItem);
377         MainMenu mainMenu = new MainMenu(mainMenuItems);
378         contentLayout.addChild(mainMenu);
379         // to let main menu handle keyboard shortcuts
380         contentLayout.keyToAction = delegate(Widget source, uint keyCode, uint flags) {
381             return mainMenu.findKeyAction(keyCode, flags);
382         };
383         contentLayout.onAction = delegate(Widget source, const Action a) {
384             if (a.id == ACTION_FILE_EXIT) {
385                 window.close();
386                 return true;
387             } else if (a.id == 31) {
388                 window.minimizeWindow();
389                 return true;
390             } else if (a.id == 32) {
391                 window.maximizeWindow();
392                 return true;
393             } else if (a.id == 33) {
394                 window.restoreWindow();
395                 return true;
396             } else if (a.id == 41) {
397                 window.showMessageBox(UIString.fromRaw("About"d), UIString.fromRaw("DLangUI demo app\n(C) Vadim Lopatin, 2014\nhttp://github.com/buggins/dlangui"d));
398                 return true;
399             } else if (a.id == ACTION_FILE_OPEN) {
400                 UIString caption;
401                 caption = "Open Text File"d;
402                 FileDialog dlg = new FileDialog(caption, window, null);
403                 dlg.allowMultipleFiles = true;
404                 dlg.addFilter(FileFilterEntry(UIString("FILTER_ALL_FILES", "All files (*)"d), "*"));
405                 dlg.addFilter(FileFilterEntry(UIString("FILTER_TEXT_FILES", "Text files (*.txt)"d), "*.txt"));
406                 dlg.addFilter(FileFilterEntry(UIString("FILTER_SOURCE_FILES", "Source files"d), "*.d;*.dd;*.c;*.cc;*.cpp;*.h;*.hpp"));
407                 dlg.addFilter(FileFilterEntry(UIString("FILTER_EXECUTABLE_FILES", "Executable files"d), "*", true));
408                 //dlg.filterIndex = 2;
409                 dlg.dialogResult = delegate(Dialog dlg, const Action result) {
410                     if (result.id == ACTION_OPEN.id) {
411                         string[] filenames = (cast(FileDialog)dlg).filenames;
412                         foreach (filename; filenames) {
413                             if (filename.endsWith(".d") || filename.endsWith(".txt") || filename.endsWith(".cpp") || filename.endsWith(".h") || filename.endsWith(".c")
414                                 || filename.endsWith(".json") || filename.endsWith(".dd") || filename.endsWith(".ddoc") || filename.endsWith(".xml") || filename.endsWith(".html")
415                                 || filename.endsWith(".html") || filename.endsWith(".css") || filename.endsWith(".log") || filename.endsWith(".hpp")) {
416                                     // open source file in tab
417                                     int index = tabs.tabIndex(filename);
418                                     if (index >= 0) {
419                                         // file is already opened in tab
420                                         tabs.selectTab(index, true);
421                                     } else {
422                                         SourceEdit editor = new SourceEdit(filename);
423                                         if (editor.load(filename)) {
424                                             tabs.addTab(editor, toUTF32(baseName(filename)), null, true);
425                                             tabs.selectTab(filename);
426                                         } else {
427                                             destroy(editor);
428                                             window.showMessageBox(UIString.fromRaw("File open error"d), UIString.fromRaw("Cannot open file "d ~ toUTF32(filename)));
429                                         }
430                                     }
431                                 } else {
432                                     Log.d("FileDialog.onDialogResult: ", result, " param=", result.stringParam);
433                                     window.showMessageBox(UIString.fromRaw("FileOpen result"d), UIString.fromRaw("Filename: "d ~ toUTF32(filename)));
434                                 }
435                         }
436                     }
437 
438                 };
439                 dlg.show();
440                 return true;
441             }
442             //else
443             //return contentLayout.dispatchAction(a);
444             return false;
445         };
446         mainMenu.menuItemClick = delegate(MenuItem item) {
447             Log.d("mainMenu.onMenuItemListener", item.label);
448             const Action a = item.action;
449             if (a) {
450                 return contentLayout.dispatchAction(a);
451             }
452             return false;
453         };
454 
455         // ========= create tabs ===================
456 
457         tabs.tabChanged = delegate(string newTabId, string oldTabId) {
458             window.windowCaption = tabs.tab(newTabId).text.value ~ " - dlangui example 1"d;
459         };
460         tabs.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
461 
462         // most of controls example
463         {
464             LinearLayout controls = new VerticalLayout("controls");
465             controls.layoutHeight(FILL_PARENT);
466             controls.padding = Rect(12.pointsToPixels,12.pointsToPixels,12.pointsToPixels,12.pointsToPixels);
467 
468             HorizontalLayout line1 = new HorizontalLayout();
469             controls.addChild(line1);
470 
471             GroupBox gb = new GroupBox("checkboxes", "CheckBox"d);
472             gb.addChild(new CheckBox("cb1", "CheckBox 1"d));
473             gb.addChild(new CheckBox("cb2", "CheckBox 2"d).checked(true));
474             gb.addChild(new CheckBox("cb3", "CheckBox disabled"d).enabled(false));
475             gb.addChild(new CheckBox("cb4", "CheckBox disabled"d).checked(true).enabled(false));
476             line1.addChild(gb);
477 
478             GroupBox gb2 = new GroupBox("radiobuttons", "RadioButton"d);
479             gb2.addChild(new RadioButton("rb1", "RadioButton 1"d).checked(true));
480             gb2.addChild(new RadioButton("rb2", "RadioButton 2"d));
481             gb2.addChild(new RadioButton("rb3", "RadioButton disabled"d).enabled(false));
482             line1.addChild(gb2);
483 
484             VerticalLayout col1 = new VerticalLayout();
485             GroupBox gb3 = new GroupBox("textbuttons", "Button"d, Orientation.Horizontal);
486             gb3.addChild(new Button("tb1", "Button"d));
487             gb3.addChild(new Button("tb2", "Button disabled"d).enabled(false));
488             col1.addChild(gb3);
489             GroupBox gb4 = new GroupBox("imagetextbuttons", "ImageTextButton"d, Orientation.Horizontal);
490             gb4.addChild(new ImageTextButton("itb1", "document-open", "Enabled"d));
491             gb4.addChild(new ImageTextButton("itb2", "document-save", "Disabled"d).enabled(false));
492             col1.addChild(gb4);
493             GroupBox gbtext = new GroupBox("text", "TextWidget"d, Orientation.Horizontal);
494             gbtext.addChild(new TextWidget("t1", "Red text"d).fontSize(12.pointsToPixels).textColor(0xFF0000));
495             gbtext.addChild(new TextWidget("t2", "Italic text"d).fontSize(12.pointsToPixels).fontItalic(true));
496             col1.addChild(gbtext);
497             line1.addChild(col1);
498 
499             VerticalLayout col2 = new VerticalLayout();
500             GroupBox gb31 = new GroupBox("switches", "SwitchButton"d, Orientation.Vertical);
501             gb31.addChild(new SwitchButton("sb1"));
502             gb31.addChild(new SwitchButton("sb2").checked(true));
503             gb31.addChild(new SwitchButton("sb3").enabled(false));
504             gb31.addChild(new SwitchButton("sb4").enabled(false).checked(true));
505             col2.addChild(gb31);
506             line1.addChild(col2);
507 
508             VerticalLayout col3 = new VerticalLayout();
509             GroupBox gb32 = new GroupBox("switches", "ImageButton"d, Orientation.Vertical);
510             gb32.addChild(new ImageButton("ib1", "edit-copy"));
511             gb32.addChild(new ImageButton("ib3", "edit-paste").enabled(false));
512             col3.addChild(gb32);
513             GroupBox gb33 = new GroupBox("images", "ImageWidget"d, Orientation.Vertical);
514             gb33.addChild(new ImageWidget("cr3_logo", "cr3_logo"));
515             col3.addChild(gb33);
516             line1.addChild(col3);
517 
518 
519             HorizontalLayout line2 = new HorizontalLayout();
520             controls.addChild(line2);
521 
522             GroupBox gb5 = new GroupBox("scrollbar", "horizontal ScrollBar"d);
523             gb5.addChild(new ScrollBar("sb1", Orientation.Horizontal));
524             line2.addChild(gb5);
525             GroupBox gb6 = new GroupBox("slider", "horizontal SliderWidget"d);
526             gb6.addChild(new SliderWidget("sb2", Orientation.Horizontal));
527             line2.addChild(gb6);
528             GroupBox gb7 = new GroupBox("editline1", "EditLine"d);
529             gb7.addChild(new EditLine("ed1", "Some text"d).minWidth(120.pointsToPixels));
530             line2.addChild(gb7);
531             GroupBox gb8 = new GroupBox("editline2", "EditLine disabled"d);
532             gb8.addChild(new EditLine("ed2", "Some text"d).enabled(false).minWidth(120.pointsToPixels));
533             line2.addChild(gb8);
534 
535             HorizontalLayout line3 = new HorizontalLayout();
536             line3.layoutWidth(FILL_PARENT);
537             GroupBox gbeditbox = new GroupBox("editbox", "EditBox"d, Orientation.Horizontal);
538             gbeditbox.layoutWidth(FILL_PARENT);
539             EditBox ed1 = new EditBox("ed1", "Some text in EditBox\nOne more line\nYet another text line");
540             ed1.layoutHeight(FILL_PARENT);
541             gbeditbox.addChild(ed1);
542             line3.addChild(gbeditbox);
543             GroupBox gbtabs = new GroupBox(null, "TabWidget"d);
544             gbtabs.layoutWidth(FILL_PARENT);
545             TabWidget tabs1 = new TabWidget("tabs1");
546             tabs1.addTab(new TextWidget("tab1", "TextWidget on tab page\nTextWidgets can be\nMultiline"d).maxLines(3), "Tab 1"d);
547             tabs1.addTab(new ImageWidget("tab2", "dlangui-logo1"), "Tab 2"d);
548             tabs1.tabHost.backgroundColor = 0xE0E0E0;
549             tabs1.tabHost.padding = Rect(10.pointsToPixels, 10.pointsToPixels, 10.pointsToPixels, 10.pointsToPixels);
550             gbtabs.addChild(tabs1);
551             line3.addChild(gbtabs);
552             controls.addChild(line3);
553 
554             HorizontalLayout line4 = new HorizontalLayout();
555             line4.layoutWidth(FILL_PARENT);
556             line4.layoutHeight(FILL_PARENT);
557             GroupBox gbgrid = new GroupBox("grid", "StringGridWidget"d, Orientation.Horizontal);
558             StringGridWidget grid = new StringGridWidget("stringgrid");
559             grid.resize(12, 10);
560             gbgrid.layoutWidth(FILL_PARENT);
561             gbgrid.layoutHeight(FILL_PARENT);
562             grid.layoutWidth(FILL_PARENT);
563             grid.layoutHeight(FILL_PARENT);
564             foreach (index, month; ["January"d, "February"d, "March"d, "April"d, "May"d, "June"d, "July"d, "August"d, "September"d, "October"d, "November"d, "December"d])
565                 grid.setColTitle(cast(int)index, month);
566             for (int y = 0; y < 10; y++)
567                 grid.setRowTitle(y, to!dstring(y+1));
568             //grid.alignment = Align.Right;
569             grid.setColWidth(0, 30.pointsToPixels);
570             grid.autoFit();
571             import std.random;
572             import std.string;
573             for (int x = 0; x < 12; x++) {
574                 for (int y = 0; y < 10; y++) {
575                     int n = uniform(0, 10000);
576                     grid.setCellText(x, y, to!dstring("%.2f".format(n / 100.0)));
577                 }
578             }
579             //grid.autoFit();
580             gbgrid.addChild(grid);
581             line4.addChild(gbgrid);
582 
583             GroupBox gbtree = new GroupBox("tree", "TreeWidget"d, Orientation.Vertical);
584             auto tree = new TreeWidget("gbtree");
585             //tree.layoutWidth(WRAP_CONTENT).layoutHeight(FILL_PARENT);
586             tree.maxHeight(200.pointsToPixels);
587             TreeItem tree1 = tree.items.newChild("group1", "Group 1"d, "document-open");
588             tree1.newChild("g1_1", "Group 1 item 1"d);
589             tree1.newChild("g1_2", "Group 1 item 2"d);
590             tree1.newChild("g1_3", "Group 1 item 3"d);
591             TreeItem tree2 = tree.items.newChild("group2", "Group 2"d, "document-save");
592             tree2.newChild("g2_1", "Group 2 item 1"d, "edit-copy");
593             tree2.newChild("g2_2", "Group 2 item 2"d, "edit-cut");
594             tree2.newChild("g2_3", "Group 2 item 3"d, "edit-paste");
595             tree2.newChild("g2_4", "Group 2 item 4"d);
596             TreeItem tree3 = tree.items.newChild("group3", "Group 3"d);
597             tree3.newChild("g3_1", "Group 3 item 1"d);
598             tree3.newChild("g3_2", "Group 3 item 2"d);
599             TreeItem tree32 = tree3.newChild("g3_3", "Group 3 item 3"d);
600             tree3.newChild("g3_4", "Group 3 item 4"d);
601             tree32.newChild("group3_2_1", "Group 3 item 2 subitem 1"d);
602             tree32.newChild("group3_2_2", "Group 3 item 2 subitem 2"d);
603             tree32.newChild("group3_2_3", "Group 3 item 2 subitem 3"d);
604             tree32.newChild("group3_2_4", "Group 3 item 2 subitem 4"d);
605             tree32.newChild("group3_2_5", "Group 3 item 2 subitem 5"d);
606             tree3.newChild("g3_5", "Group 3 item 5"d);
607             tree3.newChild("g3_6", "Group 3 item 6"d);
608             gbtree.addChild(tree);
609             tree.items.selectItem(tree1);
610             // test adding new tree items
611             HorizontalLayout newTreeItem = new HorizontalLayout();
612             newTreeItem.layoutWidth = FILL_PARENT;
613             EditLine edNewTreeItem = new EditLine("newTreeItem", "new item"d);
614             edNewTreeItem.layoutWidth = FILL_PARENT;
615             Button btnAddItem = new Button("btnAddTreeItem", "Add"d);
616             Button btnRemoveItem = new Button("btnRemoveTreeItem", "Remove"d);
617             newTreeItem.addChild(edNewTreeItem);
618             newTreeItem.addChild(btnAddItem);
619             newTreeItem.addChild(btnRemoveItem);
620             btnAddItem.click = delegate(Widget source) {
621                 import std.random;
622                 dstring label = edNewTreeItem.text;
623                 string id = "item%d".format(uniform(1000000, 9999999, rndGen));
624                 TreeItem item = tree.items.selectedItem;
625                 if (item) {
626                     Log.d("Creating new tree item ", id, " ", label);
627                     TreeItem newItem = new TreeItem(id, label);
628                     item.addChild(newItem);
629                 }
630                 return true;
631             };
632             btnRemoveItem.click = delegate(Widget source) {
633                 TreeItem item = tree.items.selectedItem;
634                 if (item) {
635                     Log.d("Removing tree item ", item.id, " ", item.text);
636                     item.parent.removeChild(item);
637                 }
638                 return true;
639             };
640             gbtree.addChild(newTreeItem);
641             line4.addChild(gbtree);
642 
643             controls.addChild(line4);
644 
645             tabs.addTab(controls, "Controls"d);
646         }
647 
648         LinearLayout layout = new LinearLayout("tab1");
649 
650 
651         layout.addChild((new TextWidget()).textColor(0x00802000).text("Text widget 0"));
652         layout.addChild((new TextWidget()).textColor(0x40FF4000).text("Text widget"));
653         layout.addChild(new ProgressBarWidget().progress(300).animationInterval(50));
654         layout.addChild(new ProgressBarWidget().progress(-1).animationInterval(50));
655         layout.addChild((new Button("BTN1")).textResource("EXIT")); //.textColor(0x40FF4000)
656         layout.addChild(new TimerTest());
657 
658         static if (true) {
659 
660 
661         LinearLayout hlayout = new HorizontalLayout();
662         hlayout.layoutWidth(FILL_PARENT);
663         //hlayout.addChild((new Button()).text("<<")); //.textColor(0x40FF4000)
664         hlayout.addChild((new TextWidget()).text("Several").alignment(Align.Center));
665         hlayout.addChild((new ImageWidget()).drawableId("btn_radio").padding(Rect(5,5,5,5)).alignment(Align.Center));
666         hlayout.addChild((new TextWidget()).text("items").alignment(Align.Center));
667         hlayout.addChild((new ImageWidget()).drawableId("btn_check").padding(Rect(5,5,5,5)).alignment(Align.Center));
668         hlayout.addChild((new TextWidget()).text("in horizontal layout"));
669         hlayout.addChild((new ImageWidget()).drawableId("exit").padding(Rect(5,5,5,5)).alignment(Align.Center));
670         hlayout.addChild((new EditLine("editline", "Some text to edit"d)).popupMenu(editPopupItem).alignment(Align.Center).layoutWidth(FILL_PARENT));
671         hlayout.addChild((new EditLine("passwd", "Password"d)).passwordChar('*').popupMenu(editPopupItem).alignment(Align.Center).layoutWidth(FILL_PARENT));
672         //hlayout.addChild((new Button()).text(">>")); //.textColor(0x40FF4000)
673         hlayout.backgroundColor = 0x8080C0;
674         layout.addChild(hlayout);
675 
676         LinearLayout vlayoutgroup = new HorizontalLayout();
677         LinearLayout vlayout = new VerticalLayout();
678         vlayout.addChild((new TextWidget()).text("VLayout line 1").textColor(0x40FF4000)); //
679         vlayout.addChild((new TextWidget()).text("VLayout line 2").textColor(0x40FF8000));
680         vlayout.addChild((new TextWidget()).text("VLayout line 2").textColor(0x40008000));
681         vlayout.addChild(new RadioButton("rb1", "Radio button 1"d));
682         vlayout.addChild(new RadioButton("rb2", "Radio button 2"d));
683         vlayout.addChild(new RadioButton("rb3", "Radio button 3"d));
684         vlayout.layoutWidth(FILL_PARENT);
685         vlayoutgroup.addChild(vlayout);
686         vlayoutgroup.layoutWidth(FILL_PARENT);
687         ScrollBar vsb = new ScrollBar("vscroll", Orientation.Vertical);
688         vlayoutgroup.addChild(vsb);
689         layout.addChild(vlayoutgroup);
690 
691         ScrollBar sb = new ScrollBar("hscroll", Orientation.Horizontal);
692         layout.addChild(sb.layoutHeight(WRAP_CONTENT).layoutWidth(FILL_PARENT));
693 
694         layout.addChild((new CheckBox("BTN2", "Some checkbox"d)));
695         layout.addChild((new TextWidget()).textColor(0x40FF4000).text("Text widget"));
696         layout.addChild((new ImageWidget()).drawableId("exit").padding(Rect(5,5,5,5)));
697         layout.addChild((new TextWidget()).textColor(0xFF4000).text("Text widget2").padding(Rect(5,5,5,5)).margins(Rect(5,5,5,5)).backgroundColor(0xA0A0A0));
698         layout.addChild((new RadioButton("BTN3", "Some radio button"d)));
699         layout.addChild((new TextWidget(null, "Text widget3 with very long text"d)).textColor(0x004000));
700         layout.addChild(new VSpacer()); // vertical spacer to fill extra space
701 
702 
703         Widget w = parseML(q{
704             VerticalLayout {
705                 id: vlayout
706                 margins: Rect { left: 5; right: 3; top: 2; bottom: 4 }
707                 padding: Rect { 5, 4, 3, 2 } // same as Rect { left: 5; top: 4; right: 3; bottom: 2 }
708                 TextWidget {
709                     /* this widget can be accessed via id myLabel1
710                     e.g. w.childById!TextWidget("myLabel1")
711                     */
712                     id: myLabel1
713                     text: "Some text"; padding: 5
714                     enabled: false
715                 }
716                 TextWidget {
717                     id: myLabel2
718                     text: SOME_TEXT_RESOURCE_ID; margins: 5
719                     enabled: true
720                 }
721             }
722         });
723         Log.d("id=", w.id, " text=", w.text, " padding=", w.padding, " margins=", w.margins,
724               " lbl1.text=", w.childById!TextWidget("myLabel1").text,
725               " lbl1.enabled=", w.childById!TextWidget("myLabel1").enabled,
726               " lbl2.text=", w.childById!TextWidget("myLabel2").text
727               );
728         destroy(w);
729 
730         layout.childById("BTN1").click = delegate (Widget w) {
731             Log.d("onClick ", w.id);
732             //w.backgroundImageId = null;
733             //w.backgroundColor = 0xFF00FF;
734             w.textColor = 0xFF00FF;
735             w.styleId = STYLE_BUTTON_NOMARGINS;
736             return true;
737         };
738         layout.childById("BTN2").click = delegate (Widget w) { Log.d("onClick ", w.id); return true; };
739         layout.childById("BTN3").click = delegate (Widget w) { Log.d("onClick ", w.id); return true; };
740 
741         }
742 
743         layout.layoutHeight(FILL_PARENT).layoutWidth(FILL_PARENT);
744 
745         tabs.addTab(layout, "Misc"d);
746 
747         static if (true) {
748             // two long lists
749             // left one is list with widgets as items
750             // right one is list with string list adapter
751             HorizontalLayout longLists = new HorizontalLayout("tab2");
752             longLists.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
753 
754             ListWidget list = new ListWidget("list1", Orientation.Vertical);
755             list.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
756 
757             StringListAdapter stringList = new StringListAdapter();
758             WidgetListAdapter listAdapter = new WidgetListAdapter();
759             listAdapter.add((new TextWidget()).text("This is a list of widgets"d).styleId("LIST_ITEM"));
760             stringList.add("This is a list of strings from StringListAdapter"d);
761             stringList.add("If you type with your keyboard,"d);
762             stringList.add("then you can find the"d);
763             stringList.add("item in the list"d);
764             stringList.add("neat!"d);
765             for (int i = 1; i < 1000; i++) {
766                 dstring label = "List item "d ~ to!dstring(i);
767                 listAdapter.add((new TextWidget()).text("Widget list - "d ~ label).styleId("LIST_ITEM"));
768                 stringList.add("Simple string - "d ~ label);
769             }
770             list.ownAdapter = listAdapter;
771             listAdapter.resetItemState(0, State.Enabled);
772             listAdapter.resetItemState(5, State.Enabled);
773             listAdapter.resetItemState(7, State.Enabled);
774             listAdapter.resetItemState(12, State.Enabled);
775             assert(list.itemEnabled(5) == false);
776             assert(list.itemEnabled(6) == true);
777             list.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
778             list.selectItem(0);
779 
780             longLists.addChild(list);
781 
782             ListWidget list2 = new StringListWidget("list2");
783             list2.ownAdapter = stringList;
784             list2.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
785             list2.selectItem(0);
786             longLists.addChild(list2);
787 
788             VerticalLayout itemedit = new VerticalLayout();
789             itemedit.addChild(new TextWidget(null, "New item text:"d));
790             EditLine itemtext = new EditLine(null, "Text for new item"d);
791             itemedit.addChild(itemtext);
792             Button btn = new Button(null, "Add item"d);
793             itemedit.addChild(btn);
794             longLists.addChild(itemedit);
795             btn.click = delegate(Widget src)
796             {
797                 stringList.add(itemtext.text);
798                 listAdapter.add((new TextWidget()).text(itemtext.text).styleId("LIST_ITEM"));
799                 return true;
800             };
801             tabs.addTab(longLists, "TAB_LONG_LIST"c);
802         }
803 
804         {
805             LinearLayout layout3 = new VerticalLayout("tab3");
806             // 3 types of buttons: Button, ImageButton, ImageTextButton
807             layout3.addChild(new TextWidget(null, "Buttons in HorizontalLayout"d));
808             WidgetGroup buttons1 = new HorizontalLayout();
809             buttons1.addChild(new TextWidget(null, "Button widgets: "d));
810             buttons1.addChild((new Button("btn1", "Button"d)).tooltipText("Tooltip text for button"d));
811             buttons1.addChild((new Button("btn2", "Disabled Button"d)).enabled(false));
812             buttons1.addChild(new TextWidget(null, "ImageButton widgets: "d));
813             buttons1.addChild(new ImageButton("btn3", "text-plain"));
814             buttons1.addChild(new TextWidget(null, "disabled: "d));
815             buttons1.addChild((new ImageButton("btn4", "folder")).enabled(false));
816             layout3.addChild(buttons1);
817 
818             WidgetGroup buttons10 = new HorizontalLayout();
819             buttons10.addChild(new TextWidget(null, "ImageTextButton widgets: "d));
820             buttons10.addChild(new ImageTextButton("btn5", "text-plain", "Enabled"d));
821             buttons10.addChild((new ImageTextButton("btn6", "folder", "Disabled"d)).enabled(false));
822             buttons10.addChild(new TextWidget(null, "SwitchButton widgets: "d));
823             buttons10.addChild((new SwitchButton("SW1")).checked(true));
824             buttons10.addChild((new SwitchButton("SW2")).checked(false));
825             buttons10.addChild((new SwitchButton("SW3")).checked(true).enabled(false));
826             buttons10.addChild((new SwitchButton("SW4")).checked(false).enabled(false));
827             layout3.addChild(buttons10);
828 
829             WidgetGroup buttons11 = new HorizontalLayout();
830             buttons11.addChild(new TextWidget(null, "Construct buttons by action (Button, ImageButton, ImageTextButton): "d));
831             Action FILE_OPEN_ACTION = new Action(ACTION_FILE_OPEN, "MENU_FILE_OPEN"c, "document-open", KeyCode.KEY_O, KeyFlag.Control);
832             buttons11.addChild(new Button(FILE_OPEN_ACTION));
833             buttons11.addChild(new ImageButton(FILE_OPEN_ACTION));
834             buttons11.addChild(new ImageTextButton(FILE_OPEN_ACTION));
835             layout3.addChild(buttons11);
836 
837             WidgetGroup buttons12 = new HorizontalLayout();
838             buttons12.addChild(new TextWidget(null, "The same in disabled state: "d));
839             buttons12.addChild((new Button(FILE_OPEN_ACTION)).enabled(false));
840             buttons12.addChild((new ImageButton(FILE_OPEN_ACTION)).enabled(false));
841             buttons12.addChild((new ImageTextButton(FILE_OPEN_ACTION)).enabled(false));
842             layout3.addChild(buttons12);
843 
844             layout3.addChild(new VSpacer());
845             layout3.addChild(new TextWidget(null, "CheckBoxes in HorizontalLayout"d));
846             WidgetGroup buttons2 = new HorizontalLayout();
847             buttons2.addChild(new CheckBox("btn1", "CheckBox 1"d));
848             buttons2.addChild(new CheckBox("btn2", "CheckBox 2"d));
849             //buttons2.addChild(new ResizerWidget());
850             buttons2.addChild(new CheckBox("btn3", "CheckBox 3"d));
851             buttons2.addChild(new CheckBox("btn4", "CheckBox 4"d));
852             layout3.addChild(buttons2);
853 
854             layout3.addChild(new VSpacer());
855             layout3.addChild(new TextWidget(null, "RadioButtons in HorizontalLayout"d));
856             WidgetGroup buttons3 = new HorizontalLayout();
857             buttons3.addChild(new RadioButton("btn1", "RadioButton 1"d));
858             buttons3.addChild(new RadioButton("btn2", "RadioButton 2"d));
859             buttons3.addChild(new RadioButton("btn3", "RadioButton 3"d));
860             buttons3.addChild(new RadioButton("btn4", "RadioButton 4"d));
861             layout3.addChild(buttons3);
862 
863             layout3.addChild(new VSpacer());
864             layout3.addChild(new TextWidget(null, "ImageButtons HorizontalLayout"d));
865             WidgetGroup buttons4 = new HorizontalLayout();
866             buttons4.addChild(new ImageButton("btn1", "fileclose"));
867             buttons4.addChild(new ImageButton("btn2", "fileopen"));
868             buttons4.addChild(new ImageButton("btn3", "exit"));
869             layout3.addChild(buttons4);
870 
871             layout3.addChild(new VSpacer());
872             layout3.addChild(new TextWidget(null, "In vertical layouts:"d));
873             HorizontalLayout hlayout2 = new HorizontalLayout();
874             hlayout2.layoutHeight(FILL_PARENT); //layoutWidth(FILL_PARENT).
875 
876             buttons1 = new VerticalLayout();
877             buttons1.addChild(new TextWidget(null, "Buttons"d));
878             buttons1.addChild(new Button("btn1", "Button 1"d));
879             buttons1.addChild(new Button("btn2", "Button 2"d));
880             buttons1.addChild((new Button("btn3", "Button 3 - disabled"d)).enabled(false));
881             buttons1.addChild(new Button("btn4", "Button 4"d));
882             hlayout2.addChild(buttons1);
883             hlayout2.addChild(new HSpacer());
884 
885             buttons2 = new VerticalLayout();
886             buttons2.addChild(new TextWidget(null, "CheckBoxes"d));
887             buttons2.addChild(new CheckBox("btn1", "CheckBox 1"d));
888             buttons2.addChild(new CheckBox("btn2", "CheckBox 2"d));
889             buttons2.addChild(new CheckBox("btn3", "CheckBox 3"d));
890             buttons2.addChild(new CheckBox("btn4", "CheckBox 4"d));
891             hlayout2.addChild(buttons2);
892             hlayout2.addChild(new HSpacer());
893 
894             buttons3 = new VerticalLayout();
895             buttons3.addChild(new TextWidget(null, "RadioButtons"d));
896             buttons3.addChild(new RadioButton("btn1", "RadioButton 1"d));
897             buttons3.addChild(new RadioButton("btn2", "RadioButton 2"d));
898             //buttons3.addChild(new ResizerWidget());
899             buttons3.addChild(new RadioButton("btn3", "RadioButton 3"d));
900             buttons3.addChild(new RadioButton("btn4", "RadioButton 4"d));
901             hlayout2.addChild(buttons3);
902             hlayout2.addChild(new HSpacer());
903 
904             buttons4 = new VerticalLayout();
905             buttons4.addChild(new TextWidget(null, "ImageButtons"d));
906             buttons4.addChild(new ImageButton("btn1", "fileclose"));
907             buttons4.addChild(new ImageButton("btn2", "fileopen"));
908             buttons4.addChild(new ImageButton("btn3", "exit"));
909             hlayout2.addChild(buttons4);
910             hlayout2.addChild(new HSpacer());
911 
912             WidgetGroup buttons5 = new VerticalLayout();
913             buttons5.addChild(new TextWidget(null, "ImageTextButtons"d));
914             buttons5.addChild(new ImageTextButton("btn1", "fileclose", "Close"d));
915             buttons5.addChild(new ImageTextButton("btn2", "fileopen", "Open"d));
916             buttons5.addChild(new ImageTextButton("btn3", "exit", "Exit"d));
917             hlayout2.addChild(buttons5);
918 
919 
920             layout3.addChild(hlayout2);
921 
922             layout3.addChild(new VSpacer());
923             layout3.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
924             tabs.addTab(layout3, "TAB_BUTTONS"c);
925         }
926 
927         TableLayout table = new TableLayout("TABLE");
928         table.colCount = 2;
929         // headers
930         table.addChild((new TextWidget(null, "Parameter Name"d)).alignment(Align.Right | Align.VCenter));
931         table.addChild((new TextWidget(null, "Edit Box to edit parameter"d)).alignment(Align.Left | Align.VCenter));
932         // row 1
933         table.addChild((new TextWidget(null, "Parameter 1 name"d)).alignment(Align.Right | Align.VCenter));
934         table.addChild((new EditLine("edit1", "Text 1"d)).layoutWidth(FILL_PARENT));
935         // row 2
936         table.addChild((new TextWidget(null, "Parameter 2 name bla bla"d)).alignment(Align.Right | Align.VCenter));
937         table.addChild((new EditLine("edit2", "Some text for parameter 2"d)).layoutWidth(FILL_PARENT));
938         // row 3
939         table.addChild((new TextWidget(null, "Param 3 is disabled"d)).alignment(Align.Right | Align.VCenter).enabled(false));
940         table.addChild((new EditLine("edit3", "Parameter 3 value"d)).layoutWidth(FILL_PARENT).enabled(false));
941         // normal readonly combo box
942         ComboBox combo1 = new ComboBox("combo1", ["item value 1"d, "item value 2"d, "item value 3"d, "item value 4"d, "item value 5"d, "item value 6"d]);
943         table.addChild((new TextWidget(null, "Combo box param"d)).alignment(Align.Right | Align.VCenter));
944         combo1.selectedItemIndex = 3;
945         table.addChild(combo1).layoutWidth(FILL_PARENT);
946         // disabled readonly combo box
947         ComboBox combo2 = new ComboBox("combo2", ["item value 1"d, "item value 2"d, "item value 3"d]);
948         table.addChild((new TextWidget(null, "Disabled combo box"d)).alignment(Align.Right | Align.VCenter));
949         combo2.enabled = false;
950         combo2.selectedItemIndex = 0;
951         table.addChild(combo2).layoutWidth(FILL_PARENT);
952 
953         table.margins(Rect(2,2,2,2)).layoutWidth(FILL_PARENT);
954         tabs.addTab(table, "TAB_TABLE_LAYOUT"c);
955 
956         //tabs.addTab((new TextWidget()).id("tab5").textColor(0x00802000).text("Tab 5 contents"), "Tab 5"d);
957 
958         //==========================================================================
959         // create Editors test tab
960         VerticalLayout editors = new VerticalLayout("editors");
961 
962         // EditLine sample
963         editors.addChild(new TextWidget(null, "EditLine: Single line editor"d));
964         EditLine editLine = new EditLine("editline1", "Single line editor sample text");
965         editors.addChild(createEditorSettingsControl(editLine));
966         editors.addChild(editLine);
967         editLine.popupMenu = editPopupItem;
968 
969         // EditBox sample
970         editors.addChild(new TextWidget(null, "SourceEdit: multiline editor, for source code editing"d));
971 
972         SourceEdit editBox = new SourceEdit("editbox1");
973         editBox.text = q{#!/usr/bin/env rdmd
974 // Computes average line length for standard input.
975 import std.stdio;
976 
977 void main()
978 {
979     ulong lines = 0;
980     double sumLength = 0;
981     foreach (line; stdin.byLine())
982     {
983         ++lines;
984         sumLength += line.length;
985     }
986     writeln("Average line length: ",
987             lines ? sumLength / lines : 0);
988 }
989         }};
990         editors.addChild(createEditorSettingsControl(editBox));
991         editors.addChild(editBox);
992         editBox.popupMenu = editPopupItem;
993 
994         editors.addChild(new TextWidget(null, "EditBox: additional view for the same content (split view testing)"d));
995         SourceEdit editBox2 = new SourceEdit("editbox2");
996         editBox2.content = editBox.content; // view the same content as first editbox
997         editors.addChild(editBox2);
998         editors.layoutHeight(FILL_PARENT).layoutWidth(FILL_PARENT);
999 
1000         tabs.addTab(editors, "TAB_EDITORS"c);
1001 
1002         //==========================================================================
1003 
1004         VerticalLayout gridContent = new VerticalLayout("GRID_CONTENT");
1005         gridContent.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
1006         HorizontalLayout gridSettings = new HorizontalLayout();
1007         StringGridWidget grid = new StringGridWidget("GRID1");
1008 
1009         gridSettings.addChild((new CheckBox("fullColumnOnLeft", "fullColumnOnLeft"d)).checked(grid.fullColumnOnLeft).tooltipText("Extends scroll area to show full column at left when scrolled to rightmost column"d).addOnCheckChangeListener(delegate(Widget, bool checked) { grid.fullColumnOnLeft = checked; return true;}));
1010         gridSettings.addChild((new CheckBox("fullRowOnTop", "fullRowOnTop"d)).checked(grid.fullRowOnTop).tooltipText("Extends scroll area to show full row at top when scrolled to end row"d).addOnCheckChangeListener(delegate(Widget, bool checked) { grid.fullRowOnTop = checked; return true;}));
1011         gridContent.addChild(gridSettings);
1012 
1013         grid.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
1014         grid.showColHeaders = true;
1015         grid.showRowHeaders = true;
1016         grid.resize(30, 50);
1017         grid.fixedCols = 3;
1018         grid.fixedRows = 2;
1019         //grid.rowSelect = true; // testing full row selection
1020         grid.multiSelect = true;
1021         grid.selectCell(4, 6, false);
1022         // create sample grid content
1023         for (int y = 0; y < grid.rows; y++) {
1024             for (int x = 0; x < grid.cols; x++) {
1025                 grid.setCellText(x, y, "cell("d ~ to!dstring(x + 1) ~ ","d ~ to!dstring(y + 1) ~ ")"d);
1026             }
1027             grid.setRowTitle(y, to!dstring(y + 1));
1028         }
1029         for (int x = 0; x < grid.cols; x++) {
1030             int col = x + 1;
1031             dstring res;
1032             int n1 = col / 26;
1033             int n2 = col % 26;
1034             if (n1)
1035                 res ~= n1 + 'A';
1036             res ~= n2 + 'A';
1037             grid.setColTitle(x, res);
1038         }
1039         grid.autoFit();
1040         gridContent.addChild(grid);
1041         tabs.addTab(gridContent, "Grid"d);
1042 
1043         //==========================================================================
1044         // Scroll view example
1045         ScrollWidget scroll = new ScrollWidget("SCROLL1");
1046         scroll.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
1047         WidgetGroup scrollContent = new VerticalLayout("CONTENT");
1048         scrollContent.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
1049 
1050         TableLayout table2 = new TableLayout("TABLE2");
1051         table2.colCount = 2;
1052         // headers
1053         table2.addChild((new TextWidget(null, "Parameter Name"d)).alignment(Align.Right | Align.VCenter));
1054         table2.addChild((new TextWidget(null, "Edit Box to edit parameter"d)).alignment(Align.Left | Align.VCenter));
1055         // row 1
1056         table2.addChild((new TextWidget(null, "Parameter 1 name"d)).alignment(Align.Right | Align.VCenter));
1057         table2.addChild((new EditLine("edit1", "Text 1"d)).layoutWidth(FILL_PARENT));
1058         // row 2
1059         table2.addChild((new TextWidget(null, "Parameter 2 name bla bla"d)).alignment(Align.Right | Align.VCenter));
1060         table2.addChild((new EditLine("edit2", "Some text for parameter 2 blah blah blah"d)).layoutWidth(FILL_PARENT));
1061         // row 3
1062         table2.addChild((new TextWidget(null, "Param 3"d)).alignment(Align.Right | Align.VCenter));
1063         table2.addChild((new EditLine("edit3", "Parameter 3 value"d)).layoutWidth(FILL_PARENT));
1064         // row 4
1065         table2.addChild((new TextWidget(null, "Param 4"d)).alignment(Align.Right | Align.VCenter));
1066         table2.addChild((new EditLine("edit3", "Parameter 4 value shdjksdfh hsjdfas hdjkf hdjsfk ah"d)).layoutWidth(FILL_PARENT));
1067         // row 5
1068         table2.addChild((new TextWidget(null, "Param 5 - edit text here - blah blah blah"d)).alignment(Align.Right | Align.VCenter));
1069         table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT));
1070         // row 6
1071         table2.addChild((new TextWidget(null, "Param 6 - just to fill content widget (DISABLED)"d)).alignment(Align.Right | Align.VCenter).enabled(false));
1072         table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT).enabled(false));
1073         // row 7
1074         table2.addChild((new TextWidget(null, "Param 7 - just to fill content widget (DISABLED)"d)).alignment(Align.Right | Align.VCenter).enabled(false));
1075         table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT).enabled(false));
1076         // row 8
1077         table2.addChild((new TextWidget(null, "Param 8 - just to fill content widget"d)).alignment(Align.Right | Align.VCenter));
1078         table2.addChild((new EditLine("edit3", "Parameter 5 value"d)).layoutWidth(FILL_PARENT));
1079         table2.margins(Rect(10,10,10,10)).layoutWidth(FILL_PARENT);
1080         scrollContent.addChild(table2);
1081 
1082         scrollContent.addChild(new TextWidget(null, "Now - some buttons"d));
1083         scrollContent.addChild(new ImageTextButton("btn1", "fileclose", "Close"d));
1084         scrollContent.addChild(new ImageTextButton("btn2", "fileopen", "Open"d));
1085         scrollContent.addChild(new TextWidget(null, "And checkboxes"d));
1086         scrollContent.addChild(new CheckBox("btn1", "CheckBox 1"d));
1087         scrollContent.addChild(new CheckBox("btn2", "CheckBox 2"d));
1088 
1089         scroll.contentWidget = scrollContent;
1090         tabs.addTab(scroll, "Scroll"d);
1091         //==========================================================================
1092         // tree view example
1093         TreeWidget tree = new TreeWidget("TREE1");
1094         tree.layoutWidth(WRAP_CONTENT).layoutHeight(FILL_PARENT);
1095         TreeItem tree1 = tree.items.newChild("group1", "Group 1"d, "document-open");
1096         tree1.newChild("g1_1", "Group 1 item 1"d);
1097         tree1.newChild("g1_2", "Group 1 item 2"d);
1098         tree1.newChild("g1_3", "Group 1 item 3"d);
1099         TreeItem tree2 = tree.items.newChild("group2", "Group 2"d, "document-save");
1100         tree2.newChild("g2_1", "Group 2 item 1"d, "edit-copy");
1101         tree2.newChild("g2_2", "Group 2 item 2"d, "edit-cut");
1102         tree2.newChild("g2_3", "Group 2 item 3"d, "edit-paste");
1103         tree2.newChild("g2_4", "Group 2 item 4"d);
1104         TreeItem tree3 = tree.items.newChild("group3", "Group 3"d);
1105         tree3.newChild("g3_1", "Group 3 item 1"d);
1106         tree3.newChild("g3_2", "Group 3 item 2"d);
1107         TreeItem tree32 = tree3.newChild("g3_3", "Group 3 item 3"d);
1108         tree3.newChild("g3_4", "Group 3 item 4"d);
1109         tree32.newChild("group3_2_1", "Group 3 item 2 subitem 1"d);
1110         tree32.newChild("group3_2_2", "Group 3 item 2 subitem 2"d);
1111         tree32.newChild("group3_2_3", "Group 3 item 2 subitem 3"d);
1112         tree32.newChild("group3_2_4", "Group 3 item 2 subitem 4"d);
1113         tree32.newChild("group3_2_5", "Group 3 item 2 subitem 5"d);
1114         tree3.newChild("g3_5", "Group 3 item 5"d);
1115         tree3.newChild("g3_6", "Group 3 item 6"d);
1116 
1117         LinearLayout treeLayout = new HorizontalLayout("TREE");
1118         LinearLayout treeControlledPanel = new VerticalLayout();
1119         treeLayout.layoutWidth = FILL_PARENT;
1120         treeControlledPanel.layoutWidth = FILL_PARENT;
1121         treeControlledPanel.layoutHeight = FILL_PARENT;
1122         TextWidget treeItemLabel = new TextWidget("TREE_ITEM_DESC");
1123         treeItemLabel.layoutWidth = FILL_PARENT;
1124         treeItemLabel.layoutHeight = FILL_PARENT;
1125         treeItemLabel.alignment = Align.Center;
1126         treeItemLabel.text = "Sample text"d;
1127         treeControlledPanel.addChild(treeItemLabel);
1128         treeLayout.addChild(tree);
1129         treeLayout.addChild(new ResizerWidget());
1130         treeLayout.addChild(treeControlledPanel);
1131 
1132         tree.selectionChange = delegate(TreeItems source, TreeItem selectedItem, bool activated) {
1133             dstring label = "Selected item: "d ~ toUTF32(selectedItem.id) ~ (activated ? " selected + activated"d : " selected"d);
1134             treeItemLabel.text = label;
1135         };
1136 
1137         tree.items.selectItem(tree.items.child(0));
1138 
1139         tabs.addTab(treeLayout, "Tree"d);
1140         //==========================================================================
1141         // charts example
1142         SimpleBarChart barChart1 = new SimpleBarChart("barChart1","SimpleBarChart Example"d);
1143         barChart1.addBar(12.0, makeRGBA(255,0,0,0), "Red bar"d);
1144         barChart1.addBar(24.0, makeRGBA(0,255,0,0), "Green bar"d);
1145         barChart1.addBar(5.0, makeRGBA(0,0,255,0), "Blue bar"d);
1146         barChart1.addBar(12.0, makeRGBA(230,126,34,0), "Orange bar"d);
1147         //barChart1.layoutWidth = FILL_PARENT;
1148         //barChart1.layoutHeight = FILL_PARENT;
1149 
1150         SimpleBarChart barChart2 = new SimpleBarChart("barChart2","SimpleBarChart Example - long descriptions"d);
1151         barChart2.addBar(12.0, makeRGBA(255,0,0,0), "Red bar\n(12.0)"d);
1152         barChart2.addBar(24.0, makeRGBA(0,255,0,0), "Green bar\n(24.0)"d);
1153         barChart2.addBar(5.0, makeRGBA(0,0,255,0), "Blue bar\n(5.0)"d);
1154         barChart2.addBar(12.0, makeRGBA(230,126,34,0), "Orange bar\n(12.0)\nlong long long description added here"d);
1155 
1156         SimpleBarChart barChart3 = new SimpleBarChart("barChart3","SimpleBarChart Example with axis ratio 0.3"d);
1157         barChart3.addBar(12.0, makeRGBA(255,0,0,0), "Red bar"d);
1158         barChart3.addBar(24.0, makeRGBA(0,255,0,0), "Green bar"d);
1159         barChart3.addBar(5.0, makeRGBA(0,0,255,0), "Blue bar"d);
1160         barChart3.addBar(12.0, makeRGBA(230,126,34,0), "Orange bar"d);
1161         barChart3.axisRatio = 0.3;
1162 
1163         SimpleBarChart barChart4 = new SimpleBarChart("barChart4","SimpleBarChart Example with axis ratio 1.3"d);
1164         barChart4.addBar(12.0, makeRGBA(255,0,0,0), "Red bar"d);
1165         barChart4.addBar(24.0, makeRGBA(0,255,0,0), "Green bar"d);
1166         barChart4.addBar(5.0, makeRGBA(0,0,255,0), "Blue bar"d);
1167         barChart4.addBar(12.0, makeRGBA(230,126,34,0), "Orange bar"d);
1168         barChart4.axisRatio = 1.3;
1169 
1170         HorizontalLayout chartsLayout = new HorizontalLayout("CHARTS");
1171         chartsLayout.layoutWidth = FILL_PARENT;
1172         chartsLayout.layoutHeight = FILL_PARENT;
1173 
1174         VerticalLayout chartColumn1 = new VerticalLayout();
1175         VerticalLayout chartColumn2 = new VerticalLayout();
1176 
1177         chartColumn1.addChild(barChart1);
1178         chartColumn1.addChild(barChart2);
1179         chartsLayout.addChild(chartColumn1);
1180         chartColumn2.addChild(barChart3);
1181         chartColumn2.addChild(barChart4);
1182         chartsLayout.addChild(chartColumn2);
1183         tabs.addTab(chartsLayout, "Charts"d);
1184 
1185         static if (BACKEND_GUI) {
1186 
1187             tabs.addTab((new SampleAnimationWidget("tab6")).layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT), "TAB_ANIMATION"c);
1188 
1189             CanvasWidget canvas = new CanvasWidget("canvas");
1190             canvas.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
1191             canvas.onDrawListener = delegate(CanvasWidget canvas, DrawBuf buf, Rect rc) {
1192                 //Log.w("canvas.onDrawListener clipRect=" ~ to!string(buf.clipRect));
1193                 buf.fill(0xFFFFFF);
1194                 int x = rc.left;
1195                 int y = rc.top;
1196                 buf.fillRect(Rect(x+20, y+20, x+150, y+200), 0x80FF80);
1197                 buf.fillRect(Rect(x+90, y+80, x+250, y+250), 0x80FF80FF);
1198                 canvas.font.drawText(buf, x + 40, y + 50, "fillRect()"d, 0xC080C0);
1199                 buf.drawFrame(Rect(x + 400, y + 30, x + 550, y + 150), 0x204060, Rect(2,3,4,5), 0x80704020);
1200                 canvas.font.drawText(buf, x + 400, y + 5, "drawFrame()"d, 0x208020);
1201                 canvas.font.drawText(buf, x + 300, y + 100, "drawPixel()"d, 0x000080);
1202                 for (int i = 0; i < 80; i++)
1203                     buf.drawPixel(x+300 + i * 4, y+140 + i * 3 % 100, 0xFF0000 + i * 2);
1204                 canvas.font.drawText(buf, x + 300, y + 420, "drawLine()"d, 0x800020);
1205                 for (int i = 0; i < 40; i+=3)
1206                     buf.drawLine(Point(x+200 + i * 4, y+290), Point(x+150 + i * 7, y+420 + i * 2), 0x008000 + i * 5);
1207                 // poly line test
1208                 //Rect newClipRect = Rect(x + 110, y + 100, x + 350, y + 320);
1209                 //buf.fillRect(newClipRect, 0xC08080FF);
1210                 //Rect oldClip = buf.clipRect;
1211                 //buf.clipRect = newClipRect;
1212                 PointF[] poly = [vec2(x+130, y+150), vec2(x+240, y+80), vec2(x+170, y+170), vec2(x+380, y+270), vec2(x+220, y+400), vec2(x+130, y+330)];
1213                 buf.polyLineF(poly, 18.0f, 0x80804020, true, 0x80FFFF00);
1214                 //buf.fillTriangleF(vec2(x+230, y+50), vec2(x+400, y+250), vec2(x+130, y+200), 0xC0FF0000);
1215                 //buf.fillTriangleF(vec2(x+230, y+250), vec2(x+200, y+350), vec2(x+80, y+200), 0xC000FF00);
1216                 //buf.fillTriangleF(vec2(x+430, y+250), vec2(x+280, y+150), vec2(x+200, y+300), 0xC00000FF);
1217                 //buf.fillTriangleF(vec2(x+80, y+150), vec2(x+280, y+250), vec2(x+80, y+200), 0xC0008080);
1218                 //buf.clipRect = oldClip;
1219                 canvas.font.drawText(buf, x + 190, y + 260, "polyLineF()"d, 0x603010);
1220                 PointF[] poly2 = [vec2(x+430, y+250), vec2(x+540, y+180), vec2(x+470, y+270), vec2(x+580, y+300),
1221                     vec2(x+620, y+400), vec2(x+480, y+350), vec2(x+520, y+450), vec2(x+480, y+430)];
1222                 buf.fillPolyF(poly2, 0x80203050);
1223                 //buf.polyLineF(poly2, 2.0f, 0x80000000, true);
1224                 canvas.font.drawText(buf, x + 500, y + 460, "fillPolyF()"d, 0x203050);
1225 
1226                 buf.drawEllipseF(x+300, y+600, 200, 150, 3, 0x80008000, 0x804040FF);
1227                 canvas.font.drawText(buf, x + 300, y + 600, "fillEllipseF()"d, 0x208050);
1228 
1229                 buf.drawEllipseArcF(x+540, y+600, 150, 180, 45, 130, 3, 0x40008000, 0x804040FF);
1230                 canvas.font.drawText(buf, x + 540, y + 580, "drawEllipseArcF()"d, 0x208050);
1231             };
1232             tabs.addTab(canvas, "TAB_CANVAS"c);
1233 
1234             static if (ENABLE_OPENGL) {
1235                 //
1236                 tabs.addTab(new MyOpenglWidget(), "OpenGL"d);
1237             }
1238         }
1239 
1240         //==========================================================================
1241 
1242         contentLayout.addChild(tabs);
1243         window.mainWidget = contentLayout;
1244 
1245         tabs.selectTab("controls");
1246     } else {
1247         window.mainWidget = (new Button()).text("sample button");
1248     }
1249     static if (BACKEND_GUI) {
1250         window.windowIcon = drawableCache.getImage("dlangui-logo1");
1251     }
1252     window.show();
1253     //window.windowCaption = "New Window Caption";
1254     // run message loop
1255 
1256     Log.i("HOME path: ", homePath);
1257     Log.i("APPDATA path: ", appDataPath(".dlangui"));
1258     Log.i("Root paths: ", getRootPaths);
1259 
1260     return Platform.instance.enterMessageLoop();
1261 }
1262 
1263 static if (ENABLE_OPENGL) {
1264 
1265     import derelict.opengl3.gl3;
1266     import derelict.opengl3.gl;
1267 
1268     class MyOpenglWidget : VerticalLayout {
1269         this() {
1270             super("OpenGLView");
1271             layoutWidth = FILL_PARENT;
1272             layoutHeight = FILL_PARENT;
1273             alignment = Align.Center;
1274             // add some UI on top of OpenGL drawable
1275             Widget w = parseML(q{
1276                 VerticalLayout {
1277                     alignment: center
1278                     layoutWidth: fill; layoutHeight: fill
1279                     // background for window - tiled texture
1280                     backgroundImageId: "tx_fabric.tiled"
1281                     VerticalLayout {
1282                         // child widget - will draw using OpenGL here
1283                         id: glView
1284                         margins: 20
1285                         padding: 20
1286                         layoutWidth: fill; layoutHeight: fill
1287 
1288                         //backgroundColor: "#C0E0E070" // semitransparent yellow background
1289                         // red bold text with size = 150% of base style size and font face Arial
1290                         TextWidget { text: "Some controls to draw on top of OpenGL scene"; textColor: "red"; fontSize: 150%; fontWeight: 800; fontFace: "Arial" }
1291                         // arrange controls as form - table with two columns
1292                         TableLayout {
1293                             colCount: 2
1294                             TextWidget { text: "param 1" }
1295                             EditLine { id: edit1; text: "some text" }
1296                             TextWidget { text: "param 2" }
1297                             EditLine { id: edit2; text: "some text for param2" }
1298                             TextWidget { text: "some radio buttons" }
1299                             // arrange some radio buttons vertically
1300                             VerticalLayout {
1301                                 RadioButton { id: rb1; text: "Item 1" }
1302                                 RadioButton { id: rb2; text: "Item 2" }
1303                                 RadioButton { id: rb3; text: "Item 3" }
1304                             }
1305                             TextWidget { text: "and checkboxes" }
1306                             // arrange some checkboxes horizontally
1307                             HorizontalLayout {
1308                                 CheckBox { id: cb1; text: "checkbox 1" }
1309                                 CheckBox { id: cb2; text: "checkbox 2" }
1310                             }
1311                         }
1312                         VSpacer { layoutWeight: 10 }
1313                         HorizontalLayout {
1314                             Button { id: btnOk; text: "Ok" }
1315                             Button { id: btnCancel; text: "Cancel" }
1316                         }
1317                     }
1318                 }
1319             });
1320             // setting OpenGL background drawable for one of child widgets
1321             w.childById("glView").backgroundDrawable = DrawableRef(new OpenGLDrawable(&doDraw));
1322             addChild(w);
1323         }
1324 
1325         bool _oldApi;
1326 
1327         /// this is OpenGLDrawableDelegate implementation
1328         private void doDraw(Rect windowRect, Rect rc) {
1329             if (!openglEnabled) {
1330                 Log.v("GlGears: OpenGL is disabled");
1331                 return;
1332             }
1333             import dlangui.graphics.glsupport : glSupport;
1334             _oldApi = glSupport.legacyMode;
1335             if (_oldApi) {
1336                 drawUsingOldAPI(rc);
1337             } else {
1338                 drawUsingNewAPI(rc);
1339             }
1340         }
1341 
1342         /// Legacy API example (glBegin/glEnd)
1343         void drawUsingOldAPI(Rect rc) {
1344             static bool _initCalled;
1345             if (!_initCalled) {
1346                 Log.d("GlGears: calling init()");
1347                 _initCalled = true;
1348                 glxgears_init();
1349             }
1350             glxgears_reshape(rc);
1351             glEnable(GL_LIGHTING);
1352             glEnable(GL_LIGHT0);
1353             glEnable(GL_DEPTH_TEST);
1354             glxgears_draw();
1355             glDisable(GL_LIGHTING);
1356             glDisable(GL_LIGHT0);
1357             glDisable(GL_DEPTH_TEST);
1358         }
1359 
1360         /// New API example (OpenGL3+, shaders)
1361         void drawUsingNewAPI(Rect rc) {
1362             // TODO: put some sample code here
1363         }
1364         /// returns true is widget is being animated - need to call animate() and redraw
1365         @property override bool animating() { return true; }
1366         /// animates window; interval is time left from previous draw, in hnsecs (1/10000000 of second)
1367         override void animate(long interval) {
1368             if (_oldApi) {
1369                 // animate legacy API example
1370                 // rotate gears
1371                 angle += interval * 0.000002f;
1372             } else {
1373                 // TODO: animate new API example
1374             }
1375             invalidate();
1376         }
1377     }
1378 
1379 
1380     // Sample project for old API: GlxGears
1381 
1382     import std.math;
1383     static __gshared GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
1384     static __gshared GLint gear1, gear2, gear3;
1385     static __gshared GLfloat angle = 0.0;
1386     alias M_PI = std.math.PI;
1387 
1388     /*
1389  *
1390  *  Draw a gear wheel.  You'll probably want to call this function when
1391  *  building a display list since we do a lot of trig here.
1392  *
1393  *  Input:  inner_radius - radius of hole at center
1394  *          outer_radius - radius at center of teeth
1395  *          width - width of gear
1396  *          teeth - number of teeth
1397  *          tooth_depth - depth of tooth
1398  */
1399     static void
1400         gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
1401             GLint teeth, GLfloat tooth_depth)
1402     {
1403         GLint i;
1404         GLfloat r0, r1, r2;
1405         GLfloat angle, da;
1406         GLfloat u, v, len;
1407 
1408         r0 = inner_radius;
1409         r1 = outer_radius - tooth_depth / 2.0;
1410         r2 = outer_radius + tooth_depth / 2.0;
1411 
1412         da = 2.0 * M_PI / teeth / 4.0;
1413 
1414         glShadeModel(GL_FLAT);
1415 
1416         glNormal3f(0.0, 0.0, 1.0);
1417 
1418         /* draw front face */
1419         glBegin(GL_QUAD_STRIP);
1420         for (i = 0; i <= teeth; i++) {
1421             angle = i * 2.0 * M_PI / teeth;
1422             glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
1423             glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
1424             if (i < teeth) {
1425                 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
1426                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
1427                     width * 0.5);
1428             }
1429         }
1430         glEnd();
1431 
1432         /* draw front sides of teeth */
1433         glBegin(GL_QUADS);
1434         da = 2.0 * M_PI / teeth / 4.0;
1435         for (i = 0; i < teeth; i++) {
1436             angle = i * 2.0 * M_PI / teeth;
1437 
1438             glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
1439             glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
1440             glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
1441                 width * 0.5);
1442             glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
1443                 width * 0.5);
1444         }
1445         glEnd();
1446 
1447         glNormal3f(0.0, 0.0, -1.0);
1448 
1449         /* draw back face */
1450         glBegin(GL_QUAD_STRIP);
1451         for (i = 0; i <= teeth; i++) {
1452             angle = i * 2.0 * M_PI / teeth;
1453             glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
1454             glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
1455             if (i < teeth) {
1456                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
1457                     -width * 0.5);
1458                 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
1459             }
1460         }
1461         glEnd();
1462 
1463         /* draw back sides of teeth */
1464         glBegin(GL_QUADS);
1465         da = 2.0 * M_PI / teeth / 4.0;
1466         for (i = 0; i < teeth; i++) {
1467             angle = i * 2.0 * M_PI / teeth;
1468 
1469             glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
1470                 -width * 0.5);
1471             glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
1472                 -width * 0.5);
1473             glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
1474             glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
1475         }
1476         glEnd();
1477 
1478         /* draw outward faces of teeth */
1479         glBegin(GL_QUAD_STRIP);
1480         for (i = 0; i < teeth; i++) {
1481             angle = i * 2.0 * M_PI / teeth;
1482 
1483             glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
1484             glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
1485             u = r2 * cos(angle + da) - r1 * cos(angle);
1486             v = r2 * sin(angle + da) - r1 * sin(angle);
1487             len = sqrt(u * u + v * v);
1488             u /= len;
1489             v /= len;
1490             glNormal3f(v, -u, 0.0);
1491             glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
1492             glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
1493             glNormal3f(cos(angle), sin(angle), 0.0);
1494             glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
1495                 width * 0.5);
1496             glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
1497                 -width * 0.5);
1498             u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
1499             v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
1500             glNormal3f(v, -u, 0.0);
1501             glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
1502                 width * 0.5);
1503             glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
1504                 -width * 0.5);
1505             glNormal3f(cos(angle), sin(angle), 0.0);
1506         }
1507 
1508         glVertex3f(r1 * cos(0.0), r1 * sin(0.0), width * 0.5);
1509         glVertex3f(r1 * cos(0.0), r1 * sin(0.0), -width * 0.5);
1510 
1511         glEnd();
1512 
1513         glShadeModel(GL_SMOOTH);
1514 
1515         /* draw inside radius cylinder */
1516         glBegin(GL_QUAD_STRIP);
1517         for (i = 0; i <= teeth; i++) {
1518             angle = i * 2.0 * M_PI / teeth;
1519             glNormal3f(-cos(angle), -sin(angle), 0.0);
1520             glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
1521             glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
1522         }
1523         glEnd();
1524     }
1525 
1526 
1527     static void glxgears_draw()
1528     {
1529         glClear(/*GL_COLOR_BUFFER_BIT | */GL_DEPTH_BUFFER_BIT);
1530 
1531         glPushMatrix();
1532         glRotatef(view_rotx, 1.0, 0.0, 0.0);
1533         glRotatef(view_roty, 0.0, 1.0, 0.0);
1534         glRotatef(view_rotz, 0.0, 0.0, 1.0);
1535 
1536         glPushMatrix();
1537         glTranslatef(-3.0, -2.0, 0.0);
1538         glRotatef(angle, 0.0, 0.0, 1.0);
1539         glCallList(gear1);
1540         glPopMatrix();
1541 
1542         glPushMatrix();
1543         glTranslatef(3.1, -2.0, 0.0);
1544         glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
1545         glCallList(gear2);
1546         glPopMatrix();
1547 
1548         glPushMatrix();
1549         glTranslatef(-3.1, 4.2, 0.0);
1550         glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
1551         glCallList(gear3);
1552         glPopMatrix();
1553 
1554         glPopMatrix();
1555     }
1556 
1557 
1558     /* new window size or exposure */
1559     static void
1560         glxgears_reshape(Rect rc)
1561     {
1562         GLfloat h = cast(GLfloat) rc.height / cast(GLfloat) rc.width;
1563         glMatrixMode(GL_PROJECTION);
1564         glLoadIdentity();
1565         glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
1566         glMatrixMode(GL_MODELVIEW);
1567         glLoadIdentity();
1568         glTranslatef(0.0, 0.0, -40.0);
1569     }
1570 
1571 
1572     static void glxgears_init()
1573     {
1574         static GLfloat[4] pos = [ 5.0, 5.0, 10.0, 0.0 ];
1575         static GLfloat[4] red = [ 0.8, 0.1, 0.0, 1.0 ];
1576         static GLfloat[4] green = [ 0.0, 0.8, 0.2, 1.0 ];
1577         static GLfloat[4] blue = [ 0.2, 0.2, 1.0, 1.0 ];
1578 
1579         glLightfv(GL_LIGHT0, GL_POSITION, pos.ptr);
1580         glEnable(GL_CULL_FACE);
1581         glEnable(GL_LIGHTING);
1582         glEnable(GL_LIGHT0);
1583         glEnable(GL_DEPTH_TEST);
1584 
1585         /* make the gears */
1586         gear1 = glGenLists(1);
1587         glNewList(gear1, GL_COMPILE);
1588         glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red.ptr);
1589         gear(1.0, 4.0, 1.0, 20, 0.7);
1590         glEndList();
1591 
1592         gear2 = glGenLists(1);
1593         glNewList(gear2, GL_COMPILE);
1594         glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green.ptr);
1595         gear(0.5, 2.0, 2.0, 10, 0.7);
1596         glEndList();
1597 
1598         gear3 = glGenLists(1);
1599         glNewList(gear3, GL_COMPILE);
1600         glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue.ptr);
1601         gear(1.3, 2.0, 0.5, 10, 0.7);
1602         glEndList();
1603 
1604         glEnable(GL_NORMALIZE);
1605     }
1606 
1607 
1608 }