db7e1a35cd323c89a28f90e05208704261d42051
[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 = formColor;
23
24    virtual void OnGotoError(const char * line, bool noParsing);
25    virtual void OnCodeLocationParseAndGoTo(const 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 = null;
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       if(activeBtn && activeBox)
98       {
99          activeBtn.checked = true;
100          activeBtn.font = { $"Tahoma", 8.25f, bold = true };
101          if(buildBtn != activeBtn) buildBtn.font = null;
102          if(debugBtn != activeBtn) debugBtn.font = null;
103          if(findBtn != activeBtn) findBtn.font = null;
104 #ifdef GDB_DEBUG_OUTPUT
105          if(gdbBtn != activeBtn) gdbBtn.font = null;
106 #endif
107
108          activeBox.visible = false;
109          activeBtn.Activate();      // Ensure proper cycling (until tab order?)
110          activeBox.visible = true;
111          activeBox.Activate();
112          findDialog.editBox = activeBox;
113       }
114    }
115
116    EditBox activeBox;
117    activeBox = buildBox;
118
119    LogBox buildBox
120    {
121       parent = this, freeCaret = true, autoEmpty = true, multiLine = true;
122       readOnly = true, hasVertScroll = true, hasHorzScroll = true;
123       anchor = Anchor { left = 0, right = 0, top = 23, bottom = 0 };
124       /*
125       font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
126       background = colorScheme.outputBackground;
127       foreground = colorScheme.outputText;
128       selectionColor = colorScheme.selectionColor;
129       selectionText = colorScheme.selectionText;
130       */
131
132       bool NotifyDoubleClick(EditBox editBox, EditLine line, Modifiers mods)
133       {
134          OnGotoError(editBox.line.text, mods.ctrl && mods.shift);
135          return false;
136       }
137
138       bool NotifyKeyDown(EditBox editBox, Key key, unichar ch)
139       {
140          if(key.code == enter || key.code == keyPadEnter)
141          {
142             OnGotoError(editBox.line.text, key.ctrl && key.shift);
143             return false;
144          }
145          return true;
146       }
147    };
148
149    LogBox debugBox
150    {
151       parent = this, freeCaret = true, autoEmpty = true, multiLine = true;
152       readOnly = true, hasVertScroll = true, hasHorzScroll = true, visible = false;
153       anchor = Anchor { left = 0, right = 0, top = 23, bottom = 0 };
154       /*
155       font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
156       background = colorScheme.outputBackground;
157       foreground = colorScheme.outputText;
158       selectionColor = colorScheme.selectionColor;
159       selectionText = colorScheme.selectionText;
160       */
161
162       bool NotifyDoubleClick(EditBox editBox, EditLine line, Modifiers mods)
163       {
164          OnCodeLocationParseAndGoTo(editBox.line.text);
165          return false;
166       }
167
168       bool NotifyKeyDown(EditBox editBox, Key key, unichar ch)
169       {
170          if((SmartKey)key == enter)
171          {
172             OnCodeLocationParseAndGoTo(editBox.line.text);
173             return false;
174          }
175          return true;
176       }
177    };
178
179    LogBox findBox
180    {
181       parent = this, freeCaret = true, autoEmpty = true, multiLine = true;
182       readOnly = true, hasVertScroll = true, hasHorzScroll = true, visible = false;
183       anchor = Anchor { left = 0, right = 0, top = 23, bottom = 0 };
184       /*
185       font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
186       background = colorScheme.outputBackground;
187       foreground = colorScheme.outputText;
188       selectionColor = colorScheme.selectionColor;
189       selectionText = colorScheme.selectionText;
190       */
191
192       bool NotifyDoubleClick(EditBox editBox, EditLine line, Modifiers mods)
193       {
194          OnCodeLocationParseAndGoTo(editBox.line.text);
195          return false;
196       }
197
198       bool NotifyKeyDown(EditBox editBox, Key key, unichar ch)
199       {
200          if((SmartKey)key == enter)
201          {
202             OnCodeLocationParseAndGoTo(editBox.line.text);
203             return false;
204          }
205          return true;
206       }
207    };
208
209 #ifdef GDB_DEBUG_OUTPUT
210    LogBox gdbBox
211    {
212       parent = this, freeCaret = true, autoEmpty = true, multiLine = true;
213       readOnly = true, hasVertScroll = true, hasHorzScroll = true, visible = false;
214       anchor = Anchor { left = 0, right = 0, top = 23, bottom = 0 };
215       font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
216       background = colorScheme.outputBackground;
217       foreground = colorScheme.outputText;
218       selectionColor = colorScheme.selectionColor;
219       selectionText = colorScheme.selectionText;
220    };
221 #endif
222
223    Menu editMenu { menu, $"Edit", e };
224
225    MenuItem item;
226    MenuItem copyItem
227    {
228       editMenu, $"Copy", c, ctrlC;
229       bool NotifySelect(MenuItem selection, Modifiers mods)
230       {
231          activeBox.Copy();
232          return true;
233       }
234    };
235    MenuDivider { editMenu };
236    MenuItem { editMenu, $"Find Previous", e, Key { f3, shift = true }, NotifySelect = MenuEditFind, id = 0 };
237    MenuItem { editMenu, $"Find Next", n, f3, NotifySelect = MenuEditFind, id = 1 };
238    MenuItem { editMenu, $"Find", f, ctrlF, NotifySelect = MenuEditFind, id = 2 };
239
240    bool MenuEditFind(MenuItem selection, Modifiers mods)
241    {
242       int64 id = selection.id;
243       const char * searchString = findDialog.searchString;
244       if(id != 2 && searchString[0])
245       {
246          activeBox.Find(searchString, findDialog.wholeWord, findDialog.matchCase, id != 0);
247          return true;
248       }
249       findDialog.Create();
250       return true;
251    }
252
253    void Show()
254    {
255       visible = true;
256       ide.RepositionWindows(false);
257       Activate();
258    }
259    void ShowClearSelectTab(OutputViewTab tab)
260    {
261       Show();
262       if(tab == build)
263          buildBox.Clear();
264       else if(tab == debug)
265          debugBox.Clear();
266       else if(tab == find)
267       {
268          findBox.Clear();
269       }
270 #ifdef GDB_DEBUG_OUTPUT
271       else if(tab == gdb)
272          gdbBox.Clear();
273 #endif
274       SelectTab(tab);
275    }
276
277    bool OnKeyDown(Key key, unichar ch)
278    {
279       switch(key)
280       {
281          case shiftTab:
282          {
283             OutputViewTab switchTo = build;
284             if(activeBox == buildBox)
285 #ifdef GDB_DEBUG_OUTPUT
286                switchTo = gdb;
287 #else
288                switchTo = find;
289 #endif
290             else if(activeBox == debugBox)
291                switchTo = build;
292             else if(activeBox == findBox)
293                switchTo = debug;
294 #ifdef GDB_DEBUG_OUTPUT
295             else if(activeBox == gdbBox)
296                switchTo = build;
297 #endif
298             SelectTab(switchTo);
299             break;
300          }
301          case tab:
302          {
303             OutputViewTab switchTo = debug;
304             if(activeBox == buildBox)
305                switchTo = debug;
306             else if(activeBox == debugBox)
307                switchTo = find;
308             else if(activeBox == findBox)
309 #ifdef GDB_DEBUG_OUTPUT
310                switchTo = gdb;
311             else if(activeBox == gdbBox)
312 #endif
313                switchTo = build;
314             SelectTab(switchTo);
315             break;
316          }
317       }
318       return true;
319    }
320 }
321
322 class LogBox : EditBox
323 {
324    bool moved, logging, tell;
325
326    void Logf(const char * format, ...)
327    {
328       char string[MAX_F_STRING*10];
329       va_list args;
330       va_start(args, format);
331       vsnprintf(string, sizeof(string), format, args);
332       string[sizeof(string)-1] = 0;
333       va_end(args);
334
335       LogRaw(string);
336    }
337
338    void LogRaw(const char * entry)
339    {
340       // Cut the line longer than 1024 because Logf prints to a buffer (and we don't want to output crazy long lines either)
341       //if(len > 1023) line[1023] = '\0';
342       /* Fixed, but disabled this ... Not sure if there's any reason to keep it? The EditBox should be fine with long lines
343          and it's easier to copy commands and go to errors */
344       /*int len = strlen(entry);
345       if(len > 1023)
346       {
347          char * newStart, * start = entry;
348
349          while(len > 1023)
350          {
351             char backup[3];
352             newStart = start + 1020;
353             strncpy(backup, newStart, 3);
354             strncpy(newStart, "\n ", 3);
355             Log(start);
356             strncpy(newStart, backup, 3);
357             start = newStart;
358             len = strlen(start);
359          }
360          Log(start);
361       }
362       else*/
363          Log(entry);
364    }
365
366    void Log(const char * string)
367    {
368       int x1, y1, x2, y2;
369       Point scrl;
370       EditLine line1;
371       EditLine line2;
372       logging = true;
373       if(moved)
374       {
375          GetSelPos(&line1, &y1, &x1, &line2, &y2, &x2, false);
376          scrl = scroll;
377       }
378       End();
379       if(tell)
380       {
381          ClearLine();
382          tell = false;
383       }
384       PutS(string);
385       Update(null);
386       if(moved)
387       {
388          scroll = scrl;
389          SetSelPos(line1, y1, x1, line2, y2, x2);
390       }
391       logging = false;
392    }
393
394    void Tellf(const char * format, ...)
395    {
396       char string[MAX_F_STRING*10];
397       va_list args;
398       va_start(args, format);
399       vsnprintf(string, sizeof(string), format, args);
400       string[sizeof(string)-1] = 0;
401       va_end(args);
402
403       Tell(string);
404    }
405
406    void Tell(const char * string)
407    {
408       Log(string);
409       if(!moved)
410       {
411          Point caretPos;
412          GetCaretPosition(caretPos);
413          SetCaret(0, caretPos.y, GetCaretSize());
414       }
415       tell = true;
416    }
417
418    void Clear()
419    {
420       EditBox::Clear();
421       moved = false;
422    }
423
424    void NotifyCaretMove(EditBox editBox, int line, int charPos)
425    {
426       LogBox logBox = (LogBox)editBox;
427       if(!logBox.logging)
428       {
429          int y1, y2;
430          logBox.GetSelPos(null, &y1, null, null, &y2, null, false);
431          logBox.moved = (y1 == logBox.numLines - 1 && y2 == y1) ? false : true;
432       }
433    }
434 }