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