ecere: embellished menu bar; ide: centralized font selection
[sdk] / ide / src / panels / OutputView.ec
1 #include <stdarg.h>
2
3 import "ecere"
4 import "CodeEditor"
5
6 enum OutputViewTab { build, debug, find
7 #ifdef GDB_DEBUG_OUTPUT
8 , gdb
9 #endif
10 };
11
12 class OutputView : Window
13 {
14    visible = false;
15    borderStyle = sizable;
16    hasClose = true;
17    mergeMenus = false;
18    text = "Output";
19    menu = Menu { };
20    anchor = Anchor { left = 0, right = 0, bottom = 0 };
21    size.h = 240;
22    background = activeBorder;
23
24    virtual void OnGotoError(char * line);
25    virtual void OnCodeLocationParseAndGoTo(char * line);
26
27    FindDialog findDialog { master = this, editBox = buildBox, isModal = true, autoCreate = false, text = "Find" };
28
29    Button buildBtn
30    {
31       this, inactive = true, text = "Build", bevelOver = true, isRadio = true, bitmap = null, checked = true;
32       size = { 99, 20 };
33       anchor = { left = 0, top = 1 };
34       font = { "Tahoma", 8.25f, bold = true };
35
36       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
37       {
38          SelectTab(build);
39          return true;
40       }
41    };
42    
43    Button debugBtn
44    {
45       this, inactive = true, text = "Debug", bevelOver = true, isRadio = true, bitmap = null;
46       size = { 99, 20 };
47       anchor = { left = 100, top = 1 };
48
49       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
50       {
51          SelectTab(debug);
52          return true;
53       }
54    };
55    
56    Button findBtn
57    {
58       this, inactive = true, text = "Find", bevelOver = true, isRadio = true, bitmap = null;
59       size = { 99, 20 };
60       anchor = { left = 200, top = 1 };
61
62       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
63       {
64          SelectTab(find);
65          return true;
66       }
67    };
68
69 #ifdef GDB_DEBUG_OUTPUT
70    Button gdbBtn
71    {
72       this, inactive = true, text = "GDB", bevelOver = true, isRadio = true, bitmap = null;
73       size = { 99, 20 };
74       anchor = { left = 300, top = 1 };
75
76       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
77       {
78          SelectTab(gdb);
79          return true;
80       }
81    };
82 #endif
83
84    void SelectTab(OutputViewTab tab)
85    {
86       Button activeBtn;
87       if(tab == build)
88          activeBtn = buildBtn, activeBox = buildBox;
89       else if(tab == debug)
90          activeBtn = debugBtn, activeBox = debugBox;
91       else if(tab == find)
92          activeBtn = findBtn, activeBox = findBox;
93 #ifdef GDB_DEBUG_OUTPUT
94       else if(tab == gdb)
95          activeBtn = gdbBtn, activeBox = gdbBox;
96 #endif
97
98       activeBtn.checked = true;
99       activeBtn.font = { "Tahoma", 8.25f, bold = true };
100       if(buildBtn != activeBtn) buildBtn.font = null;
101       if(debugBtn != activeBtn) debugBtn.font = null;
102       if(findBtn != activeBtn) findBtn.font = null;
103 #ifdef GDB_DEBUG_OUTPUT
104       if(gdbBtn != activeBtn) gdbBtn.font = null;
105 #endif
106
107       activeBox.visible = false;
108       activeBtn.Activate();      // Ensure proper cycling (until tab order?)
109       activeBox.visible = true;
110       activeBox.Activate();
111       findDialog.editBox = activeBox;
112    }
113
114    EditBox activeBox;
115    
116    LogBox buildBox
117    {
118       parent = this, freeCaret = true, autoEmpty = true, multiLine = true;
119       readOnly = true, hasVertScroll = true, hasHorzScroll = true;
120       anchor = Anchor { left = 0, right = 0, top = 23, bottom = 0 };
121       font = { panelFont.faceName, panelFont.size };
122       background = outputBackground;
123       foreground = outputText;
124       selectionColor = selectionColor, selectionText = selectionText;
125       
126       bool NotifyDoubleClick(EditBox editBox, EditLine line, Modifiers mods)
127       {
128          OnGotoError(editBox.line.text);
129          return false; //true; // why not use true here? 
130       }
131
132       bool NotifyKeyDown(EditBox editBox, Key key, unichar ch)
133       {
134          if((SmartKey)key == enter)
135          {
136             OnGotoError(editBox.line.text);
137             return false;
138          }
139          return true;
140       }
141    };
142    
143    LogBox debugBox
144    {
145       parent = this, freeCaret = true, autoEmpty = true, multiLine = true;
146       readOnly = true, hasVertScroll = true, hasHorzScroll = true, visible = false;
147       anchor = Anchor { left = 0, right = 0, top = 23, bottom = 0 };
148       font = { panelFont.faceName, panelFont.size };
149       background = outputBackground;
150       foreground = outputText;
151       selectionColor = selectionColor, selectionText = selectionText;
152    };
153    
154    LogBox findBox
155    {
156       parent = this, freeCaret = true, autoEmpty = true, multiLine = true;
157       readOnly = true, hasVertScroll = true, hasHorzScroll = true, visible = false;
158       anchor = Anchor { left = 0, right = 0, top = 23, bottom = 0 };
159       font = { panelFont.faceName, panelFont.size };
160       background = outputBackground;
161       foreground = outputText;
162       selectionColor = selectionColor, selectionText = selectionText;
163
164       bool NotifyDoubleClick(EditBox editBox, EditLine line, Modifiers mods)
165       {
166          OnCodeLocationParseAndGoTo(editBox.line.text);
167          return false; //true;
168       }
169
170       bool NotifyKeyDown(EditBox editBox, Key key, unichar ch)
171       {
172          if((SmartKey)key == enter)
173          {
174             OnCodeLocationParseAndGoTo(editBox.line.text);
175             return false;
176          }
177          return true;
178       }
179    };
180
181 #ifdef GDB_DEBUG_OUTPUT
182    LogBox gdbBox
183    {
184       parent = this, freeCaret = true, autoEmpty = true, multiLine = true;
185       readOnly = true, hasVertScroll = true, hasHorzScroll = true, visible = false;
186       anchor = Anchor { left = 0, right = 0, top = 23, bottom = 0 };
187       font = { panelFont.faceName, panelFont.size };
188    };
189 #endif
190    
191    Menu editMenu { menu, "Edit", e };
192
193    MenuItem item;
194    MenuItem copyItem
195    {
196       editMenu, "Copy", c, ctrlC;
197       bool NotifySelect(MenuItem selection, Modifiers mods)
198       {
199          activeBox.Copy();
200          return true;
201       }
202    };
203    MenuDivider { editMenu };
204    MenuItem { editMenu, "Find Previous", e, Key { f3, shift = true }, NotifySelect = MenuEditFind, id = 0 };
205    MenuItem { editMenu, "Find Next", n, f3, NotifySelect = MenuEditFind, id = 1 };
206    MenuItem { editMenu, "Find", f, ctrlF, NotifySelect = MenuEditFind, id = 2 };
207
208    bool MenuEditFind(MenuItem selection, Modifiers mods)
209    {
210       int id = selection.id;
211       char * searchString = findDialog.searchString;
212       if(id != 2 && searchString[0])
213       {
214          activeBox.Find(searchString, findDialog.wholeWord, findDialog.matchCase, id);
215          return true;
216       }
217       findDialog.Create();
218       return true;
219    }
220
221    void Show()
222    {
223       visible = true;
224       Activate();
225    }
226    void ShowClearSelectTab(OutputViewTab tab)
227    {
228       Show();
229       if(tab == build)
230          buildBox.Clear();
231       else if(tab == debug)
232          debugBox.Clear();
233       else if(tab == find)
234       {
235          findBox.Clear();
236       }
237 #ifdef GDB_DEBUG_OUTPUT
238       else if(tab == gdb)
239          gdbBox.Clear();
240 #endif
241       SelectTab(tab);
242    }
243
244    bool OnKeyDown(Key key, unichar ch)
245    {
246       switch(key)
247       {
248          case shiftTab:
249          {
250             OutputViewTab switchTo;
251             if(activeBox == buildBox)
252 #ifdef GDB_DEBUG_OUTPUT
253                switchTo = gdb;
254 #else
255                switchTo = find;
256 #endif
257             else if(activeBox == debugBox)
258                switchTo = build;
259             else if(activeBox == findBox)
260                switchTo = debug;
261 #ifdef GDB_DEBUG_OUTPUT
262             else if(activeBox == gdbBox)
263                switchTo = build;
264 #endif
265             SelectTab(switchTo);
266             break;
267          }
268          case tab:
269          {
270             OutputViewTab switchTo;
271             if(activeBox == buildBox)
272                switchTo = debug;
273             else if(activeBox == debugBox)
274                switchTo = find;
275             else if(activeBox == findBox)
276 #ifdef GDB_DEBUG_OUTPUT
277                switchTo = gdb;
278             else if(activeBox == gdbBox)
279 #endif
280                switchTo = build;
281             SelectTab(switchTo);
282             break;
283          }
284       }
285       return true;
286    }
287 }
288
289 class LogBox : EditBox
290 {
291    bool moved, logging, tell;
292
293    void Logf(char * format, ...)
294    {
295       char string[MAX_F_STRING*10];
296
297       va_list args;
298       va_start(args, format);
299       vsprintf(string, format, args);
300       va_end(args);
301
302       LogRaw(string);
303    }
304
305    void LogSprintf(char * entry)
306    {
307       char string[MAX_F_STRING];
308       sprintf(string, entry);
309       LogRaw(string);
310    }
311
312    void LogRaw(char * entry)
313    {
314       // Cut the line longer than 1024 because Logf prints to a buffer (and we don't want to output crazy long lines either)
315       //if(len > 1023) line[1023] = '\0';
316       int len = strlen(entry);
317       if(len > 1023)
318       {
319          char backup[4];
320          char * newStart, * start = entry;
321          
322          while(len > 1023)
323          {
324             newStart = start + 1020;
325             strncpy(backup, newStart, 4);
326             strncpy(newStart, " \\ \0", 4);
327             Log(start);
328             strncpy(newStart, backup, 4);
329             start = newStart;
330             len = strlen(start);
331          }
332          
333          //while((len = strlen(start)) > 1023)
334          
335       }
336       else
337          Log(entry);
338    }
339
340    void Log(char * string)
341    {
342       int x1, y1, x2, y2;
343       Point scrl;
344       EditLine line1;
345       EditLine line2;
346       logging = true;
347       if(moved)
348       {
349          GetSelPos(&line1, &y1, &x1, &line2, &y2, &x2, false);
350          scrl = scroll;
351       }
352       End();
353       if(tell)
354       {
355          ClearLine();
356          tell = false;
357       }
358       PutS(string);
359       Update(null);
360       if(moved)
361       {
362          scroll = scrl;
363          SetSelPos(line1, y1, x1, line2, y2, x2);
364       }
365       logging = false;
366    }
367
368    void Tellf(char * format, ...)
369    {
370       char string[MAX_F_STRING*10];
371
372       va_list args;
373       va_start(args, format);
374       vsprintf(string, format, args);
375       va_end(args);
376
377       Tell(string);
378    }
379
380    void Tell(char * string)
381    {
382       Log(string);
383       if(!moved)
384       {
385          Point caretPos;
386          GetCaretPosition(caretPos);
387          SetCaret(0, caretPos.y, GetCaretSize());
388       }
389       tell = true;
390    }
391
392    void Clear()
393    {
394       EditBox::Clear();
395       moved = false;
396    }
397
398    void NotifyCaretMove(EditBox editBox, int line, int charPos)
399    {
400       LogBox logBox = (LogBox)editBox;
401       if(!logBox.logging)
402       {
403          int y1, y2;
404          logBox.GetSelPos(null, &y1, null, null, &y2, null, false);
405          logBox.moved = (y1 == logBox.numLines - 1 && y2 == y1) ? false : true;
406       }
407    }
408 }