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