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