1 module dlangide.ui.frame;
2 
3 import dlangui.widgets.menu;
4 import dlangui.widgets.tabs;
5 import dlangui.widgets.layouts;
6 import dlangui.widgets.editors;
7 import dlangui.widgets.srcedit;
8 import dlangui.widgets.controls;
9 import dlangui.widgets.appframe;
10 import dlangui.widgets.docks;
11 import dlangui.widgets.toolbars;
12 import dlangui.dialogs.dialog;
13 import dlangui.dialogs.filedlg;
14 
15 import dlangide.ui.commands;
16 import dlangide.ui.wspanel;
17 import dlangide.ui.outputpanel;
18 import dlangide.workspace.workspace;
19 import dlangide.workspace.project;
20 
21 import ddc.lexer.textsource;
22 import ddc.lexer.exceptions;
23 import ddc.lexer.tokenizer;
24 
25 import std.conv;
26 import std.utf;
27 import std.algorithm;
28 
29 /// DIDE app frame
30 class IDEFrame : AppFrame {
31 
32     MenuItem mainMenuItems;
33     WorkspacePanel _wsPanel;
34     OutputPanel _logPanel;
35     DockHost _dockHost;
36     TabWidget _tabs;
37 
38     this(Window window) {
39         super();
40         window.mainWidget = this;
41     }
42 
43     override protected void init() {
44         super.init();
45     }
46 
47     /// move focus to editor in currently selected tab
48     void focusEditor(string id) {
49         Widget w = _tabs.tabBody(id);
50         if (w) {
51             if (w.visible)
52                 w.setFocus();
53         }
54     }
55 
56     /// source file selected in workspace tree
57     bool onSourceFileSelected(ProjectSourceFile file, bool activate) {
58         Log.d("onSourceFileSelected ", file.filename);
59         int index = _tabs.tabIndex(file.filename);
60         if (index >= 0) {
61             // file is already opened in tab
62             _tabs.selectTab(index, true);
63         } else {
64             // open new file
65             DSourceEdit editor = new DSourceEdit(file.filename);
66             if (editor.load(file)) {
67                 _tabs.addTab(editor, toUTF32(file.name));
68                 index = _tabs.tabIndex(file.filename);
69                 TabItem tab = _tabs.tab(file.filename);
70                 tab.objectParam = file;
71                 _tabs.selectTab(index, true);
72             } else {
73                 destroy(editor);
74                 if (window)
75                     window.showMessageBox(UIString("File open error"d), UIString("Failed to open file "d ~ toUTF32(file.filename)));
76                 return false;
77             }
78         }
79         if (activate) {
80             focusEditor(file.filename);
81         }
82         requestLayout();
83         return true;
84     }
85 
86     void onTabChanged(string newActiveTabId, string previousTabId) {
87         int index = _tabs.tabIndex(newActiveTabId);
88         if (index >= 0) {
89             TabItem tab = _tabs.tab(index);
90             ProjectSourceFile file = cast(ProjectSourceFile)tab.objectParam;
91             if (file) {
92                 // tab is source file editor
93                 _wsPanel.selectItem(file);
94                 focusEditor(file.filename);
95             }
96         }
97     }
98 
99     /// create app body widget
100     override protected Widget createBody() {
101         _dockHost = new DockHost();
102 
103         //=============================================================
104         // Create body - Tabs
105 
106         // editor tabs
107         _tabs = new TabWidget("TABS");
108         _tabs.setStyles(STYLE_DOCK_HOST_BODY, STYLE_TAB_UP_DARK, STYLE_TAB_UP_BUTTON_DARK, STYLE_TAB_UP_BUTTON_DARK_TEXT);
109         _tabs.onTabChangedListener = &onTabChanged;
110         
111         _dockHost.bodyWidget = _tabs;
112 
113         //=============================================================
114         // Create workspace docked panel
115         _wsPanel = new WorkspacePanel("workspace");
116         _wsPanel.sourceFileSelectionListener = &onSourceFileSelected;
117         _dockHost.addDockedWindow(_wsPanel);
118 
119         _logPanel = new OutputPanel("output");
120         _logPanel.addLogLines(null, "Line 1"d);
121         _logPanel.addLogLines(null, "Line 2"d);
122         _logPanel.addLogLines(null, "Line 3"d, "Line 4"d);
123 
124         _dockHost.addDockedWindow(_logPanel);
125 
126         return _dockHost;
127     }
128 
129     /// create main menu
130     override protected MainMenu createMainMenu() {
131 
132         mainMenuItems = new MenuItem();
133         MenuItem fileItem = new MenuItem(new Action(1, "MENU_FILE"));
134         fileItem.add(ACTION_FILE_NEW, ACTION_FILE_OPEN, ACTION_FILE_SAVE, ACTION_FILE_EXIT);
135 
136         MenuItem editItem = new MenuItem(new Action(2, "MENU_EDIT"));
137 		editItem.add(ACTION_EDIT_COPY, ACTION_EDIT_PASTE, ACTION_EDIT_CUT, ACTION_EDIT_UNDO, ACTION_EDIT_REDO);
138 
139 		editItem.add(new Action(20, "MENU_EDIT_PREFERENCES"));
140 		MenuItem windowItem = new MenuItem(new Action(3, "MENU_WINDOW"c));
141         windowItem.add(new Action(30, "MENU_WINDOW_PREFERENCES"));
142         MenuItem helpItem = new MenuItem(new Action(4, "MENU_HELP"c));
143         helpItem.add(new Action(40, "MENU_HELP_VIEW_HELP"));
144 		MenuItem aboutItem = new MenuItem(new Action(ACTION_HELP_ABOUT, "MENU_HELP_ABOUT"));
145         helpItem.add(aboutItem);
146 		aboutItem.onMenuItemClick = delegate(MenuItem item) {
147 			Window wnd = Platform.instance.createWindow("About...", window, WindowFlag.Modal);
148 			wnd.mainWidget = createAboutWidget();
149 			wnd.show();
150 			return true;
151 		};
152         mainMenuItems.add(fileItem);
153         mainMenuItems.add(editItem);
154 		//mainMenuItems.add(viewItem);
155 		mainMenuItems.add(windowItem);
156         mainMenuItems.add(helpItem);
157 
158         MainMenu mainMenu = new MainMenu(mainMenuItems);
159         mainMenu.backgroundColor = 0xd6dbe9;
160         return mainMenu;
161     }
162 	
163     /// create app toolbars
164     override protected ToolBarHost createToolbars() {
165         ToolBarHost res = new ToolBarHost();
166         ToolBar tb;
167         tb = res.getOrAddToolbar("Standard");
168         tb.addButtons(ACTION_FILE_OPEN, ACTION_FILE_SAVE, ACTION_SEPARATOR, 
169                       ACTION_EDIT_COPY, ACTION_EDIT_PASTE, ACTION_EDIT_CUT);
170         return res;
171     }
172 
173     /// override to handle specific actions
174 	override bool handleAction(const Action a) {
175         if (a) {
176             switch (a.id) {
177                 case IDEActions.FileExit:
178                     return true;
179                 case ACTION_HELP_ABOUT:
180                     Window wnd = Platform.instance.createWindow("About...", window, WindowFlag.Modal);
181                     wnd.mainWidget = createAboutWidget();
182                     wnd.show();
183                     return true;
184                 case IDEActions.FileOpen:
185                     UIString caption;
186                     caption = "Open Text File"d;
187                     FileDialog dlg = new FileDialog(caption, window, null);
188                     dlg.onDialogResult = delegate(Dialog dlg, const Action result) {
189                         //
190                     };
191                     dlg.show();
192                     return true;
193                 default:
194                     if (window.focusedWidget)
195                         return window.focusedWidget.handleAction(a);
196                     else
197                         return handleAction(a);
198             }
199         }
200 		return false;
201 	}
202 
203     bool loadWorkspace(string path) {
204         // testing workspace loader
205         Workspace ws = new Workspace();
206         ws.load(path);
207         currentWorkspace = ws;
208         _wsPanel.workspace = ws;
209         return true;
210     }
211 }
212 
213 Widget createAboutWidget() 
214 {
215 	LinearLayout res = new VerticalLayout();
216 	res.padding(Rect(10,10,10,10));
217 	res.addChild(new TextWidget(null, "DLangIDE"d));
218 	res.addChild(new TextWidget(null, "(C) Vadim Lopatin, 2014"d));
219 	res.addChild(new TextWidget(null, "http://github.com/buggins/dlangide"d));
220 	res.addChild(new TextWidget(null, "So far, it's just a test for DLangUI library."d));
221 	res.addChild(new TextWidget(null, "Later I hope to make working IDE :)"d));
222 	Button closeButton = new Button("close", "Close"d);
223 	closeButton.onClickListener = delegate(Widget src) {
224 		Log.i("Closing window");
225 		res.window.close();
226 		return true;
227 	};
228 	res.addChild(closeButton);
229 	return res;
230 }