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 example1;
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 import widgets;
29
30 mixin APP_ENTRY_POINT;
31
32 class TextEditorWidget : VerticalLayout {
33 EditBox _edit;
34 this(string ID) {
35 super(ID);
36 _edit = new EditBox("editor");
37 _edit.layoutWidth = FILL_PARENT;
38 _edit.layoutHeight = FILL_PARENT;
39 addChild(_edit);
40 }
41 }
42
43 /// Constructs items for main menu
44 auto constructMainMenu()
45 {
46 MenuItem mainMenuItems = new MenuItem();
47 MenuItem fileItem = new MenuItem(new Action(1, "MENU_FILE"c));
48 fileItem.add(new Action(ACTION_FILE_OPEN, "MENU_FILE_OPEN"c, "document-open", KeyCode.KEY_O, KeyFlag.Control));
49 fileItem.add(new Action(ACTION_FILE_SAVE, "MENU_FILE_SAVE"c, "document-save", KeyCode.KEY_S, KeyFlag.Control));
50 MenuItem openRecentItem = new MenuItem(new Action(13, "MENU_FILE_OPEN_RECENT", "document-open-recent"));
51 openRecentItem.add(new Action(100, "&1: File 1"d));
52 openRecentItem.add(new Action(101, "&2: File 2"d));
53 openRecentItem.add(new Action(102, "&3: File 3"d));
54 openRecentItem.add(new Action(103, "&4: File 4"d));
55 openRecentItem.add(new Action(104, "&5: File 5"d));
56 fileItem.add(openRecentItem);
57 fileItem.add(new Action(ACTION_FILE_EXIT, "MENU_FILE_EXIT"c, "document-close"c, KeyCode.KEY_X, KeyFlag.Alt));
58
59 MenuItem editItem = new MenuItem(new Action(2, "MENU_EDIT"));
60 editItem.add(new Action(EditorActions.Copy, "MENU_EDIT_COPY"c, "edit-copy", KeyCode.KEY_C, KeyFlag.Control));
61 editItem.add(new Action(EditorActions.Paste, "MENU_EDIT_PASTE"c, "edit-paste", KeyCode.KEY_V, KeyFlag.Control));
62 editItem.add(new Action(EditorActions.Cut, "MENU_EDIT_CUT"c, "edit-cut", KeyCode.KEY_X, KeyFlag.Control));
63 editItem.add(new Action(EditorActions.Undo, "MENU_EDIT_UNDO"c, "edit-undo", KeyCode.KEY_Z, KeyFlag.Control));
64 editItem.add(new Action(EditorActions.Redo, "MENU_EDIT_REDO"c, "edit-redo", KeyCode.KEY_Y, KeyFlag.Control));
65 editItem.add(new Action(EditorActions.Indent, "MENU_EDIT_INDENT"c, "edit-indent", KeyCode.TAB, 0));
66 editItem.add(new Action(EditorActions.Unindent, "MENU_EDIT_UNINDENT"c, "edit-unindent", KeyCode.TAB, KeyFlag.Control));
67 editItem.add(new Action(20, "MENU_EDIT_PREFERENCES"));
68
69 MenuItem viewItem = new MenuItem(new Action(60, "MENU_VIEW"));
70 MenuItem langItem = new MenuItem(new Action(61, "MENU_VIEW_LANGUAGE"));
71 auto onLangChange = delegate (MenuItem item) {
72 if (!item.checked)
73 return false;
74 if (item.id == 611) {
75 // set interface language to english
76 platform.instance.uiLanguage = "en";
77 } else if (item.id == 612) {
78 // set interface language to russian
79 platform.instance.uiLanguage = "ru";
80 }
81 return true;
82 };
83 MenuItem enLang = (new MenuItem(new Action(611, "MENU_VIEW_LANGUAGE_EN"))).type(MenuItemType.Radio).checked(true);
84 MenuItem ruLang = (new MenuItem(new Action(612, "MENU_VIEW_LANGUAGE_RU"))).type(MenuItemType.Radio);
85 enLang.menuItemClick = onLangChange;
86 ruLang.menuItemClick = onLangChange;
87 langItem.add(enLang);
88 langItem.add(ruLang);
89 viewItem.add(langItem);
90 MenuItem themeItem = new MenuItem(new Action(62, "MENU_VIEW_THEME"));
91 MenuItem theme1 = (new MenuItem(new Action(621, "MENU_VIEW_THEME_DEFAULT"))).type(MenuItemType.Radio).checked(true);
92 MenuItem theme2 = (new MenuItem(new Action(622, "MENU_VIEW_THEME_DARK"))).type(MenuItemType.Radio);
93 MenuItem theme3 = (new MenuItem(new Action(623, "MENU_VIEW_THEME_CUSTOM1"))).type(MenuItemType.Radio);
94 auto onThemeChange = delegate (MenuItem item) {
95 if (!item.checked)
96 return false;
97 if (item.id == 621) {
98 platform.instance.uiTheme = "theme_default";
99 } else if (item.id == 622) {
100 platform.instance.uiTheme = "theme_dark";
101 } else if (item.id == 623) {
102 platform.instance.uiTheme = "theme_custom1";
103 }
104 return true;
105 };
106 theme1.menuItemClick = onThemeChange;
107 theme2.menuItemClick = onThemeChange;
108 theme3.menuItemClick = onThemeChange;
109 themeItem.add(theme1);
110 themeItem.add(theme2);
111 themeItem.add(theme3);
112 viewItem.add(themeItem);
113
114 MenuItem windowItem = new MenuItem(new Action(3, "MENU_WINDOW"c));
115 windowItem.add(new Action(30, "MENU_WINDOW_PREFERENCES"));
116 windowItem.add(new Action(31, UIString.fromId("MENU_WINDOW_MINIMIZE")));
117 windowItem.add(new Action(32, UIString.fromId("MENU_WINDOW_MAXIMIZE")));
118 windowItem.add(new Action(33, UIString.fromId("MENU_WINDOW_RESTORE")));
119 MenuItem helpItem = new MenuItem(new Action(4, "MENU_HELP"c));
120 helpItem.add(new Action(40, "MENU_HELP_VIEW_HELP"));
121 MenuItem aboutItem = new MenuItem(new Action(41, "MENU_HELP_ABOUT"));
122 helpItem.add(aboutItem);
123 mainMenuItems.add(fileItem);
124 mainMenuItems.add(editItem);
125 mainMenuItems.add(viewItem);
126 mainMenuItems.add(windowItem);
127 mainMenuItems.add(helpItem);
128 return mainMenuItems;
129 }
130
131 /// entry point for dlangui based application
132 extern (C) int UIAppMain(string[] args)
133 {
134 // always use trace, even for release builds
135 //Log.setLogLevel(LogLevel.Trace);
136 //Log.setFileLogger(new std.stdio.File("ui.log", "w"));
137
138 // resource directory search paths
139 // not required if only embedded resources are used
140 //string[] resourceDirs = [
141 // appendPath(exePath, "../../../res/"), // for Visual D and DUB builds
142 // appendPath(exePath, "../../../res/mdpi/"), // for Visual D and DUB builds
143 // appendPath(exePath, "../../../../res/"),// for Mono-D builds
144 // appendPath(exePath, "../../../../res/mdpi/"),// for Mono-D builds
145 // appendPath(exePath, "res/"), // when res dir is located at the same directory as executable
146 // appendPath(exePath, "../res/"), // when res dir is located at project directory
147 // appendPath(exePath, "../../res/"), // when res dir is located at the same directory as executable
148 // appendPath(exePath, "res/mdpi/"), // when res dir is located at the same directory as executable
149 // appendPath(exePath, "../res/mdpi/"), // when res dir is located at project directory
150 // appendPath(exePath, "../../res/mdpi/") // when res dir is located at the same directory as executable
151 //];
152 // setup resource directories - will use only existing directories
153 //Platform.instance.resourceDirs = resourceDirs;
154
155 // embed resources listed in views/resources.list into executable
156 embeddedResourceList.addResources(embedResourcesFromList!("resources.list")());
157
158 //version (USE_OPENGL) {
159 // // you can turn on subpixel font rendering (ClearType) here
160 //FontManager.subpixelRenderingMode = SubpixelRenderingMode.None; //
161 //} else {
162 // you can turn on subpixel font rendering (ClearType) here
163 FontManager.subpixelRenderingMode = SubpixelRenderingMode.BGR; //SubpixelRenderingMode.None; //
164 //}
165
166 // select translation file - for english language
167 Platform.instance.uiLanguage = "en";
168 // load theme from file "theme_default.xml"
169 Platform.instance.uiTheme = "theme_default";
170 //Platform.instance.uiTheme = "theme_dark";
171
172 // you can override default hinting mode here (Normal, AutoHint, Disabled)
173 FontManager.hintingMode = HintingMode.Normal;
174 // you can override antialiasing setting here (0 means antialiasing always on, some big value = always off)
175 // fonts with size less than specified value will not be antialiased
176 FontManager.minAnitialiasedFontSize = 0; // 0 means always antialiased
177 //version (USE_OPENGL) {
178 // // you can turn on subpixel font rendering (ClearType) here
179 FontManager.subpixelRenderingMode = SubpixelRenderingMode.None; //
180 //} else {
181 // you can turn on subpixel font rendering (ClearType) here
182 //FontManager.subpixelRenderingMode = SubpixelRenderingMode.BGR; //SubpixelRenderingMode.None; //
183 //}
184
185 // create window
186 //Window window = Platform.instance.createWindow("DlangUI Example 1", null, WindowFlag.Resizable, 800, 700);
187 // Expand window size if content is bigger than 800, 700 (change to above version if you want scrollbars and 800, 700 size)
188 Window window = Platform.instance.createWindow("DlangUI Example 1", null, WindowFlag.Resizable | WindowFlag.ExpandSize, 800, 700);
189 // here you can see window or content resize mode
190 //Window window = Platform.instance.createWindow("DlangUI Example 1", null, WindowFlag.Resizable, 400, 400);
191 //window.windowOrContentResizeMode = WindowOrContentResizeMode.resizeWindow;
192 //window.windowOrContentResizeMode = WindowOrContentResizeMode.scrollWindow;
193 //window.windowOrContentResizeMode = WindowOrContentResizeMode.shrinkWidgets;
194
195 VerticalLayout contentLayout = new VerticalLayout();
196
197 TabWidget tabs = new TabWidget("TABS");
198 tabs.tabClose = delegate(string tabId) {
199 tabs.removeTab(tabId);
200 };
201
202 //=========================================================================
203 // create main menu
204
205 MainMenu mainMenu = new MainMenu(constructMainMenu());
206 mainMenu.menuItemClick = delegate(MenuItem item) {
207 Log.d("mainMenu.onMenuItemListener", item.label);
208 const Action a = item.action;
209 if (a) {
210 return contentLayout.dispatchAction(a);
211 }
212 return false;
213 };
214 contentLayout.addChild(mainMenu);
215 // to let main menu handle keyboard shortcuts
216 contentLayout.keyToAction = delegate(Widget source, uint keyCode, uint flags) {
217 return mainMenu.findKeyAction(keyCode, flags);
218 };
219 contentLayout.onAction = delegate(Widget source, const Action a) {
220 if (a.id == ACTION_FILE_EXIT) {
221 window.close();
222 return true;
223 } else if (a.id == 31) {
224 window.minimizeWindow();
225 return true;
226 } else if (a.id == 32) {
227 window.maximizeWindow();
228 return true;
229 } else if (a.id == 33) {
230 window.restoreWindow();
231 return true;
232 } else if (a.id == 41) {
233 window.showMessageBox(UIString.fromRaw("About"d), UIString.fromRaw("DLangUI demo app\n(C) Vadim Lopatin, 2014\nhttp://github.com/buggins/dlangui"d));
234 return true;
235 } else if (a.id == ACTION_FILE_OPEN) {
236 UIString caption;
237 caption = "Open Text File"d;
238 FileDialog dlg = new FileDialog(caption, window, null);
239 dlg.allowMultipleFiles = true;
240 dlg.addFilter(FileFilterEntry(UIString("FILTER_ALL_FILES", "All files (*)"d), "*"));
241 dlg.addFilter(FileFilterEntry(UIString("FILTER_TEXT_FILES", "Text files (*.txt)"d), "*.txt"));
242 dlg.addFilter(FileFilterEntry(UIString("FILTER_SOURCE_FILES", "Source files"d), "*.d;*.dd;*.c;*.cc;*.cpp;*.h;*.hpp"));
243 dlg.addFilter(FileFilterEntry(UIString("FILTER_EXECUTABLE_FILES", "Executable files"d), "*", true));
244 //dlg.filterIndex = 2;
245 dlg.dialogResult = delegate(Dialog dlg, const Action result) {
246 if (result.id == ACTION_OPEN.id) {
247 string[] filenames = (cast(FileDialog)dlg).filenames;
248 foreach (filename; filenames) {
249 if (filename.endsWith(".d") || filename.endsWith(".txt") || filename.endsWith(".cpp") || filename.endsWith(".h") || filename.endsWith(".c")
250 || filename.endsWith(".json") || filename.endsWith(".dd") || filename.endsWith(".ddoc") || filename.endsWith(".xml") || filename.endsWith(".html")
251 || filename.endsWith(".html") || filename.endsWith(".css") || filename.endsWith(".log") || filename.endsWith(".hpp")) {
252 // open source file in tab
253 int index = tabs.tabIndex(filename);
254 if (index >= 0) {
255 // file is already opened in tab
256 tabs.selectTab(index, true);
257 } else {
258 SourceEdit editor = new SourceEdit(filename);
259 if (editor.load(filename)) {
260 tabs.addTab(editor, toUTF32(baseName(filename)), null, true);
261 tabs.selectTab(filename);
262 } else {
263 destroy(editor);
264 window.showMessageBox(UIString.fromRaw("File open error"d), UIString.fromRaw("Cannot open file "d ~ toUTF32(filename)));
265 }
266 }
267 } else {
268 Log.d("FileDialog.onDialogResult: ", result, " param=", result.stringParam);
269 window.showMessageBox(UIString.fromRaw("FileOpen result"d), UIString.fromRaw("Filename: "d ~ toUTF32(filename)));
270 }
271 }
272 }
273
274 };
275 dlg.show();
276 return true;
277 }
278 //else
279 //return contentLayout.dispatchAction(a);
280 return false;
281 };
282
283 // Setup tab view
284 tabs.tabChanged = delegate(string newTabId, string oldTabId)
285 {
286 window.windowCaption = tabs.tab(newTabId).text.value ~ " - dlangui example 1"d;
287 };
288 tabs.layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT);
289
290
291 // Add all the example tabs
292 tabs.addTab(new BasicControls("controls"), "Controls"d);
293 tabs.addTab(new MiscExample("tab1"), "Misc"d);
294 tabs.addTab(new LongListsExample("tab2"), "TAB_LONG_LIST"c);
295 tabs.addTab(new ButtonsExample("tab3"), "TAB_BUTTONS"c);
296 tabs.addTab(new TableExample("TABLE"), "TAB_TABLE_LAYOUT"c);
297 tabs.addTab(new EditorsExample("EDITORS"), "TAB_EDITORS"c);
298 tabs.addTab(new GridExample("GRID_CONTENT"), "Grid"d);
299 tabs.addTab(new ScrollExample("SCROLL1"), "Scroll"d);
300 tabs.addTab(new TreeExample("TREE"), "Tree"d);
301 tabs.addTab(new ChartsExample("charts"), "Charts"d);
302 tabs.addTab((new SampleAnimationWidget("tab6")).layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT), "TAB_ANIMATION"c);
303 tabs.addTab(new CanvasExample("canvas"), UIString.fromId("TAB_CANVAS"));
304 tabs.addTab(new IconsExample("icons"), "Icons"d);
305
306 static if (BACKEND_GUI && ENABLE_OPENGL)
307 {
308 tabs.addTab(new OpenGLExample(), "OpenGL"d);
309 }
310
311 //==========================================================================
312
313 contentLayout.addChild(tabs);
314 window.mainWidget = contentLayout;
315
316 tabs.selectTab("controls");
317
318 static if (BACKEND_GUI) {
319 window.windowIcon = drawableCache.getImage("dlangui-logo1");
320 }
321 window.show();
322 //window.windowCaption = "New Window Caption";
323 // run message loop
324
325 Log.i("HOME path: ", homePath);
326 Log.i("APPDATA path: ", appDataPath(".dlangui"));
327 Log.i("Root paths: ", getRootPaths);
328
329 return Platform.instance.enterMessageLoop();
330 }