ide/Project/epj monitoring: Added support for notifying of modification of added...
[sdk] / ide / src / ide.ec
1 #ifdef ECERE_STATIC
2 public import static "ecere"
3 public import static "ec"
4 #else
5 public import "ecere"
6 public import "ec"
7 #endif
8
9 import "GlobalSettingsDialog"
10 import "NewProjectDialog"
11 import "FindInFilesDialog"
12 import "ActiveCompilerDialog"
13
14 #ifdef GDB_DEBUG_GUI
15 import "GDBDialog"
16 #endif
17
18 import "Project"
19 import "ProjectActiveConfig"
20 import "ProjectConfig"
21 import "ProjectNode"
22 import "NodeProperties"
23 import "ProjectSettings"
24 import "ProjectView"
25 import "Workspace"
26
27 import "CodeEditor"
28 import "Designer"
29 import "ToolBox"
30 import "Sheet"
31
32 import "Debugger"
33
34 import "OutputView"
35 import "BreakpointsView"
36 import "CallStackView"
37 import "ThreadsView"
38 import "WatchesView"
39
40 #ifndef NO3D
41 import "ModelView"
42 #endif
43 import "PictureEdit"
44
45 import "about"
46
47 import "FileSystemIterator"
48
49 #if defined(__WIN32__)
50 define pathListSep = ";";
51 #else
52 define pathListSep = ":";
53 #endif
54
55 define maxPathLen = 65 * MAX_LOCATION;
56
57 class PathBackup : struct
58 {
59    String oldLDPath;
60    String oldPath;
61
62    PathBackup()
63    {
64       oldPath = new char[maxPathLen];
65       oldLDPath = new char[maxPathLen];
66
67       GetEnvironment("PATH", oldPath, maxPathLen);
68 #if defined(__APPLE__)
69       GetEnvironment("DYLD_LIBRARY_PATH", oldLDPath, maxPathLen);
70 #else
71       GetEnvironment("LD_LIBRARY_PATH", oldLDPath, maxPathLen);
72 #endif
73    }
74
75    ~PathBackup()
76    {
77       SetEnvironment("PATH", oldPath);
78 #if defined(__APPLE__)
79       SetEnvironment("DYLD_LIBRARY_PATH", oldLDPath);
80 #else
81       SetEnvironment("LD_LIBRARY_PATH", oldLDPath);
82 #endif
83       delete oldPath;
84       delete oldLDPath;
85    }
86 };
87
88 enum OpenCreateIfFails { no, yes, something, whatever };
89 enum OpenMethod { normal, add };
90
91 static Array<FileFilter> fileFilters
92 { [
93    { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
94    { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
95    { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
96    { $"Text files (*.txt, *.text, *.nfo, *.info)", "txt, text, nfo, info" },
97    { $"Web files (*.html, *.htm, *.xhtml, *.css, *.php, *.js, *.jsi, *.rb, *.xml)", "html, htm, xhtml, css, php, js, jsi, rb, xml" },
98    { $"Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", "jpg, jpeg, bmp, pcx, png, gif" },
99    { $"3D Studio Model Files (*.3ds)", "3ds" },
100    { $"All files", null }
101 ] };
102
103 static Array<FileType> fileTypes
104 { [
105    { $"Based on extension", null },
106    { $"Text",               "txt" },
107    { $"Image",              "jpg" },
108    { $"3D Studio Model",    "3ds" }
109 ] };
110
111 static Array<FileFilter> projectFilters
112 { [
113    { $"Project Files (*.epj)", ProjectExtension }
114 ] };
115
116 static Array<FileType> projectTypes
117 { [
118    { $"Project File", ProjectExtension }
119 ] };
120
121 static Array<FileFilter> findInFilesFileFilters
122 { [
123    { $"eC Files (*.ec, *.eh)", "ec, eh" },
124    { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
125    { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
126    { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
127    { $"Text files (*.txt)", "txt" },
128    { $"All files", null }
129 ] };
130
131 FileDialog ideFileDialog
132 {
133    type = multiOpen, text = $"Open";
134    types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType), filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter);
135 };
136
137 define openProjectFileDialogTitle = $"Open Project";
138 define addProjectFileDialogTitle = $"Open Additional Project";
139 FileDialog ideProjectFileDialog
140 {
141    type = open;
142    types = projectTypes.array, sizeTypes = projectTypes.count * sizeof(FileType), filters = projectFilters.array, sizeFilters = projectFilters.count * sizeof(FileFilter);
143 };
144
145 GlobalSettingsDialog globalSettingsDialog
146 {
147    ideSettings = ideSettings;
148    settingsContainer = settingsContainer;
149
150    void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange)
151    {
152       switch(globalSettingsChange)
153       {
154          case editorSettings:
155          {
156             Window child;
157             for(child = ide.firstChild; child; child = child.next)
158             {
159                if(child._class == class(CodeEditor))
160                {
161                   CodeEditor codeEditor = (CodeEditor) child;
162                   codeEditor.editBox.freeCaret = ideSettings.useFreeCaret;
163                   // codeEditor.editBox.lineNumbers = ideSettings.showLineNumbers;
164                   codeEditor.editBox.caretFollowsScrolling = ideSettings.caretFollowsScrolling;
165                   codeEditor.OnPostCreate(); // Update editBox margin size
166                }
167             }
168             break;
169          }
170          case projectOptions:
171             break;
172          case compilerSettings:
173          {
174             ide.UpdateMakefiles();
175             break;
176          }
177       }
178    }
179 };
180
181 void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
182 {
183    int lineY;
184    if(line)
185    {
186       lineY = (line - 1) * lineH;
187       if(lineY + lineH > scrollY && lineY + lineH < scrollY + boxH)
188       {
189          Bitmap bitmap = resource.bitmap;
190          if(bitmap)
191             surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
192       }
193    }
194 }
195
196 #define IDEItem(x)   (&((IDEWorkSpace)0).x)
197
198 class IDEToolbar : ToolBar
199 {
200    /* File options */
201    // New
202    ToolButton buttonNewFile { this, toolTip = $"New file", menuItemPtr = IDEItem(fileNewItem) };
203    // Open
204    ToolButton buttonOpenFile { this, toolTip = $"Open file", menuItemPtr = IDEItem(fileOpenItem) };
205    // Close
206    // ToolButton buttonCloseFile { this, toolTip = $"Close file", menuItemPtr = IDEItem(fileCloseItem) };
207    // Save
208    ToolButton buttonSaveFile { this, toolTip = $"Save file", menuItemPtr = IDEItem(fileSaveItem) };
209    // Save All
210    ToolButton buttonSaveAllFile { this, toolTip = $"Save all", menuItemPtr = IDEItem(fileSaveAllItem) };
211
212    ToolSeparator separator1 { this };
213
214    /* Edit options */
215    // Cut
216    // Copy 
217    // Paste
218    // Undo
219    // Redo
220
221    // ToolSeparator separator2 { this };
222
223    /* Project  options */
224    // New project
225    ToolButton buttonNewProject { this, toolTip = $"New project", menuItemPtr = IDEItem(projectNewItem) };
226    // Open project
227    ToolButton buttonOpenProject { this, toolTip = $"Open project", menuItemPtr = IDEItem(projectOpenItem) };
228    // Add project to workspace
229    ToolButton buttonAddProject { this, toolTip = $"Add project to workspace", menuItemPtr = IDEItem(projectAddItem), disabled = true; };
230    // Close project
231    // ToolButton buttonCloseProject { this, toolTip = $"Close project", menuItemPtr = IDEItem(projectCloseItem), disabled = true; };
232
233    ToolSeparator separator3 { this };
234
235    /* Build/Execution options */
236    // Build
237    ToolButton buttonBuild { this, toolTip = $"Build project", menuItemPtr = IDEItem(projectBuildItem), disabled = true; };
238    // Re-link
239    ToolButton buttonReLink { this, toolTip = $"Relink project", menuItemPtr = IDEItem(projectLinkItem), disabled = true; };
240    // Rebuild
241    ToolButton buttonRebuild { this, toolTip = $"Rebuild project", menuItemPtr = IDEItem(projectRebuildItem), disabled = true; };
242    // Clean
243    ToolButton buttonClean { this, toolTip = $"Clean project", menuItemPtr = IDEItem(projectCleanItem), disabled = true; };
244    // Real Clean
245    // ToolButton buttonRealClean { this, toolTip = $"Real clean project", menuItemPtr = IDEItem(projectRealCleanItem), disabled = true; };
246    // Regenerate Makefile
247    ToolButton buttonRegenerateMakefile { this, toolTip = $"Regenerate Makefile", menuItemPtr = IDEItem(projectRegenerateItem), disabled = true; };
248    // Compile actual file
249    // Execute
250    ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem), disabled = true; };
251
252    ToolSeparator separator4 { this };
253
254    /* Debug options */
255    // Start/Resume
256    ToolButton buttonDebugStartResume { this, toolTip = $"Start", menuItemPtr = IDEItem(debugStartResumeItem), disabled = true; };
257    // Restart
258    ToolButton buttonDebugRestart { this, toolTip = $"Restart", menuItemPtr = IDEItem(debugRestartItem), disabled = true; };
259    // Pause
260    ToolButton buttonDebugPause { this, toolTip = $"Break", menuItemPtr = IDEItem(debugBreakItem), disabled = true; };
261    // Stop
262    ToolButton buttonDebugStop { this, toolTip = $"Stop", menuItemPtr = IDEItem(debugStopItem), disabled = true; };
263    // Breakpoints
264    //ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem) };
265    // F11
266    ToolButton buttonDebugStepInto { this, toolTip = $"Step Into", menuItemPtr = IDEItem(debugStepIntoItem), disabled = true; };
267    // F10
268    ToolButton buttonDebugStepOver { this, toolTip = $"Step Over", menuItemPtr = IDEItem(debugStepOverItem), disabled = true; };
269    // Shift+F11
270    ToolButton buttonDebugStepOut { this, toolTip = $"Step Out", menuItemPtr = IDEItem(debugStepOutItem), disabled = true; };
271    // Shift+F10
272    ToolButton buttonDebugSkipStepOver { this, toolTip = $"Step Over Skipping Breakpoints", menuItemPtr = IDEItem(debugSkipStepOverItem), disabled = true; };
273 }
274
275 class IDEMainFrame : Window
276 {
277    background = formColor;
278    borderStyle = sizable;
279    hasMaximize = true;
280    hasMinimize = true;
281    hasClose = true;
282    minClientSize = { 600, 300 };
283    hasMenuBar = true;
284    icon = { ":icon.png" };
285    text = titleECEREIDE;
286 #if 0 //def _DEBUG
287    //stayOnTop = true;
288    size = { 800, 600 };
289    anchor = { top = 0, right = 0, bottom = 0 };
290 #else
291    state = maximized;
292    anchor = { left = 0, top = 0, right = 0, bottom = 0 };
293 #endif
294
295    Stacker stack
296    {
297       this;
298       menu = { };
299       isActiveClient = true;
300       gap = 0;
301       direction = vertical;
302       background = formColor;
303       anchor = { left = 0, top = 0, right = 0, bottom = 0 };
304    };
305    IDEToolbar toolBar
306    {
307       stack, ideWorkSpace;
308
309       void OnDestroy(void)
310       {
311          ((IDEWorkSpace)master).toolBar = null;
312       }
313    };
314    IDEWorkSpace ideWorkSpace { stack, this, toolBar = toolBar };
315 }
316
317 define ide = ideMainFrame.ideWorkSpace;
318
319 class IDEWorkSpace : Window
320 {
321    background = Color { 85, 85, 85 };
322
323    //tabCycle = true;
324    hasVertScroll = true;
325    hasHorzScroll = true;
326    hasStatusBar = true;
327    isActiveClient = true;
328    anchor = { left = 0, top = 0, right = 0, bottom = 0 };
329    menu = Menu {  };
330    IDEToolbar toolBar;
331
332    MenuItem * driverItems, * skinItems;
333    StatusField pos { width = 150 };
334    StatusField ovr, caps, num;
335
336    BitmapResource back                 { ":ecereBack.jpg", window = this };
337    BitmapResource bmpBp                { ":codeMarks/breakpoint.png", window = this };
338    BitmapResource bmpBpDisabled        { ":codeMarks/breakpointDisabled.png", window = this };
339    BitmapResource bmpBpHalf            { ":codeMarks/breakpointHalf.png", window = this };
340    BitmapResource bmpBpHalfDisabled    { ":codeMarks/breakpointHalfDisabled.png", window = this };
341    BitmapResource bmpCursor            { ":codeMarks/cursor.png", window = this };
342    BitmapResource bmpCursorError       { ":codeMarks/cursorError.png", window = this };
343    BitmapResource bmpTopFrame          { ":codeMarks/topFrame.png", window = this };
344    BitmapResource bmpTopFrameError     { ":codeMarks/topFrameError.png", window = this };
345    BitmapResource bmpTopFrameHalf      { ":codeMarks/topFrameHalf.png", window = this };
346    BitmapResource bmpTopFrameHalfError { ":codeMarks/topFrameHalfError.png", window = this };
347    
348    Debugger debugger { };
349
350    ProjectView projectView;
351
352    OutputView outputView
353    {
354       parent = this;
355
356       void OnGotoError(char * line)
357       {
358          ide.GoToError(line);
359       }
360
361       void OnCodeLocationParseAndGoTo(char * line)
362       {
363          ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir);
364       }
365
366       bool OnKeyDown(Key key, unichar ch)
367       {
368          switch(key)
369          {
370             case escape: 
371                if(!ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
372                   ide.ShowCodeEditor(); 
373                break;
374             case ctrlS:
375                ide.projectView.stopBuild = true;
376                break;
377             default:
378             {
379                OutputView::OnKeyDown(key, ch);
380                break;
381             }
382          }
383          return true;
384       }
385
386       bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
387       {
388          if(active)
389             ide.RepositionWindows(false);
390          return true;
391       }
392
393       bool OnClose(bool parentClosing)
394       {
395          visible = false;
396          if(!parentClosing)
397             ide.RepositionWindows(false);
398          return parentClosing;
399       }
400    };
401
402    CallStackView callStackView
403    {
404       parent = this, font = { panelFont.faceName, panelFont.size };
405
406       void OnGotoLine(char * line)
407       {
408          int stackLvl;
409          stackLvl = atoi(line);
410          ide.debugger.GoToStackFrameLine(stackLvl, true);
411       }
412
413       void OnSelectFrame(int lineNumber)
414       {
415          ide.debugger.SelectFrame(lineNumber);
416       }
417
418       void OnToggleBreakpoint()
419       {
420          Debugger debugger = ide.debugger;
421          if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
422          {
423             int line = debugger.activeFrame.line;
424             char name[MAX_LOCATION];
425             Project prj = null;
426             // TOFIX: Improve on this, don't use only filename, make a function
427             GetLastDirectory(debugger.activeFrame.absoluteFile, name);
428             if(ide && ide.workspace)
429             {
430                for(p : ide.workspace.projects)
431                {
432                   if(p.topNode.Find(name, false))
433                   {
434                      prj = p;
435                      break;
436                   }
437                }
438                if(!prj)
439                {
440                   for(p : ide.workspace.projects)
441                   {
442                      if(eString_PathInsideOf(debugger.activeFrame.absoluteFile, p.topNode.path))
443                      {
444                         prj = p;
445                         break;
446                      }
447                   }
448                }
449             }
450             debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line, prj);
451             Update(null);
452             {
453                CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
454                if(codeEditor) { codeEditor.Update(null); Activate(); }
455             }
456          }
457       }
458
459       bool OnKeyDown(Key key, unichar ch)
460       {
461          switch(key)
462          {
463             case escape: ide.ShowCodeEditor(); break;
464          }
465          return true;
466       }
467
468       bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
469       {
470          if(active)
471             ide.RepositionWindows(false);
472          return true;
473       }
474
475       bool OnClose(bool parentClosing)
476       {
477          visible = false;
478          if(!parentClosing)
479             ide.RepositionWindows(false);
480          return parentClosing;
481       }
482
483       void OnRedraw(Surface surface)
484       {
485          bool error;
486          int lineCursor, lineTopFrame, activeThread, hitThread;
487          int lineH, scrollY, boxH;
488          BitmapResource bmp;
489          Breakpoint bp = null;
490          Debugger debugger = ide.debugger;
491          Frame activeFrame = debugger.activeFrame;
492
493          boxH = clientSize.h;
494          scrollY = editBox.scroll.y;
495          displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
496
497          activeThread = debugger.activeThread;
498          hitThread = debugger.hitThread;
499          debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
500
501          if(activeFrame && activeFrame.absoluteFile)
502          {
503             for(i : ide.workspace.breakpoints; i.type == user)
504             {
505                if(i.absoluteFilePath && i.absoluteFilePath[0] && 
506                   !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
507                   activeFrame.line == i.line)
508                {
509                   bp = i;
510                   break;
511                }
512             }
513          }
514
515          if(bp)
516             DrawLineMarginIcon(surface,
517                   /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
518                   lineCursor /*1*/, lineH, scrollY, boxH);
519
520          /*
521          if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
522             DrawLineMarginIcon(surface,
523                   (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
524                   1, lineH, scrollY, boxH);
525          */
526          DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
527          if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
528             bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
529          else
530             bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
531          DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
532          if(editBox.horzScroll && editBox.horzScroll.visible)
533          {
534             surface.SetBackground(control);
535             surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
536          }
537       }
538    };
539    
540    WatchesView watchesView { parent = this };
541    ThreadsView threadsView
542    {
543       parent = this, font = { panelFont.faceName, panelFont.size };
544
545       bool OnKeyDown(Key key, unichar ch)
546       {
547          switch(key)
548          {
549             case escape: ide.ShowCodeEditor(); break;
550          }
551          return true;
552       }
553
554       bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
555       {
556          if(active)
557             ide.RepositionWindows(false);
558          return true;
559       }
560
561       bool OnClose(bool parentClosing)
562       {
563          visible = false;
564          if(!parentClosing)
565             ide.RepositionWindows(false);
566          return parentClosing;
567       }
568
569       void OnSelectThread(int threadId)
570       {
571          if(threadId)
572             ide.debugger.SelectThread(threadId);
573       }
574
575       bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
576       {
577          bool result = false;
578          Debugger debugger = ide.debugger;
579          *activeThread = debugger.activeThread;
580          *hitThread = debugger.hitThread;
581          *signalThread = debugger.signalThread;
582          result = true;
583          return result;
584       }
585    };
586    BreakpointsView breakpointsView { parent = this };
587
588    ToolBox toolBox { parent = this };
589    Sheet sheet { parent = this };
590
591    char * tmpPrjDir;
592    property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
593
594    Menu fileMenu { menu, $"File", f, hasMargin = true };
595       MenuItem fileNewItem
596       {
597          fileMenu, $"New", n, ctrlN;
598          bitmap = { ":actions/docNew.png" };
599          bool NotifySelect(MenuItem selection, Modifiers mods)
600          {
601             Window document = (Window)NewCodeEditor(this, normal, false);
602             document.NotifySaved = DocumentSaved;
603             return true;
604          }
605       }
606       MenuItem fileOpenItem
607       {
608          fileMenu, $"Open...", o, ctrlO;
609          bitmap = { ":actions/docOpen.png" };
610          bool NotifySelect(MenuItem selection, Modifiers mods)
611          {
612             if(!projectView && ideSettings.ideFileDialogLocation)
613                ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
614             for(;;)
615             {
616                if(ideFileDialog.Modal() == ok)
617                {
618                   bool gotWhatWeWant = false;
619                   int c;
620                   int numSelections = ideFileDialog.numSelections;
621                   char ** multiFilePaths = ideFileDialog.multiFilePaths;
622
623                   for(c = 0; c < numSelections; c++)
624                   {
625                      if(OpenFile(multiFilePaths[c], normal, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal))
626                         gotWhatWeWant = true;
627                   }
628                   if(gotWhatWeWant ||
629                      MessageBox { type = yesNo, master = this, text = $"Error opening file", 
630                      contents = $"Open a different file?" }.Modal() == no)
631                   {
632                      if(!projectView && gotWhatWeWant)
633                         ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
634                      break;
635                   }
636                }
637                else
638                   break;
639             }
640             return true;
641          }
642       }
643       MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
644       MenuDivider { fileMenu };
645       MenuItem fileSaveItem { fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" } };
646       MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
647       MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
648       MenuDivider { fileMenu };
649       MenuItem findInFiles
650       {
651          fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
652          bool NotifySelect(MenuItem selection, Modifiers mods)
653          {
654             findInFilesDialog.replaceMode = false;
655             findInFilesDialog.Show();
656             return true;
657          }
658       }
659       MenuItem replaceInFiles
660       {
661          fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
662          bool NotifySelect(MenuItem selection, Modifiers mods)
663          {
664             findInFilesDialog.replaceMode = true;
665             findInFilesDialog.Show();
666             return true;
667          }
668       }
669       MenuDivider { fileMenu };
670       MenuItem globalSettingsItem
671       {
672          fileMenu, $"Global Settings...", g;
673          bool NotifySelect(MenuItem selection, Modifiers mods)
674          {
675             globalSettingsDialog.master = this;
676             if(ide.workspace && ide.workspace.compiler)
677                globalSettingsDialog.workspaceActiveCompiler = ide.workspace.compiler;
678             else if(ideSettings.defaultCompiler)
679                globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
680             globalSettingsDialog.Modal();
681             return true;
682          }
683       }
684       MenuDivider { fileMenu };
685       Menu recentFiles { fileMenu, $"Recent Files", r };
686       Menu recentProjects { fileMenu, $"Recent Projects", p };
687       MenuDivider { fileMenu };
688       MenuItem exitItem
689       {
690          fileMenu, $"Exit", x, altF4, NotifySelect = MenuFileExit;
691
692          bool NotifySelect(MenuItem selection, Modifiers mods)
693          {
694             ideMainFrame.Destroy(0);
695             return true;
696          }
697       };
698
699       bool FileRecentFile(MenuItem selection, Modifiers mods)
700       {
701          int id = 0;
702          for(file : ideSettings.recentFiles)
703          {
704             if(id == selection.id)
705             {
706                OpenFile(file, normal, true, null, no, normal);
707                break;
708             }
709             id++;
710          }
711          return true;
712       }
713
714       bool FileRecentProject(MenuItem selection, Modifiers mods)
715       {
716          int id = 0;
717          for(file : ideSettings.recentProjects)
718          {
719             if(id == selection.id)
720             {
721                OpenFile(file, normal, true, null, no, normal);
722                break;
723             }
724             id++;
725          }
726          return true;
727       }
728
729    MenuPlacement editMenu { menu, $"Edit", e };
730    
731    Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
732       MenuItem projectNewItem
733       {
734          projectMenu, $"New...", n, Key { n, true, true };
735          bitmap = { ":actions/projNew.png" };
736          bool NotifySelect(MenuItem selection, Modifiers mods)
737          {
738             if(!DontTerminateDebugSession($"New Project"))
739                if(MenuWindowCloseAll(null, 0))
740                {
741                   NewProjectDialog newProjectDialog;
742
743                   if(projectView)
744                   {
745                      projectView.visible = false;
746                      if(!projectView.Destroy(0))
747                         return true;
748                   }
749                   
750                   newProjectDialog = { master = this };
751                   newProjectDialog.Modal();
752                   if(projectView)
753                   {
754                      ideSettings.AddRecentProject(projectView.fileName);
755                      ide.UpdateRecentMenus();
756                      settingsContainer.Save();
757                   }
758                }
759             return true;
760          }
761       }
762       MenuItem projectOpenItem
763       {
764          projectMenu, $"Open...", o, Key { o, true, true };
765          bitmap = { ":actions/projOpen.png" };
766          bool NotifySelect(MenuItem selection, Modifiers mods)
767          {
768             if(ideSettings.ideProjectFileDialogLocation)
769                ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
770
771             ideProjectFileDialog.text = openProjectFileDialogTitle;
772             if(ideProjectFileDialog.Modal() == ok)
773             {
774                OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal);
775                //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
776             }
777             return true;
778          }
779       }
780       MenuItem projectQuickItem
781       {
782          projectMenu, $"Quick...", q, f7, disabled = true;
783          bool NotifySelect(MenuItem selection, Modifiers mods)
784          {
785             if(!projectView)
786                QuickProjectDialog{ this }.Modal();
787             return true;
788          }
789       }
790       MenuItem projectAddItem
791       {
792          projectMenu, $"Add project to workspace...", a, Key { a, true, true };
793          bitmap = { ":actions/projAdd.png" };
794          disabled = true;
795          bool NotifySelect(MenuItem selection, Modifiers mods)
796          {
797             if(ideSettings.ideProjectFileDialogLocation)
798                ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
799
800             ideProjectFileDialog.text = addProjectFileDialogTitle;
801             for(;;)
802             {
803                if(ideProjectFileDialog.Modal() == ok)
804                {
805                   if(OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add))
806                      break;
807                   if(MessageBox { type = yesNo, master = this, text = $"Error opening project file", 
808                         contents = $"Add a different project?" }.Modal() == no)
809                   {
810                      break;
811                   }
812                }
813                else
814                   break;
815             }
816             return true;
817          }
818       }
819       MenuItem projectCloseItem
820       {
821          projectMenu, $"Close", c, disabled = true;
822          bool NotifySelect(MenuItem selection, Modifiers mods)
823          {
824             if(projectView)
825             {
826                if(!ide.DontTerminateDebugSession($"Project Close"))
827                {
828                   if(findInFilesDialog)
829                      findInFilesDialog.SearchStop();
830                   projectView.visible = false;
831                   if(projectView.Destroy(0))
832                      MenuWindowCloseAll(null, 0);
833                   {
834                      char workingDir[MAX_LOCATION];
835                      GetWorkingDir(workingDir, MAX_LOCATION);
836                      findInFilesDialog.currentDirectory = workingDir;
837                      ideMainFrame.text = titleECEREIDE;
838                   }
839                }
840             }
841             return true;
842          }
843       }
844       MenuDivider { projectMenu };
845       MenuItem activeCompilerItem
846       {
847          projectMenu, $"Active Compiler...", g, /*altF5, */disabled = true;
848          bool NotifySelect(MenuItem selection, Modifiers mods)
849          {
850             projectView.MenuCompiler(null, mods);
851             return true;
852          }
853       }
854       MenuItem projectActiveConfigItem
855       {
856          projectMenu, $"Active Configuration...", g, altF5, disabled = true;
857          bool NotifySelect(MenuItem selection, Modifiers mods)
858          {
859             projectView.MenuConfig(projectView.active ? selection : null, mods);
860             return true;
861          }
862       }
863       MenuItem projectSettingsItem
864       {
865          projectMenu, $"Settings...", s, altF7, disabled = true;
866          bool NotifySelect(MenuItem selection, Modifiers mods)
867          {
868             projectView.MenuSettings(projectView.active ? selection : null, mods);
869             return true;
870          }
871       }
872       MenuDivider { projectMenu };
873       MenuItem projectBrowseFolderItem
874       {
875          projectMenu, $"Browse Project Folder", p, disabled = true;
876          bool NotifySelect(MenuItem selection, Modifiers mods)
877          {
878             if(projectView)
879                projectView.MenuBrowseFolder(null, mods);
880             return true;
881          }
882       }
883       MenuDivider { projectMenu };
884       MenuItem projectRunItem
885       {
886          projectMenu, $"Run", r, ctrlF5, disabled = true;
887          bitmap = { ":actions/run.png" };
888          bool NotifySelect(MenuItem selection, Modifiers mods)
889          {
890             if(projectView)
891                projectView.Run(null, mods);
892             return true;
893          }
894       }
895       MenuItem projectBuildItem
896       {
897          projectMenu, $"Build", b, f7, disabled = true;
898          bitmap = { ":actions/build.png" };
899          bool NotifySelect(MenuItem selection, Modifiers mods)
900          {
901             if(projectView)
902                projectView.ProjectBuild(projectView.active ? selection : null, mods);
903             return true;
904          }
905       }
906       MenuItem projectLinkItem
907       {
908          projectMenu, $"Relink", l, disabled = true;
909          bitmap = { ":actions/relink.png" };
910          bool NotifySelect(MenuItem selection, Modifiers mods)
911          {
912             if(projectView)
913                projectView.ProjectLink(projectView.active ? selection : null, mods);
914             return true;
915          }
916       }
917       MenuItem projectRebuildItem
918       {
919          projectMenu, $"Rebuild", d, shiftF7, disabled = true;
920          bitmap = { ":actions/rebuild.png" };
921          bool NotifySelect(MenuItem selection, Modifiers mods)
922          {
923             if(projectView)
924                projectView.ProjectRebuild(projectView.active ? selection : null, mods);
925             return true;
926          }
927       }
928       MenuItem projectCleanItem
929       {
930          projectMenu, $"Clean", e, disabled = true;
931          bitmap = { ":actions/clean.png" };
932          bool NotifySelect(MenuItem selection, Modifiers mods)
933          {
934             if(projectView)
935             {
936                debugger.Stop();
937                projectView.ProjectClean(projectView.active ? selection : null, mods);
938             }
939             return true;
940          }
941       }
942       MenuItem projectRealCleanItem
943       {
944          projectMenu, $"Real Clean", disabled = true;
945          bitmap = { ":actions/clean.png" };
946          bool NotifySelect(MenuItem selection, Modifiers mods)
947          {
948             if(projectView)
949             {
950                debugger.Stop();
951                projectView.ProjectRealClean(projectView.active ? selection : null, mods);
952             }
953             return true;
954          }
955       }
956       MenuItem projectRegenerateItem
957       {
958          projectMenu, $"Regenerate Makefile", m, disabled = true;
959          bitmap = { ":actions/regMakefile.png" };
960          bool NotifySelect(MenuItem selection, Modifiers mods)
961          {
962             if(projectView)
963                projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
964             return true;
965          }
966       }
967       MenuItem projectCompileItem;
968    Menu debugMenu { menu, $"Debug", d, hasMargin = true };
969       MenuItem debugStartResumeItem
970       {
971          debugMenu, $"Start", s, f5, disabled = true;
972          bitmap = { ":actions/debug.png" };
973          NotifySelect = MenuDebugStart;
974       }
975       bool MenuDebugStart(MenuItem selection, Modifiers mods)
976       {
977          if(projectView)
978          {
979             debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
980             if(!projectView.DebugStart())
981                debugStartResumeItem.disabled = false; // same exception
982          }
983          return true;
984       }
985       bool MenuDebugResume(MenuItem selection, Modifiers mods)
986       {
987          if(projectView)
988             projectView.DebugResume();
989          return true;
990       }
991       MenuItem debugRestartItem
992       {
993          debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
994          bitmap = { ":actions/restart.png" };
995          bool NotifySelect(MenuItem selection, Modifiers mods)
996          {
997             if(projectView)
998                projectView.DebugRestart();
999             return true;
1000          }
1001       }
1002       MenuItem debugBreakItem
1003       {
1004          debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1005          bitmap = { ":actions/pause.png" };
1006          bool NotifySelect(MenuItem selection, Modifiers mods)
1007          {
1008             if(projectView)
1009                projectView.DebugBreak();
1010             return true;
1011          }
1012       }
1013       MenuItem debugStopItem
1014       {
1015          debugMenu, $"Stop", p, shiftF5, disabled = true;
1016          bitmap = { ":actions/stopDebug.png" };
1017          bool NotifySelect(MenuItem selection, Modifiers mods)
1018          {
1019             if(projectView)
1020                projectView.DebugStop();
1021             return true;
1022          }
1023       }
1024       MenuDivider { debugMenu };
1025       MenuItem debugStepIntoItem
1026       {
1027          debugMenu, $"Step Into", i, f11, disabled = true;
1028          bitmap = { ":actions/stepInto.png" };
1029          bool NotifySelect(MenuItem selection, Modifiers mods)
1030          {
1031             if(projectView)
1032                projectView.DebugStepInto();
1033             return true;
1034          }
1035       }
1036       MenuItem debugStepOverItem
1037       {
1038          debugMenu, $"Step Over", v, f10, disabled = true;
1039          bitmap = { ":actions/stepOver.png" };
1040          bool NotifySelect(MenuItem selection, Modifiers mods)
1041          {
1042             if(projectView)
1043                projectView.DebugStepOver(false);
1044             return true;
1045          }
1046       }
1047       MenuItem debugStepOutItem
1048       {
1049          debugMenu, $"Step Out", o, shiftF11, disabled = true;
1050          bitmap = { ":actions/stepOut.png" };
1051          bool NotifySelect(MenuItem selection, Modifiers mods)
1052          {
1053             if(projectView)
1054                projectView.DebugStepOut(false);
1055             return true;
1056          }
1057       }
1058       MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1059       MenuItem debugSkipStepOverItem
1060       {
1061          debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1062          bool NotifySelect(MenuItem selection, Modifiers mods)
1063          {
1064             if(projectView)
1065                projectView.DebugStepOver(true);
1066             return true;
1067          }
1068       }
1069       MenuItem debugSkipStepOutItem
1070       {
1071          debugMenu, $"Step Out Skipping Breakpoints", t, Key { f11, ctrl = true, shift = true }, disabled = true;
1072          bitmap = { ":actions/skipBreaks.png" };
1073          bool NotifySelect(MenuItem selection, Modifiers mods)
1074          {
1075             if(projectView)
1076                projectView.DebugStepOut(true);
1077             return true;
1078          }
1079       }
1080       MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1081       //MenuDivider { debugMenu };
1082       //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1083    MenuPlacement imageMenu { menu, $"Image", i };
1084    Menu viewMenu { menu, $"View", v };
1085       MenuItem viewProjectItem
1086       {
1087          viewMenu, $"Project View", j, alt0, disabled = true;
1088          bool NotifySelect(MenuItem selection, Modifiers mods)
1089          {
1090             if(projectView)
1091             {
1092                projectView.visible = true;
1093                projectView.Activate();
1094             }
1095             return true;
1096          }
1097       }
1098       MenuPlacement { viewMenu, $"View Designer" };
1099       MenuPlacement { viewMenu, $"View Code" };
1100       MenuPlacement { viewMenu, $"View Properties" };
1101       MenuPlacement { viewMenu, $"View Methods" };
1102       MenuItem viewDesignerItem
1103       {
1104          viewMenu, $"View Designer", d, f8;
1105          bool NotifySelect(MenuItem selection, Modifiers mods)
1106          {
1107             Window client = activeClient;
1108             Class dataType = client._class;
1109             if(!strcmp(dataType.name, "Designer"))
1110             {
1111                client.visible = true;
1112                client.Activate();
1113             }
1114             else
1115                ((CodeEditor)client).ViewDesigner();
1116             return true;
1117          }
1118       }
1119       MenuItem viewCodeItem
1120       {
1121          viewMenu, $"View Code", c, f8;
1122          bool NotifySelect(MenuItem selection, Modifiers mods)
1123          {
1124             Window client = activeClient;
1125             Class dataType = client._class;
1126             if(!strcmp(dataType.name, "Designer"))
1127                client = ((Designer)client).codeEditor;
1128
1129             client.Activate();
1130             // Do this after so the caret isn't moved yet...
1131             client.visible = true;
1132             return true;
1133          }
1134       }
1135       MenuItem viewPropertiesItem
1136       {
1137          viewMenu, $"View Properties", p, f4;
1138          bool NotifySelect(MenuItem selection, Modifiers mods)
1139          {
1140             sheet.visible = true;
1141             sheet.sheetSelected = properties;
1142             sheet.Activate();
1143             return true;
1144          }
1145       }
1146       MenuItem viewMethodsItem
1147       {
1148          viewMenu, $"View Methods", m, f4;
1149          bool NotifySelect(MenuItem selection, Modifiers mods)
1150          {
1151             sheet.visible = true;
1152             sheet.sheetSelected = methods;
1153             sheet.Activate();
1154             return true;
1155          }
1156       }
1157       MenuItem viewToolBoxItem
1158       {
1159          viewMenu, $"View Toolbox", x, f12;
1160          bool NotifySelect(MenuItem selection, Modifiers mods)
1161          {
1162             toolBox.visible = true;
1163             toolBox.Activate();
1164             return true;
1165          }
1166       }
1167       MenuItem viewOutputItem
1168       {
1169          viewMenu, $"Output", o, alt2;
1170          bool NotifySelect(MenuItem selection, Modifiers mods)
1171          {
1172             outputView.Show();
1173             return true;
1174          }
1175       }
1176       MenuItem viewWatchesItem
1177       {
1178          viewMenu, $"Watches", w, alt3;
1179          bool NotifySelect(MenuItem selection, Modifiers mods)
1180          {
1181             watchesView.Show();
1182             return true;
1183          }
1184       }
1185       MenuItem viewThreadsItem
1186       {
1187          viewMenu, $"Threads", t, alt4;
1188          bool NotifySelect(MenuItem selection, Modifiers mods)
1189          {
1190             threadsView.Show();
1191             return true;
1192          }
1193       }
1194       MenuItem viewBreakpointsItem
1195       {
1196          viewMenu, $"Breakpoints", b, alt5;
1197          bool NotifySelect(MenuItem selection, Modifiers mods)
1198          {
1199             breakpointsView.Show();
1200             return true;
1201          }
1202       }
1203       MenuItem viewCallStackItem
1204       {
1205          viewMenu, $"Call Stack", s, alt7;
1206          bool NotifySelect(MenuItem selection, Modifiers mods)
1207          {
1208             callStackView.Show();
1209             return true;
1210          }
1211       }
1212       MenuItem viewAllDebugViews
1213       {
1214          viewMenu, $"All Debug Views", a, alt9;
1215          bool NotifySelect(MenuItem selection, Modifiers mods)
1216          {
1217             outputView.Show();
1218             watchesView.Show();
1219             threadsView.Show();
1220             callStackView.Show();
1221             breakpointsView.Show();
1222             return true;
1223          }
1224       }
1225 #ifdef GDB_DEBUG_GUI
1226       MenuDivider { viewMenu };
1227       MenuItem viewGDBItem
1228       {
1229          viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1230          bool NotifySelect(MenuItem selection, Modifiers mods)
1231          {
1232             gdbDialog.Show();
1233             return true;
1234          }
1235       }
1236 #endif
1237       MenuDivider { viewMenu };
1238       MenuItem viewColorPicker
1239       {
1240          viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1241          bool NotifySelect(MenuItem selection, Modifiers mods)
1242          {
1243             ColorPicker colorPicker { master = this, parent = this, stayOnTop = true };
1244             colorPicker.Create();
1245             return true;
1246          }
1247       }
1248       MenuDivider { viewMenu };
1249       /*
1250       MenuItem
1251       {
1252          viewMenu, "Full Screen", f, checkable = true;
1253
1254          bool NotifySelect(MenuItem selection, Modifiers mods)
1255          {
1256             app.fullScreen ^= true;
1257             SetDriverAndSkin();
1258             anchor = { 0, 0, 0, 0 };
1259             return true;
1260          }
1261       };
1262       */
1263       Menu driversMenu { viewMenu, $"Graphics Driver", v };
1264       //Menu skinsMenu { viewMenu, "GUI Skins", k };
1265    Menu windowMenu { menu, $"Window", w };
1266       MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1267       MenuDivider { windowMenu };
1268       MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1269       MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1270       MenuDivider { windowMenu };
1271       MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1272       MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1273       MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1274       MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1275       MenuDivider { windowMenu };
1276       MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1277    Menu helpMenu { menu, $"Help", h };
1278       MenuItem
1279       {
1280          helpMenu, $"API Reference", r, f1;
1281          bool NotifySelect(MenuItem selection, Modifiers mods)
1282          {
1283             Execute("documentor");
1284             return true;
1285          }
1286       }
1287       MenuDivider { helpMenu };
1288       MenuItem
1289       {
1290          helpMenu, $"About...", a;
1291          bool NotifySelect(MenuItem selection, Modifiers mods)
1292          {
1293             AboutIDE { master = this }.Modal();
1294             return true;
1295          }
1296       }
1297
1298    property ToolBox toolBox
1299    {
1300       get { return toolBox; }
1301    }
1302
1303    property Sheet sheet
1304    {
1305       get { return sheet; }
1306    }
1307
1308    property Project project
1309    {
1310       get { return projectView ? projectView.project : null; }
1311    }
1312
1313    property Workspace workspace
1314    {
1315       get { return projectView ? projectView.workspace : null; }
1316    }
1317
1318    FindInFilesDialog findInFilesDialog
1319    {
1320       master = this, parent = this;
1321       filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1322       filter = 1;
1323    };
1324
1325 #ifdef GDB_DEBUG_GUI
1326    GDBDialog gdbDialog
1327    {
1328       master = this, parent = this;
1329       anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1330
1331       void OnCommand(char * string)
1332       {
1333          if(ide)
1334             ide.debugger.SendGDBCommand(string);
1335       }
1336    };
1337 #endif
1338    
1339    bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1340    {
1341       //app.driver = app.drivers[selection.id];
1342 #ifdef __unix__
1343       app.driver = selection.id ? "OpenGL" : "X";
1344 #else
1345       app.driver = selection.id ? "OpenGL" : "GDI";
1346 #endif
1347       delete ideSettings.displayDriver;
1348       ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1349
1350       settingsContainer.Save();
1351       //SetDriverAndSkin();
1352       return true;
1353    }
1354
1355    bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1356    {
1357       app.skin = app.skins[selection.id];
1358       SetDriverAndSkin();
1359       return true;
1360    }
1361
1362    void SetDriverAndSkin()
1363    {
1364       int c;
1365       for(c = 0; c < app.numSkins; c++)
1366          if(!strcmp(app.skins[c], app.skin))
1367          {
1368             skinItems[c].checked = true;
1369             break;
1370          }
1371       for(c = 0; c < app.numDrivers; c++)
1372          if(!strcmp(app.drivers[c], app.driver))
1373          {
1374             driverItems[c].checked = true;
1375             break;
1376          }
1377    }
1378
1379    ProjectView CreateProjectView(Workspace workspace, char * fileName)
1380    {
1381       Project project = workspace.projects.firstIterator.data;
1382       projectView = ProjectView
1383       {
1384          this;
1385          fileName = fileName;
1386          
1387          void NotifyDestroyed(Window window, DialogResult result)
1388          {
1389             projectView = null;
1390             text = titleECEREIDE;
1391             
1392             AdjustMenus();
1393          }
1394       };
1395       projectView.Create();
1396       RepositionWindows(false);
1397
1398       // Leave it after Create to avoid flicker due to seeing IDE without a project view
1399       projectView.workspace = workspace;
1400       projectView.project = project;
1401       ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1402
1403       AdjustMenus();
1404
1405       ide.breakpointsView.LoadFromWorkspace();
1406       ide.watchesView.LoadFromWorkspace();
1407
1408       findInFilesDialog.projectNodeField.userData = projectView;
1409
1410       {
1411          char fileName[MAX_LOCATION];
1412          strcpy(fileName, project.topNode.path);
1413          PathCat(fileName, project.topNode.name);
1414       }
1415       return projectView;
1416    }
1417
1418    bool GetDebugMenusDisabled()
1419    {
1420       if(projectView)
1421       {
1422          Project project = projectView.project;
1423          if(project)
1424             if(project.GetTargetType(project.config) == executable)
1425                return false;
1426            
1427       }
1428       return true;
1429    }
1430
1431    void RepositionWindows(bool expand)
1432    {
1433       if(this)
1434       {
1435          Window child;
1436          bool inDebugMode = debugger.isActive;
1437          bool callStackVisible = expand ? false : callStackView.visible;
1438          bool threadsVisible = expand ? false : threadsView.visible;
1439          bool watchesVisible = expand ? false : watchesView.visible;
1440          bool breakpointsVisible = expand ? false : breakpointsView.visible;
1441          bool toolBoxVisible = toolBox.visible;
1442          bool outputVisible = expand ? false : outputView.visible;
1443          int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1444          int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1445          
1446          for(child = firstChild; child; child = child.next)
1447          {
1448             if(child._class == class(CodeEditor) || child._class == class(Designer) || 
1449                child._class == class(Sheet) || child._class == class(ProjectView))
1450             {
1451                Anchor anchor = child.anchor;
1452                anchor.top = topDistance;
1453                anchor.bottom = bottomDistance;
1454                if(child._class == class(CodeEditor) || child._class == class(Designer))
1455                {
1456                   anchor.right = toolBoxVisible ? 150 : 0;
1457                }
1458                child.anchor = anchor;
1459             }
1460             else if(expand)
1461             {
1462                if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) || 
1463                   child._class == class(BreakpointsView))
1464                   child.visible = false;
1465             }
1466          }
1467          // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1468          Update(null);
1469       }
1470    }
1471
1472    bool ShowCodeEditor()
1473    {
1474       if(activeClient)
1475          activeClient.Activate();
1476       else if(projectView)
1477       { 
1478          projectView.visible = true;
1479          projectView.Activate();
1480       }
1481       else
1482       {
1483          sheet.visible = true;
1484          sheet.Activate();
1485       }
1486       return false;
1487    }
1488
1489    bool ShouldStopBuild()
1490    {
1491       return projectView.stopBuild;
1492    }
1493
1494    void DocumentSaved(Window document, char * fileName)
1495    {
1496       ideSettings.AddRecentFile(fileName);
1497       ide.UpdateRecentMenus();
1498       ide.AdjustFileMenus();
1499       settingsContainer.Save();
1500    }
1501
1502    bool Window::OnFileModified(FileChange fileChange, char * param)
1503    {
1504       char temp[4096];
1505       sprintf(temp, $"The document %s was modified by another application.\n"
1506             "Would you like to reload it and lose your changes?", this.fileName);
1507       if(MessageBox { type = yesNo, master = this/*.parent*/,
1508             text = $"Document has been modified", contents = temp }.Modal() == yes)
1509       {
1510          char * fileName = CopyString(this.fileName);
1511          WindowState state = this.state;
1512          Anchor anchor = this.anchor;
1513          Size size = this.size;
1514
1515          this.modifiedDocument = false;
1516          this.Destroy(0);
1517          this = ide.OpenFile(fileName, normal, true, null, no, normal);
1518          if(this)
1519          {
1520             this.anchor = anchor;
1521             this.size = size;
1522             this.SetState(state, true, 0);
1523          }
1524          delete fileName;
1525          return true;
1526       }
1527       return true;
1528    }
1529
1530    void UpdateMakefiles()
1531    {
1532       if(workspace)
1533       {
1534          CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1535          projectView.ShowOutputBuildLog(true);
1536          projectView.DisplayCompiler(compiler, false);
1537          for(prj : workspace.projects)
1538             projectView.ProjectUpdateMakefileForAllConfigs(prj);
1539          delete compiler;
1540       }
1541    }
1542
1543    void AdjustMenus()
1544    {
1545       bool unavailable = !project;
1546
1547       projectAddItem.disabled             = unavailable;
1548       toolBar.buttonAddProject.disabled   = unavailable;
1549
1550       activeCompilerItem.disabled         = unavailable;
1551       projectActiveConfigItem.disabled    = unavailable;
1552       projectSettingsItem.disabled        = unavailable;
1553
1554       projectBrowseFolderItem.disabled    = unavailable;
1555
1556       viewProjectItem.disabled            = unavailable;
1557
1558       AdjustFileMenus();
1559       AdjustBuildMenus();
1560       AdjustDebugMenus();
1561    }
1562
1563    property bool hasOpenedCodeEditors
1564    {
1565       get
1566       {
1567          Window w;
1568          for(w = firstChild; w; w = w.next)
1569             if(w._class == class(CodeEditor) &&
1570                   w.isDocument && !w.closing && w.visible && w.created &&
1571                   w.fileName && w.fileName[0])
1572                return true;
1573          return false;
1574       }
1575    }
1576
1577    void AdjustFileMenus()
1578    {
1579       bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
1580
1581       projectQuickItem.disabled           = unavailable;
1582    }
1583
1584    void AdjustBuildMenus()
1585    {
1586       bool unavailable = project && projectView.buildInProgress;
1587
1588       projectNewItem.disabled             = unavailable;
1589       toolBar.buttonNewProject.disabled   = unavailable;
1590       projectOpenItem.disabled            = unavailable;
1591       toolBar.buttonOpenProject.disabled  = unavailable;
1592
1593       unavailable = !project || projectView.buildInProgress;
1594
1595       projectCloseItem.disabled           = unavailable;
1596       // toolBar.buttonCloseProject.disabled = unavailable;
1597
1598       projectRunItem.disabled    = unavailable || project.GetTargetType(project.config) != executable;
1599       toolBar.buttonRun.disabled = unavailable || project.GetTargetType(project.config) != executable;
1600       projectBuildItem.disabled                 = unavailable;
1601       toolBar.buttonBuild.disabled              = unavailable;
1602       projectLinkItem.disabled                  = unavailable;
1603       toolBar.buttonReLink.disabled             = unavailable;
1604       projectRebuildItem.disabled               = unavailable;
1605       toolBar.buttonRebuild.disabled            = unavailable;
1606       projectCleanItem.disabled                 = unavailable;
1607       toolBar.buttonClean.disabled              = unavailable;
1608       projectRealCleanItem.disabled             = unavailable;
1609       // toolBar.buttonRealClean.disabled          = unavailable;
1610       projectRegenerateItem.disabled            = unavailable;
1611       toolBar.buttonRegenerateMakefile.disabled = unavailable;
1612       projectCompileItem.disabled               = unavailable;
1613
1614       if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
1615       {
1616          MenuItem menu;
1617          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);      if(menu) menu.disabled = unavailable;
1618          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0);       if(menu) menu.disabled = unavailable;
1619          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0);    if(menu) menu.disabled = unavailable;
1620          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0);      if(menu) menu.disabled = unavailable;
1621          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0);  if(menu) menu.disabled = unavailable;
1622          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
1623          projectView.popupMenu.Update(null);
1624       }
1625    }
1626
1627    void AdjustDebugMenus()
1628    {
1629       bool unavailable = !project || project.GetTargetType(project.config) != executable ||
1630                projectView.buildInProgress == buildingMainProject;
1631       bool active = ide.debugger.isActive;
1632       bool executing = ide.debugger.state == running;
1633       //bool holding = ide.debugger.state == stopped;
1634
1635       debugStartResumeItem.disabled       = unavailable || executing;
1636       debugStartResumeItem.text           = active ? $"Resume" : $"Start";
1637       debugStartResumeItem.NotifySelect   = active ? MenuDebugResume : MenuDebugStart;
1638       if(toolBar)
1639       {
1640          toolBar.buttonDebugStartResume.disabled      = unavailable || executing;
1641          toolBar.buttonDebugStartResume.toolTip       = active ? $"Resume" : $"Start";
1642       }
1643
1644       debugBreakItem.disabled             = unavailable || !executing;
1645       debugStopItem.disabled              = unavailable || !active;
1646       debugRestartItem.disabled           = unavailable || !active;
1647       if(toolBar)
1648       {
1649          toolBar.buttonDebugPause.disabled            = unavailable || !executing;
1650          toolBar.buttonDebugStop.disabled             = unavailable || !active;
1651          toolBar.buttonDebugRestart.disabled          = unavailable || !active;
1652       }
1653
1654       debugStepIntoItem.disabled          = unavailable || executing;
1655       debugStepOverItem.disabled          = unavailable || executing;
1656       debugStepOutItem.disabled           = unavailable || executing || !active;
1657       debugSkipStepOverItem.disabled      = unavailable || executing;
1658       debugSkipStepOutItem.disabled       = unavailable || executing || !active;
1659       if(toolBar)
1660       {
1661          toolBar.buttonDebugStepInto.disabled         = unavailable || executing;
1662          toolBar.buttonDebugStepOver.disabled         = unavailable || executing;
1663          toolBar.buttonDebugStepOut.disabled          = unavailable || executing || !active;
1664          toolBar.buttonDebugSkipStepOver.disabled     = unavailable || executing;
1665          // toolBar.buttonDebugSkipStepOutItem.disabled  = unavailable || executing;
1666       }
1667       if((Designer)GetActiveDesigner())
1668       {
1669          CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
1670          if(codeEditor)
1671          {
1672             codeEditor.debugRunToCursor.disabled      = unavailable || executing;
1673             codeEditor.debugSkipRunToCursor.disabled  = unavailable || executing;
1674          }
1675       }
1676    }
1677
1678    void ChangeFileDialogsDirectory(char * directory, bool saveSettings)
1679    {
1680       char tempString[MAX_LOCATION];
1681       strcpy(tempString, directory);
1682       if(saveSettings && !projectView)
1683       {
1684          ideSettings.ideFileDialogLocation = directory;
1685          settingsContainer.Save();
1686       }
1687
1688       ideFileDialog.currentDirectory = tempString;
1689       codeEditorFileDialog.currentDirectory = tempString;
1690       codeEditorFormFileDialog.currentDirectory = tempString;
1691    }
1692
1693    void ChangeProjectFileDialogDirectory(char * directory)
1694    {
1695       ideSettings.ideProjectFileDialogLocation = directory;
1696       settingsContainer.Save();
1697    }
1698
1699    Window FindWindow(char * filePath)
1700    {
1701       Window document = null;
1702
1703       // TOCHECK: Do we need to change slashes here?
1704       for(document = firstChild; document; document = document.next)
1705       {
1706          char * fileName = document.fileName;
1707          if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
1708          {
1709             document.visible = true;
1710             document.Activate();
1711             return document;
1712          }
1713       }
1714       return null;
1715    }
1716
1717    bool DontTerminateDebugSession(char * title)
1718    {
1719       if(debugger.isActive)
1720       {
1721          if(MessageBox { type = yesNo, master = ide, 
1722                            contents = $"Do you want to terminate the debugging session in progress?", 
1723                            text = title }.Modal() == no)
1724             return true;
1725          /*
1726          MessageBox msg { type = yesNo, master = ide, 
1727                            contents = "Do you want to terminate the debugging session in progress?", 
1728                            text = title };
1729          if(msg.Modal() == no)
1730          {
1731             msg.Destroy(0);
1732             delete msg;
1733             return true;
1734          }
1735          msg.Destroy(0);
1736          delete msg;*/
1737       }
1738       return false;
1739    }
1740
1741    Window OpenFile(char * origFilePath, WindowState state, bool visible, char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod)
1742    {
1743       char extension[MAX_EXTENSION] = "";
1744       Window document = null;
1745       bool isProject = false;
1746       bool needFileModified = true;
1747       char winFilePath[MAX_LOCATION];
1748       char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
1749
1750       if(!type)
1751       {
1752          GetExtension(filePath, extension);
1753          strlwr(extension);
1754       }
1755       else
1756          strcpy(extension, type);
1757
1758       if(strcmp(extension, ProjectExtension))
1759       {
1760          for(document = firstChild; document; document = document.next)
1761          {
1762             char * fileName = document.fileName;
1763             if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
1764             {
1765                document.visible = true;
1766                if(visible)
1767                   document.Activate();
1768                return document;
1769             }
1770          }
1771       }
1772
1773       if(createIfFails == whatever)
1774          ;
1775       else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
1776       {
1777          needFileModified = false;
1778          if(openMethod == normal)
1779          {
1780             if(DontTerminateDebugSession($"Open Project"))
1781                return null;
1782             isProject = true;
1783             if(MenuWindowCloseAll(null, 0))
1784             {
1785                if(projectView)
1786                {
1787                   projectView.visible = false;
1788                   projectView.Destroy(0);
1789                   // Where did this come from? projectView = null;
1790                }
1791                if(!projectView)
1792                {
1793                   for(;;)
1794                   {
1795                      Project project;
1796                      Workspace workspace = null;
1797                      
1798                      if(FileExists(filePath))
1799                      {
1800                         if(!strcmp(extension, ProjectExtension))
1801                         {
1802                            char workspaceFile[MAX_LOCATION];
1803                            strcpy(workspaceFile, filePath);
1804                            ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
1805                            workspace = LoadWorkspace(workspaceFile, filePath);
1806                         }
1807                         else if(!strcmp(extension, WorkspaceExtension))
1808                            workspace = LoadWorkspace(filePath, null);
1809                         else
1810                            return null;
1811                         //project = LoadProject(filePath);
1812                      }
1813                      
1814                      if(workspace)
1815                      {
1816                         char absolutePath[MAX_LOCATION];
1817                         CreateProjectView(workspace, filePath);
1818                         document = projectView;
1819
1820                         workspace.DropInvalidBreakpoints();
1821                         workspace.Save();
1822
1823                         ide.projectView.ShowOutputBuildLog(true);
1824                         {
1825                            CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
1826                            ide.projectView.DisplayCompiler(compiler, false);
1827                            delete compiler;
1828                         }
1829                         UpdateMakefiles();
1830                         {
1831                            char newWorkingDir[MAX_LOCATION];
1832                            StripLastDirectory(filePath, newWorkingDir);
1833                            ChangeFileDialogsDirectory(newWorkingDir, false);
1834                         }
1835                         if(document)
1836                            document.fileName = filePath;
1837
1838                         ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
1839
1840                         // this crashes on starting ide with epj file, solution please?
1841                         // app.UpdateDisplay();
1842
1843                         workspace.holdTracking = true;
1844                         for(ofi : workspace.openedFiles)
1845                         {
1846                            if(ofi.state != closed)
1847                            {
1848                               Window file = OpenFile(ofi.path, normal, true, null, no, normal);
1849                               if(file)
1850                               {
1851                                  char fileName[MAX_LOCATION];
1852                                  ProjectNode node;
1853                                  GetLastDirectory(ofi.path, fileName);
1854                                  node = projectView.project.topNode.Find(fileName, true);
1855                                  if(node)
1856                                     node.EnsureVisible();
1857                               }
1858                            }
1859                         }
1860                         workspace.holdTracking = false;
1861
1862                         workspace.timer.Start();
1863
1864                         findInFilesDialog.mode = FindInFilesMode::project;
1865                         findInFilesDialog.currentDirectory = ide.project.topNode.path;
1866                         
1867                         {
1868                            char location[MAX_LOCATION];
1869                            StripLastDirectory(ide.project.topNode.path, location);
1870                            ChangeProjectFileDialogDirectory(location);
1871                         }
1872                         
1873                         /*
1874                         if(projectView.debugger)
1875                            projectView.debugger.EvaluateWatches();
1876                         */
1877                         
1878                         break;
1879                      }
1880                      else 
1881                      {
1882                         if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
1883                         {
1884                            ideProjectFileDialog.text = openProjectFileDialogTitle;
1885                            if(ideProjectFileDialog.Modal() == cancel)
1886                               return null;
1887                            filePath = ideProjectFileDialog.filePath;
1888                            GetExtension(filePath, extension);
1889                         }
1890                         else
1891                            return null;
1892                      }
1893                   }
1894                }
1895             }
1896             else
1897                return null;
1898          }
1899          else if(openMethod == add)
1900          {
1901             if(workspace)
1902             {
1903                Project prj = null;
1904                char slashFilePath[MAX_LOCATION];
1905                GetSlashPathBuffer(slashFilePath, filePath);
1906                for(p : workspace.projects)
1907                {
1908                   if(!fstrcmp(p.filePath, slashFilePath))
1909                   {
1910                      prj = p;
1911                      break;
1912                   }
1913                }
1914                if(prj)
1915                {
1916                   MessageBox { type = ok, parent = parent, master = this, text = $"Same Project", 
1917                         contents = $"This project is already present in workspace." }.Modal();
1918                }
1919                else
1920                {
1921                   prj = LoadProject(filePath);
1922                   if(prj)
1923                   {
1924                      CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1925                      prj.StartMonitoring();
1926                      workspace.projects.Add(prj);
1927                      if(projectView)
1928                         projectView.AddNode(prj.topNode, null);
1929                      workspace.modified = true;
1930                      workspace.Save();
1931                      findInFilesDialog.AddProjectItem(prj);
1932                      projectView.ShowOutputBuildLog(true);
1933                      projectView.DisplayCompiler(compiler, false);
1934                      projectView.ProjectUpdateMakefileForAllConfigs(prj);
1935                      delete compiler;
1936
1937                      {
1938                         char location[MAX_LOCATION];
1939                         StripLastDirectory(prj.topNode.path, location);
1940                         ChangeProjectFileDialogDirectory(location);
1941                      }
1942
1943                      // projectView is associated with the main project and not with the one just added but
1944                      return projectView; // just to let the caller know something was opened
1945                   }
1946                }
1947             }
1948             else
1949                return null;
1950          }
1951       }
1952       else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
1953             !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
1954             !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
1955       {
1956          if(FileExists(filePath))
1957             document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable, 
1958                                        hasVertScroll = true, hasHorzScroll = true, parent = this, state = state, 
1959                                        visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
1960                                     };
1961          if(!document)
1962             MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
1963       }
1964 #ifndef NO3D
1965       else if(!strcmp(extension, "3ds"))
1966       {
1967          if(FileExists(filePath))
1968             document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable, 
1969                                     hasVertScroll = true, hasHorzScroll = true, parent = this, state = state, 
1970                                     visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
1971                                     };
1972
1973          if(!document)
1974             MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
1975       }
1976 #endif
1977       else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
1978             !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
1979             !strcmp(extension, "htm") || !strcmp(extension, "html") ||
1980             !strcmp(extension, "css") || !strcmp(extension, "php") ||
1981             !strcmp(extension, "js"))
1982       {
1983          CodeEditor editor { parent = this, state = state, visible = false };
1984          editor.updatingCode = true;
1985          if(editor.LoadFile(filePath))
1986          {
1987             document = editor;
1988             editor.visible = true;
1989          }
1990          else
1991             delete editor;
1992          needFileModified = false;
1993       }
1994       else
1995       {
1996          CodeEditor editor { parent = this, state = state, visible = false };
1997          if(editor.LoadFile(filePath))
1998          {
1999             document = editor;
2000             editor.visible = true;
2001          }
2002          else
2003             delete editor;
2004          needFileModified = false;
2005       }
2006
2007       if(document && (document._class == class(PictureEdit) ||
2008             document._class == class(ModelView)))
2009       {
2010          document.Create();
2011          if(document)
2012          {
2013             document.fileName = filePath;
2014             if(workspace && !workspace.holdTracking)
2015                workspace.UpdateOpenedFileInfo(filePath, opened);
2016          }
2017       }
2018       
2019       if(!document && createIfFails != no)
2020       {
2021          if(createIfFails != yes && !needFileModified && 
2022                MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2023             createIfFails = yes;
2024          if(createIfFails == yes || createIfFails == whatever)
2025          {
2026             document = (Window)NewCodeEditor(this, state, true);
2027             if(document)
2028                document.fileName = filePath;
2029          }
2030       }
2031
2032       if(document)
2033       {
2034          if(projectView && document._class == class(CodeEditor) && workspace)
2035          {
2036             int lineNumber, position;
2037             Point scroll;
2038             CodeEditor editor = (CodeEditor)document;
2039             editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2040             editor.openedFileInfo.holdTracking = true;
2041             lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2042             position = Max(editor.openedFileInfo.position - 1, 0);
2043             editor.editBox.GoToLineNum(lineNumber);
2044             editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2045             scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2046             scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2047             editor.editBox.scroll = scroll;
2048             editor.openedFileInfo.holdTracking = false;
2049          }
2050          
2051          if(needFileModified)
2052             document.OnFileModified = OnFileModified;
2053          document.NotifySaved = DocumentSaved;
2054          
2055          if(isProject)
2056             ideSettings.AddRecentProject(document.fileName);
2057          else
2058             ideSettings.AddRecentFile(document.fileName);
2059          ide.UpdateRecentMenus();
2060          ide.AdjustFileMenus();
2061          settingsContainer.Save();
2062          
2063          return document;
2064       }
2065       else
2066          return null;
2067    }
2068
2069    // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2070    /*bool Window::GenericDocumentOnClose(bool parentClosing)
2071    {
2072       if(!parentClosing && ide.workspace)
2073          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2074       return true;
2075    }*/
2076    bool ModelView::ModelViewOnClose(bool parentClosing)
2077    {
2078       if(!parentClosing && ide.workspace)
2079          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2080       return true;
2081    }
2082    bool PictureEdit::PictureEditOnClose(bool parentClosing)
2083    {
2084       if(!parentClosing && ide.workspace)
2085          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2086       return true;
2087    }
2088
2089    /*
2090    void OnUnloadGraphics(Window window)
2091    {
2092       display.ClearMaterials();
2093       display.ClearTextures();
2094       display.ClearMeshes();
2095    }
2096    */
2097
2098    bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2099    {
2100       caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2101       num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2102       return true;
2103    }
2104
2105    bool OnKeyDown(Key key, unichar ch)
2106    {
2107       switch(key)
2108       {
2109          case b:
2110             projectView.Update(null);
2111             break;
2112          case capsLock:
2113             caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2114             break;
2115          case numLock:
2116             num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2117             break;
2118       }
2119       return true;
2120    }
2121
2122    void GoToError(const char * line)
2123    {
2124       if(projectView)
2125          projectView.GoToError(line);
2126    }
2127
2128    void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
2129    {
2130       char *path = text;
2131       char *colon = strchr(text, ':');
2132       char filePath[MAX_LOCATION];
2133       char completePath[MAX_LOCATION];
2134       int line = 0, col = 0;
2135       Project prj = null;
2136
2137       if(text[3] == '(')
2138       {
2139          char * close = strchr(text, ')');
2140          if(close)
2141          {
2142             char name[256];
2143             strncpy(name, &text[4], close - text - 4);
2144             name[close - text - 4] = '\0';
2145             for(p : ide.workspace.projects)
2146             {
2147                if(!strcmp(p.name, name))
2148                {
2149                   path = close + 1;
2150                   prj = p;
2151                   break;
2152                }
2153             }
2154          }
2155       }
2156       if(!prj)
2157          prj = project ? project : (dir ? null : ide.project);
2158       if(colon && (colon[1] == '/' || colon[1] == '\\'))
2159       {
2160          path = (colon - 1 > path) ? colon - 1 : path;
2161          colon = strstr(colon + 1, ":");
2162       }
2163       while(isspace(*path)) path++;
2164       if(colon)
2165       {
2166          strncpy(filePath, path, colon - path);
2167          filePath[colon - path] = '\0';
2168          line = atoi(colon + 1);
2169          colon = strstr(colon + 1, ":");
2170          if(colon)
2171             col = atoi(colon + 1);
2172       }
2173       else if(path - 1 >= path && *(path - 1) == '\"')
2174       {
2175          colon = strchr(path, '\"');
2176          if(colon)
2177          {
2178             strncpy(filePath, path, colon - path);
2179             filePath[colon - path] = '\0';
2180          }
2181       }
2182
2183       if(prj)
2184          strcpy(completePath, prj.topNode.path);
2185       else if(dir && dir[0])
2186          strcpy(completePath, dir);
2187       else
2188          completePath[0] = '\0';
2189       PathCat(completePath, filePath);
2190
2191       if(FileExists(completePath).isFile)
2192       {
2193          CodeEditor codeEditor = (CodeEditor)OpenFile(completePath, normal, true, "", no, normal);
2194          if(codeEditor && line)
2195          {
2196             EditBox editBox = codeEditor.editBox;
2197             editBox.GoToLineNum(line - 1);
2198             editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2199          }
2200       }
2201    }
2202
2203    void OnRedraw(Surface surface)
2204    {
2205       Bitmap bitmap = back.bitmap;
2206       if(bitmap)
2207          surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2208    }
2209
2210    void SheetSelected(SheetType sheetSelected)
2211    {
2212       if(activeChild == sheet)
2213       {
2214          if(sheetSelected == methods)
2215          {
2216             viewPropertiesItem.accelerator = f4;
2217             viewPropertiesItem.parent = viewMenu;
2218             viewMethodsItem.parent = null;
2219          }
2220          else
2221          {
2222             viewMethodsItem.accelerator = f4;
2223             viewMethodsItem.parent = viewMenu;
2224             viewPropertiesItem.parent = null;
2225          }
2226       }
2227       else
2228       {
2229          viewMethodsItem.parent = viewMenu;
2230          viewPropertiesItem.parent = viewMenu;
2231          if(sheetSelected == methods)
2232          {
2233             viewMethodsItem.accelerator = f4;
2234             viewPropertiesItem.accelerator = 0;
2235          }
2236          else
2237          {
2238             viewMethodsItem.accelerator = 0;
2239             viewPropertiesItem.accelerator = f4;
2240          }
2241       }
2242    }
2243
2244    void OnActivateClient(Window client, Window previous)
2245    {
2246       //if(!client || client != previous)
2247       {
2248          Class dataType;
2249          if(!client || client != previous)
2250          {
2251             if(previous)
2252                dataType = previous._class;
2253             if(previous && !strcmp(dataType.name, "CodeEditor"))
2254             {
2255                ((CodeEditor)previous).UpdateFormCode();
2256             }
2257             else if(previous && !strcmp(dataType.name, "Designer"))
2258             {
2259                ((Designer)previous).codeEditor.UpdateFormCode();
2260             }
2261          }
2262
2263          if(client)
2264             dataType = client._class;
2265          if(client && !strcmp(dataType.name, "CodeEditor"))
2266          {
2267             CodeEditor codeEditor = (CodeEditor)client;
2268             SetPrivateModule(codeEditor.privateModule);
2269             SetCurrentContext(codeEditor.globalContext);
2270             SetTopContext(codeEditor.globalContext);
2271             SetGlobalContext(codeEditor.globalContext);
2272             
2273             SetDefines(&codeEditor.defines);
2274             SetImports(&codeEditor.imports);
2275
2276             SetActiveDesigner(codeEditor.designer);
2277             
2278             sheet.codeEditor = codeEditor;
2279             toolBox.codeEditor = codeEditor;
2280
2281             viewDesignerItem.parent = viewMenu;
2282             if(activeChild != codeEditor)
2283             {
2284                viewCodeItem.parent = viewMenu;
2285                viewDesignerItem.accelerator = 0;
2286                viewCodeItem.accelerator = f8;
2287             }
2288             else
2289             {
2290                viewCodeItem.parent = null;
2291                viewDesignerItem.accelerator = f8;
2292             }
2293          }
2294          else if(client && !strcmp(dataType.name, "Designer"))
2295          {
2296             CodeEditor codeEditor = ((Designer)client).codeEditor;
2297             if(codeEditor)
2298             {
2299                SetPrivateModule(codeEditor.privateModule);
2300                SetCurrentContext(codeEditor.globalContext);
2301                SetTopContext(codeEditor.globalContext);
2302                SetGlobalContext(codeEditor.globalContext);
2303                SetDefines(&codeEditor.defines);
2304                SetImports(&codeEditor.imports);
2305             }
2306             else
2307             {
2308                SetPrivateModule(null);
2309                SetCurrentContext(null);
2310                SetTopContext(null);
2311                SetGlobalContext(null);
2312                SetDefines(null);
2313                SetImports(null);
2314             }
2315
2316             SetActiveDesigner((Designer)client);
2317
2318             sheet.codeEditor = codeEditor;
2319             toolBox.codeEditor = codeEditor;
2320
2321             viewCodeItem.parent = viewMenu;
2322             if(activeChild != client)
2323             {
2324                viewDesignerItem.parent = viewMenu;
2325                viewDesignerItem.accelerator = f8;
2326                viewCodeItem.accelerator = 0;
2327             }
2328             else
2329             {
2330                viewDesignerItem.parent = null;
2331                viewCodeItem.accelerator = f8;
2332             }
2333          }
2334          else
2335          {
2336             if(sheet)
2337                sheet.codeEditor = null;
2338             toolBox.codeEditor = null;
2339             SetActiveDesigner(null);
2340
2341             viewDesignerItem.parent = null;
2342             viewCodeItem.parent = null;
2343          }
2344          if(sheet)
2345             SheetSelected(sheet.sheetSelected);
2346       }
2347
2348       projectCompileItem = null;
2349
2350       if(statusBar)
2351       {
2352          statusBar.Clear();
2353          if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
2354          {
2355             CodeEditor codeEditor = (CodeEditor)client;
2356             EditBox editBox = codeEditor.editBox;
2357
2358             statusBar.AddField(pos);
2359
2360             caps = { width = 40, text = $"CAPS", color = app.GetKeyState(capsState) ? black : Color { 128, 128, 128 } };
2361             statusBar.AddField(caps);
2362
2363             ovr = { width = 30, text = $"OVR", color = editBox.overwrite ? black : Color { 128, 128, 128 } };
2364             statusBar.AddField(ovr);
2365
2366             num = { width = 30, text = $"NUM", color = app.GetKeyState(numState) ? black : Color { 128, 128, 128 } };
2367             statusBar.AddField(num);
2368
2369             //statusBar.text = "Ready";
2370
2371             if(projectView && projectView.project)
2372             {
2373                ProjectNode node = projectView.GetNodeFromWindow(client, null);
2374                if(node)
2375                {
2376                   char name[1024];
2377                   sprintf(name, $"Compile %s", node.name);
2378                   projectCompileItem = 
2379                   {
2380                      copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
2381
2382                      bool NotifySelect(MenuItem selection, Modifiers mods)
2383                      {
2384                         if(projectView)
2385                         {
2386                            bool result = false;
2387                            ProjectNode node = null;
2388                            for(p : ide.workspace.projects)
2389                            {
2390                               node = projectView.GetNodeFromWindow(activeClient, p);
2391                               if(node && projectView.Compile(node))
2392                               {
2393                                  result = true;
2394                                  break;
2395                               }
2396                            }
2397                            if(!result && node)
2398                               ide.outputView.buildBox.Logf($"File %s is excluded from current build configuration.\n", node.name);
2399                         }
2400                         return true;
2401                      }
2402                   };
2403                   projectMenu.AddDynamic(projectCompileItem, ide, false);
2404                }
2405             }
2406          }
2407          else
2408          {
2409             caps = ovr = num = null;
2410          }
2411       }
2412    }
2413
2414    bool OnClose(bool parentClosing)
2415    {
2416       //return !projectView.buildInProgress;
2417       if(projectView && projectView.buildInProgress)
2418          return false;
2419       if(DontTerminateDebugSession($"Close IDE"))
2420          return false;
2421       if(findInFilesDialog)
2422          findInFilesDialog.SearchStop();
2423       if(workspace)
2424       {
2425          workspace.timer.Stop();
2426          workspace.Save();
2427       }
2428       ideMainFrame.Destroy(0);
2429       return true;
2430    }
2431
2432    bool OnPostCreate()
2433    {
2434       int c;
2435       for(c = 1; c<app.argc; c++)
2436       {
2437          char fullPath[MAX_LOCATION];
2438          char parentPath[MAX_LOCATION];
2439          char ext[MAX_EXTENSION];
2440          bool isProject;
2441          FileAttribs dirAttribs;
2442          GetWorkingDir(fullPath, MAX_LOCATION);
2443          PathCat(fullPath, app.argv[c]);
2444          StripLastDirectory(fullPath, parentPath);
2445          GetExtension(app.argv[c], ext);
2446          isProject = !strcmpi(ext, "epj");
2447
2448          if(isProject && c > 1) continue;
2449
2450          // Create directory for projects (only)
2451          if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
2452          {
2453             if(isProject && !FileExists(fullPath))
2454             {
2455                // The NewProject will handle directory creation
2456                /*if(!dirAttribs.isDirectory)
2457                {
2458                   MakeDir(parentPath);
2459                   dirAttribs = FileExists(parentPath);
2460                }
2461                if(dirAttribs.isDirectory)*/
2462                {
2463                   char name[MAX_LOCATION];
2464                   NewProjectDialog newProjectDialog;
2465
2466                   if(projectView)
2467                   {
2468                      projectView.visible = false;
2469                      if(!projectView.Destroy(0))
2470                         return true;
2471                   }
2472
2473                   newProjectDialog = { master = this };
2474
2475                   strcpy(name, app.argv[c]);
2476                   StripExtension(name);
2477                   GetLastDirectory(name, name);
2478                   newProjectDialog.projectName.contents = name;
2479                   newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
2480                   newProjectDialog.locationEditBox.path = parentPath;
2481                   newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
2482
2483                   newProjectDialog.Modal();
2484                   if(projectView)
2485                   {
2486                      ideSettings.AddRecentProject(projectView.fileName);
2487                      ide.UpdateRecentMenus();
2488                      settingsContainer.Save();
2489                   }
2490                }
2491                // Open only one project
2492                break;
2493             }
2494             else
2495                ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
2496          }
2497       }
2498       return true;
2499    }
2500
2501    void OnDestroy()
2502    {
2503       // IS THIS NEEDED? WASN'T HERE BEFORE...  Crashes on getting node's projectView otherwise
2504       if(projectView)
2505       {
2506          projectView.visible = false;
2507          projectView.Destroy(0);
2508          projectView = null;
2509       }
2510 #ifdef GDB_DEBUG_GUI
2511       gdbDialog.Destroy(0);
2512       delete gdbDialog;
2513 #endif
2514    }
2515
2516    void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config)
2517    {
2518       int c, len, count;
2519       char * newList;
2520       char * oldPaths[128];
2521       String oldList = new char[maxPathLen];
2522       Array<String> newExePaths { };
2523       //Map<String, bool> exePathExists { };
2524       bool found = false;
2525 #if defined(__unix__) || defined(__APPLE__)
2526       Array<String> newLibPaths { };
2527       Map<String, bool> libPathExists { };
2528 #endif
2529
2530       if(projectsDirs)
2531       {
2532          for(prj : workspace.projects)
2533          {
2534             DirExpression targetDirExp;
2535
2536             // SKIP FIRST PROJECT...
2537             if(prj == workspace.projects.firstIterator.data) continue;
2538
2539             // NOTE: Right now the additional project config dir will be
2540             //       obtained when the debugger is started, so toggling it
2541             //       while building will change which library gets used.
2542             //       To go with the initial state, e.g. when F5 was pressed,
2543             //       we nould need to keep a list of all project's active
2544             //       config upon startup.
2545             targetDirExp = prj.GetTargetDir(compiler, prj.config);
2546
2547             /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
2548                cfg = prj.config;
2549             else
2550             {
2551                for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2552                   if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
2553                      break;
2554                if(!cfg)
2555                {
2556                   for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2557                      if(cfg.targetType == sharedLibrary && cfg.debug)
2558                         break;
2559                }
2560             }*/
2561             if(targetDirExp.dir)
2562             {
2563                char buffer[MAX_LOCATION];
2564 #if defined(__WIN32__)
2565                Array<String> paths = newExePaths;
2566 #else
2567                Array<String> paths = newLibPaths;
2568 #endif
2569                GetSystemPathBuffer(buffer, prj.topNode.path);
2570                PathCat(buffer, targetDirExp.dir);
2571                for(p : paths)
2572                {
2573                   if(!fstrcmp(p, buffer))
2574                   {
2575                      found = true;
2576                      break;
2577                   }
2578                }
2579                if(!found)
2580                   paths.Add(CopyString(buffer));
2581             }
2582             delete targetDirExp;
2583          }
2584       }
2585
2586       for(item : compiler.executableDirs)
2587       {
2588          found = false;
2589          for(p : newExePaths)
2590          {
2591             if(!fstrcmp(p, item))
2592             {
2593                found = true;
2594                break;
2595             }
2596          }
2597          if(!found)
2598             newExePaths.Add(CopySystemPath(item));
2599       }
2600
2601       GetEnvironment("PATH", oldList, maxPathLen);
2602 /*#ifdef _DEBUG
2603       printf("Old value of PATH: %s\n", oldList);
2604 #endif*/
2605       count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
2606       for(c = 0; c < count; c++)
2607       {
2608          found = false;
2609          for(p : newExePaths)
2610          {
2611             if(!fstrcmp(p, oldPaths[c]))
2612             {
2613                found = true;
2614                break;
2615             }
2616          }
2617          if(!found)
2618             newExePaths.Add(CopySystemPath(oldPaths[c]));
2619       }
2620
2621       len = 0;
2622       for(path : newExePaths)
2623          len += strlen(path) + 1;
2624       newList = new char[len + 1];
2625       newList[0] = '\0';
2626       for(path : newExePaths)
2627       {
2628          strcat(newList, path);
2629          strcat(newList, pathListSep);
2630       }
2631       newList[len - 1] = '\0';
2632       SetEnvironment("PATH", newList);
2633 /*#ifdef _DEBUG
2634       printf("New value of PATH: %s\n", newList);
2635 #endif*/
2636       delete newList;
2637
2638       newExePaths.Free();
2639       delete newExePaths;
2640
2641 #if defined(__unix__) || defined(__APPLE__)
2642
2643       for(item : compiler.libraryDirs)
2644       {
2645          if(!libPathExists[item])  // fstrcmp should be used
2646          {
2647             newLibPaths.Add(item);
2648             libPathExists[item] = true;
2649          }
2650       }
2651
2652 #if defined(__APPLE__)
2653       GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
2654 #else
2655       GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
2656 #endif
2657 /*#ifdef _DEBUG
2658       printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
2659 #endif*/
2660       count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
2661       for(c = 0; c < count; c++)
2662       {
2663          if(!libPathExists[oldPaths[c]])  // fstrcmp should be used
2664          {
2665             newLibPaths.Add(oldPaths[c]);
2666             libPathExists[oldPaths[c]] = true;
2667          }
2668       }
2669
2670       len = 0;
2671       for(path : newLibPaths)
2672          len += strlen(path) + 1;
2673       newList = new char[len + 1];
2674       newList[0] = '\0';
2675       for(path : newLibPaths)
2676       {
2677          strcat(newList, path);
2678          strcat(newList, pathListSep);
2679       }
2680       newList[len - 1] = '\0';
2681 #if defined(__APPLE__)
2682       SetEnvironment("DYLD_LIBRARY_PATH", newList);
2683 #else
2684       SetEnvironment("LD_LIBRARY_PATH", newList);
2685 #endif
2686 /*#ifdef _DEBUG
2687       printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
2688 #endif*/
2689       delete newList;
2690
2691       delete newLibPaths;
2692       delete libPathExists;
2693 #endif
2694
2695       if(compiler.distccEnabled && compiler.distccHosts)
2696          SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
2697
2698       delete oldList;
2699    }
2700
2701    void DestroyTemporaryProjectDir()
2702    {
2703       if(tmpPrjDir && tmpPrjDir[0])
2704       {
2705          if(FileExists(tmpPrjDir).isDirectory)
2706             DestroyDir(tmpPrjDir);
2707          property::tmpPrjDir = null;
2708       }
2709    }
2710
2711    IDEWorkSpace()
2712    {
2713       // Graphics Driver Menu
2714       int c;
2715
2716       /*
2717       app.currentSkin.selectionColor = selectionColor;
2718       app.currentSkin.selectionText = selectionText;
2719       */
2720
2721 /*
2722       driverItems = new MenuItem[app.numDrivers];
2723       for(c = 0; c < app.numDrivers; c++)
2724       {
2725          driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
2726          driverItems[c].id = c;
2727          driverItems[c].isRadio = true;         
2728       }
2729 */
2730       driverItems = new MenuItem[2];
2731 #if defined(__unix__)
2732          driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
2733          driverItems[0].id = 0;
2734          driverItems[0].isRadio = true;         
2735 #else
2736          driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
2737          driverItems[0].id = 0;
2738          driverItems[0].isRadio = true;         
2739 #endif
2740          driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
2741          driverItems[1].id = 1;
2742          driverItems[1].isRadio = true;         
2743
2744 /*      skinItems = new MenuItem[app.numSkins];
2745       for(c = 0; c < app.numSkins; c++)
2746       {
2747          skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
2748          skinItems[c].id = c;
2749          skinItems[c].isRadio = true;         
2750       }
2751 */
2752       ideFileDialog.master = this;
2753       ideProjectFileDialog.master = this;
2754
2755       //SetDriverAndSkin();
2756       return true;
2757    }
2758
2759    void UpdateRecentMenus()
2760    {
2761       int c;
2762       Menu fileMenu = menu.FindMenu($"File");
2763       Menu recentFiles = fileMenu.FindMenu($"Recent Files");
2764       Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
2765       char itemName[MAX_LOCATION + 4];
2766       MenuItem item;
2767
2768       recentFiles.Clear();
2769       c = 0;
2770
2771       for(recent : ideSettings.recentFiles)
2772       {
2773          sprintf(itemName, "%d %s", 1 + c, recent);
2774          MakeSystemPath(itemName);
2775          recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
2776          c++;
2777       }
2778
2779       recentProjects.Clear();
2780       c = 0;
2781       for(recent : ideSettings.recentProjects)
2782       {
2783          sprintf(itemName, "%d %s", 1 + c, recent);
2784          MakeSystemPath(itemName);
2785          recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
2786          c++;
2787       }
2788    }
2789
2790    ~IDEWorkSpace()
2791    {
2792       delete driverItems;
2793       delete skinItems;
2794       delete ideSettings;
2795    }
2796 }
2797
2798 void DestroyDir(char * path)
2799 {
2800    RecursiveDeleteFolderFSI fsi { };
2801    fsi.Iterate(path);
2802    delete fsi;
2803 }
2804
2805 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
2806 {
2807    bool preserveRootFolder;
2808
2809    void OutFolder(char * folderPath, bool isRoot)
2810    {
2811       if(!(preserveRootFolder && isRoot))
2812          RemoveDir(folderPath);
2813    }
2814
2815    bool OnFile(char * filePath)
2816    {
2817       DeleteFile(filePath);
2818       return true;
2819    }
2820 }
2821
2822 class IDEApp : GuiApplication
2823 {
2824    //driver = "Win32Console";
2825    // driver = "OpenGL";
2826    // skin = "Aqua";
2827    //skin = "TVision";
2828    bool Init()
2829    {
2830       SetLoggingMode(stdOut, null);
2831       //SetLoggingMode(debug, null);
2832
2833       settingsContainer.Load();
2834 #if defined(__unix__) || defined(__APPLE__)
2835       app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
2836 #else
2837       app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
2838 #endif
2839       ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
2840
2841       SetInIDE(true);
2842
2843       desktop.text = titleECEREIDE;
2844       /*
2845       int c;
2846       for(c = 1; c<app.argc; c++)
2847       {
2848          char fullPath[MAX_LOCATION];
2849          GetWorkingDir(fullPath, MAX_LOCATION);
2850          PathCat(fullPath, app.argv[c]);
2851          ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
2852       }
2853       */
2854       return true;
2855    }
2856 }
2857
2858 IDEMainFrame ideMainFrame { };
2859
2860 define app = ((IDEApp)__thisModule);
2861 #ifdef _DEBUG
2862 define titleECEREIDE = $"ECERE IDE (Debug)";
2863 #else
2864 define titleECEREIDE = $"ECERE IDE";
2865 #endif