ide: improved quick project menu item enabling/disabling.
[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          if(openMethod == normal)
1778          {
1779             if(DontTerminateDebugSession($"Open Project"))
1780                return null;
1781             isProject = true;
1782             if(MenuWindowCloseAll(null, 0))
1783             {
1784                if(projectView)
1785                {
1786                   projectView.visible = false;
1787                   projectView.Destroy(0);
1788                   // Where did this come from? projectView = null;
1789                }
1790                if(!projectView)
1791                {
1792                   for(;;)
1793                   {
1794                      Project project;
1795                      Workspace workspace = null;
1796                      
1797                      if(FileExists(filePath))
1798                      {
1799                         if(!strcmp(extension, ProjectExtension))
1800                         {
1801                            char workspaceFile[MAX_LOCATION];
1802                            strcpy(workspaceFile, filePath);
1803                            ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
1804                            workspace = LoadWorkspace(workspaceFile, filePath);
1805                         }
1806                         else if(!strcmp(extension, WorkspaceExtension))
1807                            workspace = LoadWorkspace(filePath, null);
1808                         else
1809                            return null;
1810                         //project = LoadProject(filePath);
1811                      }
1812                      
1813                      if(workspace)
1814                      {
1815                         char absolutePath[MAX_LOCATION];
1816                         CreateProjectView(workspace, filePath);
1817                         document = projectView;
1818
1819                         workspace.DropInvalidBreakpoints();
1820                         workspace.Save();
1821
1822                         ide.projectView.ShowOutputBuildLog(true);
1823                         {
1824                            CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
1825                            ide.projectView.DisplayCompiler(compiler, false);
1826                            delete compiler;
1827                         }
1828                         UpdateMakefiles();
1829                         {
1830                            char newWorkingDir[MAX_LOCATION];
1831                            StripLastDirectory(filePath, newWorkingDir);
1832                            ChangeFileDialogsDirectory(newWorkingDir, false);
1833                         }
1834                         if(document)
1835                            document.fileName = filePath;
1836
1837                         ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
1838
1839                         // this crashes on starting ide with epj file, solution please?
1840                         // app.UpdateDisplay();
1841
1842                         workspace.holdTracking = true;
1843                         for(ofi : workspace.openedFiles)
1844                         {
1845                            if(ofi.state != closed)
1846                            {
1847                               Window file = OpenFile(ofi.path, normal, true, null, no, normal);
1848                               if(file)
1849                               {
1850                                  char fileName[MAX_LOCATION];
1851                                  ProjectNode node;
1852                                  GetLastDirectory(ofi.path, fileName);
1853                                  node = projectView.project.topNode.Find(fileName, true);
1854                                  if(node)
1855                                     node.EnsureVisible();
1856                               }
1857                            }
1858                         }
1859                         workspace.holdTracking = false;
1860
1861                         workspace.timer.Start();
1862
1863                         findInFilesDialog.mode = FindInFilesMode::project;
1864                         findInFilesDialog.currentDirectory = ide.project.topNode.path;
1865                         
1866                         {
1867                            char location[MAX_LOCATION];
1868                            StripLastDirectory(ide.project.topNode.path, location);
1869                            ChangeProjectFileDialogDirectory(location);
1870                         }
1871                         
1872                         /*
1873                         if(projectView.debugger)
1874                            projectView.debugger.EvaluateWatches();
1875                         */
1876                         
1877                         break;
1878                      }
1879                      else 
1880                      {
1881                         if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
1882                         {
1883                            ideProjectFileDialog.text = openProjectFileDialogTitle;
1884                            if(ideProjectFileDialog.Modal() == cancel)
1885                               return null;
1886                            filePath = ideProjectFileDialog.filePath;
1887                            GetExtension(filePath, extension);
1888                         }
1889                         else
1890                            return null;
1891                      }
1892                   }
1893                }
1894             }
1895             else
1896                return null;
1897          }
1898          else if(openMethod == add)
1899          {
1900             if(workspace)
1901             {
1902                Project prj = null;
1903                char slashFilePath[MAX_LOCATION];
1904                GetSlashPathBuffer(slashFilePath, filePath);
1905                for(p : workspace.projects)
1906                {
1907                   if(!fstrcmp(p.filePath, slashFilePath))
1908                   {
1909                      prj = p;
1910                      break;
1911                   }
1912                }
1913                if(prj)
1914                {
1915                   MessageBox { type = ok, parent = parent, master = this, text = $"Same Project", 
1916                         contents = $"This project is already present in workspace." }.Modal();
1917                }
1918                else
1919                {
1920                   prj = LoadProject(filePath);
1921                   if(prj)
1922                   {
1923                      CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1924                      workspace.projects.Add(prj);
1925                      if(projectView)
1926                         projectView.AddNode(prj.topNode, null);
1927                      workspace.modified = true;
1928                      workspace.Save();
1929                      findInFilesDialog.AddProjectItem(prj);
1930                      projectView.ShowOutputBuildLog(true);
1931                      projectView.DisplayCompiler(compiler, false);
1932                      projectView.ProjectUpdateMakefileForAllConfigs(prj);
1933                      delete compiler;
1934
1935                      {
1936                         char location[MAX_LOCATION];
1937                         StripLastDirectory(prj.topNode.path, location);
1938                         ChangeProjectFileDialogDirectory(location);
1939                      }
1940
1941                      // projectView is associated with the main project and not with the one just added but
1942                      return projectView; // just to let the caller know something was opened
1943                   }
1944                }
1945             }
1946             else
1947                return null;
1948          }
1949       }
1950       else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
1951             !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
1952             !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
1953       {
1954          if(FileExists(filePath))
1955             document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable, 
1956                                        hasVertScroll = true, hasHorzScroll = true, parent = this, state = state, 
1957                                        visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
1958                                     };
1959          if(!document)
1960             MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
1961       }
1962 #ifndef NO3D
1963       else if(!strcmp(extension, "3ds"))
1964       {
1965          if(FileExists(filePath))
1966             document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable, 
1967                                     hasVertScroll = true, hasHorzScroll = true, parent = this, state = state, 
1968                                     visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
1969                                     };
1970
1971          if(!document)
1972             MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
1973       }
1974 #endif
1975       else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
1976             !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
1977             !strcmp(extension, "htm") || !strcmp(extension, "html") ||
1978             !strcmp(extension, "css") || !strcmp(extension, "php") ||
1979             !strcmp(extension, "js"))
1980       {
1981          CodeEditor editor { parent = this, state = state, visible = false };
1982          editor.updatingCode = true;
1983          if(editor.LoadFile(filePath))
1984          {
1985             document = editor;
1986             editor.visible = true;
1987          }
1988          else
1989             delete editor;
1990          needFileModified = false;
1991       }
1992       else
1993       {
1994          CodeEditor editor { parent = this, state = state, visible = false };
1995          if(editor.LoadFile(filePath))
1996          {
1997             document = editor;
1998             editor.visible = true;
1999          }
2000          else
2001             delete editor;
2002          needFileModified = false;
2003       }
2004
2005       if(document && (document._class == class(PictureEdit) ||
2006             document._class == class(ModelView)))
2007       {
2008          document.Create();
2009          if(document)
2010          {
2011             document.fileName = filePath;
2012             if(workspace && !workspace.holdTracking)
2013                workspace.UpdateOpenedFileInfo(filePath, opened);
2014          }
2015       }
2016       
2017       if(!document && createIfFails != no)
2018       {
2019          if(createIfFails != yes && !needFileModified && 
2020                MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2021             createIfFails = yes;
2022          if(createIfFails == yes || createIfFails == whatever)
2023          {
2024             document = (Window)NewCodeEditor(this, state, true);
2025             if(document)
2026                document.fileName = filePath;
2027          }
2028       }
2029
2030       if(document)
2031       {
2032          if(projectView && document._class == class(CodeEditor) && workspace)
2033          {
2034             int lineNumber, position;
2035             Point scroll;
2036             CodeEditor editor = (CodeEditor)document;
2037             editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2038             editor.openedFileInfo.holdTracking = true;
2039             lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2040             position = Max(editor.openedFileInfo.position - 1, 0);
2041             editor.editBox.GoToLineNum(lineNumber);
2042             editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2043             scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2044             scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2045             editor.editBox.scroll = scroll;
2046             editor.openedFileInfo.holdTracking = false;
2047          }
2048          
2049          if(needFileModified)
2050             document.OnFileModified = OnFileModified;
2051          document.NotifySaved = DocumentSaved;
2052          
2053          if(isProject)
2054             ideSettings.AddRecentProject(document.fileName);
2055          else
2056             ideSettings.AddRecentFile(document.fileName);
2057          ide.UpdateRecentMenus();
2058          ide.AdjustFileMenus();
2059          settingsContainer.Save();
2060          
2061          return document;
2062       }
2063       else
2064          return null;
2065    }
2066
2067    // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2068    /*bool Window::GenericDocumentOnClose(bool parentClosing)
2069    {
2070       if(!parentClosing && ide.workspace)
2071          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2072       return true;
2073    }*/
2074    bool ModelView::ModelViewOnClose(bool parentClosing)
2075    {
2076       if(!parentClosing && ide.workspace)
2077          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2078       return true;
2079    }
2080    bool PictureEdit::PictureEditOnClose(bool parentClosing)
2081    {
2082       if(!parentClosing && ide.workspace)
2083          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2084       return true;
2085    }
2086
2087    /*
2088    void OnUnloadGraphics(Window window)
2089    {
2090       display.ClearMaterials();
2091       display.ClearTextures();
2092       display.ClearMeshes();
2093    }
2094    */
2095
2096    bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2097    {
2098       caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2099       num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2100       return true;
2101    }
2102
2103    bool OnKeyDown(Key key, unichar ch)
2104    {
2105       switch(key)
2106       {
2107          case b:
2108             projectView.Update(null);
2109             break;
2110          case capsLock:
2111             caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2112             break;
2113          case numLock:
2114             num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2115             break;
2116       }
2117       return true;
2118    }
2119
2120    void GoToError(const char * line)
2121    {
2122       if(projectView)
2123          projectView.GoToError(line);
2124    }
2125
2126    void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
2127    {
2128       char *path = text;
2129       char *colon = strchr(text, ':');
2130       char filePath[MAX_LOCATION];
2131       char completePath[MAX_LOCATION];
2132       int line = 0, col = 0;
2133       Project prj = null;
2134
2135       if(text[3] == '(')
2136       {
2137          char * close = strchr(text, ')');
2138          if(close)
2139          {
2140             char name[256];
2141             strncpy(name, &text[4], close - text - 4);
2142             name[close - text - 4] = '\0';
2143             for(p : ide.workspace.projects)
2144             {
2145                if(!strcmp(p.name, name))
2146                {
2147                   path = close + 1;
2148                   prj = p;
2149                   break;
2150                }
2151             }
2152          }
2153       }
2154       if(!prj)
2155          prj = project ? project : (dir ? null : ide.project);
2156       if(colon && (colon[1] == '/' || colon[1] == '\\'))
2157       {
2158          path = (colon - 1 > path) ? colon - 1 : path;
2159          colon = strstr(colon + 1, ":");
2160       }
2161       while(isspace(*path)) path++;
2162       if(colon)
2163       {
2164          strncpy(filePath, path, colon - path);
2165          filePath[colon - path] = '\0';
2166          line = atoi(colon + 1);
2167          colon = strstr(colon + 1, ":");
2168          if(colon)
2169             col = atoi(colon + 1);
2170       }
2171       else if(path - 1 >= path && *(path - 1) == '\"')
2172       {
2173          colon = strchr(path, '\"');
2174          if(colon)
2175          {
2176             strncpy(filePath, path, colon - path);
2177             filePath[colon - path] = '\0';
2178          }
2179       }
2180
2181       if(prj)
2182          strcpy(completePath, prj.topNode.path);
2183       else if(dir && dir[0])
2184          strcpy(completePath, dir);
2185       else
2186          completePath[0] = '\0';
2187       PathCat(completePath, filePath);
2188
2189       if(FileExists(completePath).isFile)
2190       {
2191          CodeEditor codeEditor = (CodeEditor)OpenFile(completePath, normal, true, "", no, normal);
2192          if(codeEditor && line)
2193          {
2194             EditBox editBox = codeEditor.editBox;
2195             editBox.GoToLineNum(line - 1);
2196             editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2197          }
2198       }
2199    }
2200
2201    void OnRedraw(Surface surface)
2202    {
2203       Bitmap bitmap = back.bitmap;
2204       if(bitmap)
2205          surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2206    }
2207
2208    void SheetSelected(SheetType sheetSelected)
2209    {
2210       if(activeChild == sheet)
2211       {
2212          if(sheetSelected == methods)
2213          {
2214             viewPropertiesItem.accelerator = f4;
2215             viewPropertiesItem.parent = viewMenu;
2216             viewMethodsItem.parent = null;
2217          }
2218          else
2219          {
2220             viewMethodsItem.accelerator = f4;
2221             viewMethodsItem.parent = viewMenu;
2222             viewPropertiesItem.parent = null;
2223          }
2224       }
2225       else
2226       {
2227          viewMethodsItem.parent = viewMenu;
2228          viewPropertiesItem.parent = viewMenu;
2229          if(sheetSelected == methods)
2230          {
2231             viewMethodsItem.accelerator = f4;
2232             viewPropertiesItem.accelerator = 0;
2233          }
2234          else
2235          {
2236             viewMethodsItem.accelerator = 0;
2237             viewPropertiesItem.accelerator = f4;
2238          }
2239       }
2240    }
2241
2242    void OnActivateClient(Window client, Window previous)
2243    {
2244       //if(!client || client != previous)
2245       {
2246          Class dataType;
2247          if(!client || client != previous)
2248          {
2249             if(previous)
2250                dataType = previous._class;
2251             if(previous && !strcmp(dataType.name, "CodeEditor"))
2252             {
2253                ((CodeEditor)previous).UpdateFormCode();
2254             }
2255             else if(previous && !strcmp(dataType.name, "Designer"))
2256             {
2257                ((Designer)previous).codeEditor.UpdateFormCode();
2258             }
2259          }
2260
2261          if(client)
2262             dataType = client._class;
2263          if(client && !strcmp(dataType.name, "CodeEditor"))
2264          {
2265             CodeEditor codeEditor = (CodeEditor)client;
2266             SetPrivateModule(codeEditor.privateModule);
2267             SetCurrentContext(codeEditor.globalContext);
2268             SetTopContext(codeEditor.globalContext);
2269             SetGlobalContext(codeEditor.globalContext);
2270             
2271             SetDefines(&codeEditor.defines);
2272             SetImports(&codeEditor.imports);
2273
2274             SetActiveDesigner(codeEditor.designer);
2275             
2276             sheet.codeEditor = codeEditor;
2277             toolBox.codeEditor = codeEditor;
2278
2279             viewDesignerItem.parent = viewMenu;
2280             if(activeChild != codeEditor)
2281             {
2282                viewCodeItem.parent = viewMenu;
2283                viewDesignerItem.accelerator = 0;
2284                viewCodeItem.accelerator = f8;
2285             }
2286             else
2287             {
2288                viewCodeItem.parent = null;
2289                viewDesignerItem.accelerator = f8;
2290             }
2291          }
2292          else if(client && !strcmp(dataType.name, "Designer"))
2293          {
2294             CodeEditor codeEditor = ((Designer)client).codeEditor;
2295             if(codeEditor)
2296             {
2297                SetPrivateModule(codeEditor.privateModule);
2298                SetCurrentContext(codeEditor.globalContext);
2299                SetTopContext(codeEditor.globalContext);
2300                SetGlobalContext(codeEditor.globalContext);
2301                SetDefines(&codeEditor.defines);
2302                SetImports(&codeEditor.imports);
2303             }
2304             else
2305             {
2306                SetPrivateModule(null);
2307                SetCurrentContext(null);
2308                SetTopContext(null);
2309                SetGlobalContext(null);
2310                SetDefines(null);
2311                SetImports(null);
2312             }
2313
2314             SetActiveDesigner((Designer)client);
2315
2316             sheet.codeEditor = codeEditor;
2317             toolBox.codeEditor = codeEditor;
2318
2319             viewCodeItem.parent = viewMenu;
2320             if(activeChild != client)
2321             {
2322                viewDesignerItem.parent = viewMenu;
2323                viewDesignerItem.accelerator = f8;
2324                viewCodeItem.accelerator = 0;
2325             }
2326             else
2327             {
2328                viewDesignerItem.parent = null;
2329                viewCodeItem.accelerator = f8;
2330             }
2331          }
2332          else
2333          {
2334             if(sheet)
2335                sheet.codeEditor = null;
2336             toolBox.codeEditor = null;
2337             SetActiveDesigner(null);
2338
2339             viewDesignerItem.parent = null;
2340             viewCodeItem.parent = null;
2341          }
2342          if(sheet)
2343             SheetSelected(sheet.sheetSelected);
2344       }
2345
2346       projectCompileItem = null;
2347
2348       if(statusBar)
2349       {
2350          statusBar.Clear();
2351          if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
2352          {
2353             CodeEditor codeEditor = (CodeEditor)client;
2354             EditBox editBox = codeEditor.editBox;
2355
2356             statusBar.AddField(pos);
2357
2358             caps = { width = 40, text = $"CAPS", color = app.GetKeyState(capsState) ? black : Color { 128, 128, 128 } };
2359             statusBar.AddField(caps);
2360
2361             ovr = { width = 30, text = $"OVR", color = editBox.overwrite ? black : Color { 128, 128, 128 } };
2362             statusBar.AddField(ovr);
2363
2364             num = { width = 30, text = $"NUM", color = app.GetKeyState(numState) ? black : Color { 128, 128, 128 } };
2365             statusBar.AddField(num);
2366
2367             //statusBar.text = "Ready";
2368
2369             if(projectView && projectView.project)
2370             {
2371                ProjectNode node = projectView.GetNodeFromWindow(client, null);
2372                if(node)
2373                {
2374                   char name[1024];
2375                   sprintf(name, $"Compile %s", node.name);
2376                   projectCompileItem = 
2377                   {
2378                      copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
2379
2380                      bool NotifySelect(MenuItem selection, Modifiers mods)
2381                      {
2382                         if(projectView)
2383                         {
2384                            ProjectNode node = projectView.GetNodeFromWindow(activeClient, null);
2385                            if(node)
2386                               projectView.Compile(node);
2387                         }
2388                         return true;
2389                      }
2390                   };
2391                   projectMenu.AddDynamic(projectCompileItem, ide, false);
2392                }
2393             }
2394          }
2395          else
2396          {
2397             caps = ovr = num = null;
2398          }
2399       }
2400    }
2401
2402    bool OnClose(bool parentClosing)
2403    {
2404       //return !projectView.buildInProgress;
2405       if(projectView && projectView.buildInProgress)
2406          return false;
2407       if(DontTerminateDebugSession($"Close IDE"))
2408          return false;
2409       if(findInFilesDialog)
2410          findInFilesDialog.SearchStop();
2411       if(workspace)
2412       {
2413          workspace.timer.Stop();
2414          workspace.Save();
2415       }
2416       ideMainFrame.Destroy(0);
2417       return true;
2418    }
2419
2420    bool OnPostCreate()
2421    {
2422       int c;
2423       for(c = 1; c<app.argc; c++)
2424       {
2425          char fullPath[MAX_LOCATION];
2426          char parentPath[MAX_LOCATION];
2427          char ext[MAX_EXTENSION];
2428          bool isProject;
2429          FileAttribs dirAttribs;
2430          GetWorkingDir(fullPath, MAX_LOCATION);
2431          PathCat(fullPath, app.argv[c]);
2432          StripLastDirectory(fullPath, parentPath);
2433          GetExtension(app.argv[c], ext);
2434          isProject = !strcmpi(ext, "epj");
2435
2436          if(isProject && c > 1) continue;
2437
2438          // Create directory for projects (only)
2439          if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
2440          {
2441             if(isProject && !FileExists(fullPath))
2442             {
2443                // The NewProject will handle directory creation
2444                /*if(!dirAttribs.isDirectory)
2445                {
2446                   MakeDir(parentPath);
2447                   dirAttribs = FileExists(parentPath);
2448                }
2449                if(dirAttribs.isDirectory)*/
2450                {
2451                   char name[MAX_LOCATION];
2452                   NewProjectDialog newProjectDialog;
2453
2454                   if(projectView)
2455                   {
2456                      projectView.visible = false;
2457                      if(!projectView.Destroy(0))
2458                         return true;
2459                   }
2460
2461                   newProjectDialog = { master = this };
2462
2463                   strcpy(name, app.argv[c]);
2464                   StripExtension(name);
2465                   GetLastDirectory(name, name);
2466                   newProjectDialog.projectName.contents = name;
2467                   newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
2468                   newProjectDialog.locationEditBox.path = parentPath;
2469                   newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
2470
2471                   newProjectDialog.Modal();
2472                   if(projectView)
2473                   {
2474                      ideSettings.AddRecentProject(projectView.fileName);
2475                      ide.UpdateRecentMenus();
2476                      settingsContainer.Save();
2477                   }
2478                }
2479                // Open only one project
2480                break;
2481             }
2482             else
2483                ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
2484          }
2485       }
2486       return true;
2487    }
2488
2489    void OnDestroy()
2490    {
2491       // IS THIS NEEDED? WASN'T HERE BEFORE...  Crashes on getting node's projectView otherwise
2492       if(projectView)
2493       {
2494          projectView.visible = false;
2495          projectView.Destroy(0);
2496          projectView = null;
2497       }
2498 #ifdef GDB_DEBUG_GUI
2499       gdbDialog.Destroy(0);
2500       delete gdbDialog;
2501 #endif
2502    }
2503
2504    void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config)
2505    {
2506       int c, len, count;
2507       char * newList;
2508       char * oldPaths[128];
2509       String oldList = new char[maxPathLen];
2510       Array<String> newExePaths { };
2511       //Map<String, bool> exePathExists { };
2512       bool found = false;
2513 #if defined(__unix__) || defined(__APPLE__)
2514       Array<String> newLibPaths { };
2515       Map<String, bool> libPathExists { };
2516 #endif
2517
2518       if(projectsDirs)
2519       {
2520          for(prj : workspace.projects)
2521          {
2522             DirExpression targetDirExp;
2523
2524             // SKIP FIRST PROJECT...
2525             if(prj == workspace.projects.firstIterator.data) continue;
2526
2527             // NOTE: Right now the additional project config dir will be
2528             //       obtained when the debugger is started, so toggling it
2529             //       while building will change which library gets used.
2530             //       To go with the initial state, e.g. when F5 was pressed,
2531             //       we nould need to keep a list of all project's active
2532             //       config upon startup.
2533             targetDirExp = prj.GetTargetDir(compiler, prj.config);
2534
2535             /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
2536                cfg = prj.config;
2537             else
2538             {
2539                for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2540                   if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
2541                      break;
2542                if(!cfg)
2543                {
2544                   for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2545                      if(cfg.targetType == sharedLibrary && cfg.debug)
2546                         break;
2547                }
2548             }*/
2549             if(targetDirExp.dir)
2550             {
2551                char buffer[MAX_LOCATION];
2552 #if defined(__WIN32__)
2553                Array<String> paths = newExePaths;
2554 #else
2555                Array<String> paths = newLibPaths;
2556 #endif
2557                GetSystemPathBuffer(buffer, prj.topNode.path);
2558                PathCat(buffer, targetDirExp.dir);
2559                for(p : paths)
2560                {
2561                   if(!fstrcmp(p, buffer))
2562                   {
2563                      found = true;
2564                      break;
2565                   }
2566                }
2567                if(!found)
2568                   paths.Add(CopyString(buffer));
2569             }
2570             delete targetDirExp;
2571          }
2572       }
2573
2574       for(item : compiler.executableDirs)
2575       {
2576          found = false;
2577          for(p : newExePaths)
2578          {
2579             if(!fstrcmp(p, item))
2580             {
2581                found = true;
2582                break;
2583             }
2584          }
2585          if(!found)
2586             newExePaths.Add(CopySystemPath(item));
2587       }
2588
2589       GetEnvironment("PATH", oldList, maxPathLen);
2590 /*#ifdef _DEBUG
2591       printf("Old value of PATH: %s\n", oldList);
2592 #endif*/
2593       count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
2594       for(c = 0; c < count; c++)
2595       {
2596          found = false;
2597          for(p : newExePaths)
2598          {
2599             if(!fstrcmp(p, oldPaths[c]))
2600             {
2601                found = true;
2602                break;
2603             }
2604          }
2605          if(!found)
2606             newExePaths.Add(CopySystemPath(oldPaths[c]));
2607       }
2608
2609       len = 0;
2610       for(path : newExePaths)
2611          len += strlen(path) + 1;
2612       newList = new char[len + 1];
2613       newList[0] = '\0';
2614       for(path : newExePaths)
2615       {
2616          strcat(newList, path);
2617          strcat(newList, pathListSep);
2618       }
2619       newList[len - 1] = '\0';
2620       SetEnvironment("PATH", newList);
2621 /*#ifdef _DEBUG
2622       printf("New value of PATH: %s\n", newList);
2623 #endif*/
2624       delete newList;
2625
2626       newExePaths.Free();
2627       delete newExePaths;
2628
2629 #if defined(__unix__) || defined(__APPLE__)
2630
2631       for(item : compiler.libraryDirs)
2632       {
2633          if(!libPathExists[item])  // fstrcmp should be used
2634          {
2635             newLibPaths.Add(item);
2636             libPathExists[item] = true;
2637          }
2638       }
2639
2640 #if defined(__APPLE__)
2641       GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
2642 #else
2643       GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
2644 #endif
2645 /*#ifdef _DEBUG
2646       printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
2647 #endif*/
2648       count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
2649       for(c = 0; c < count; c++)
2650       {
2651          if(!libPathExists[oldPaths[c]])  // fstrcmp should be used
2652          {
2653             newLibPaths.Add(oldPaths[c]);
2654             libPathExists[oldPaths[c]] = true;
2655          }
2656       }
2657
2658       len = 0;
2659       for(path : newLibPaths)
2660          len += strlen(path) + 1;
2661       newList = new char[len + 1];
2662       newList[0] = '\0';
2663       for(path : newLibPaths)
2664       {
2665          strcat(newList, path);
2666          strcat(newList, pathListSep);
2667       }
2668       newList[len - 1] = '\0';
2669 #if defined(__APPLE__)
2670       SetEnvironment("DYLD_LIBRARY_PATH", newList);
2671 #else
2672       SetEnvironment("LD_LIBRARY_PATH", newList);
2673 #endif
2674 /*#ifdef _DEBUG
2675       printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
2676 #endif*/
2677       delete newList;
2678
2679       delete newLibPaths;
2680       delete libPathExists;
2681 #endif
2682
2683       if(compiler.distccEnabled && compiler.distccHosts)
2684          SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
2685
2686       delete oldList;
2687    }
2688
2689    void DestroyTemporaryProjectDir()
2690    {
2691       if(tmpPrjDir && tmpPrjDir[0])
2692       {
2693          if(FileExists(tmpPrjDir).isDirectory)
2694             DestroyDir(tmpPrjDir);
2695          property::tmpPrjDir = null;
2696       }
2697    }
2698
2699    IDEWorkSpace()
2700    {
2701       // Graphics Driver Menu
2702       int c;
2703
2704       /*
2705       app.currentSkin.selectionColor = selectionColor;
2706       app.currentSkin.selectionText = selectionText;
2707       */
2708
2709 /*
2710       driverItems = new MenuItem[app.numDrivers];
2711       for(c = 0; c < app.numDrivers; c++)
2712       {
2713          driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
2714          driverItems[c].id = c;
2715          driverItems[c].isRadio = true;         
2716       }
2717 */
2718       driverItems = new MenuItem[2];
2719 #if defined(__unix__)
2720          driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
2721          driverItems[0].id = 0;
2722          driverItems[0].isRadio = true;         
2723 #else
2724          driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
2725          driverItems[0].id = 0;
2726          driverItems[0].isRadio = true;         
2727 #endif
2728          driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
2729          driverItems[1].id = 1;
2730          driverItems[1].isRadio = true;         
2731
2732 /*      skinItems = new MenuItem[app.numSkins];
2733       for(c = 0; c < app.numSkins; c++)
2734       {
2735          skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
2736          skinItems[c].id = c;
2737          skinItems[c].isRadio = true;         
2738       }
2739 */
2740       ideFileDialog.master = this;
2741       ideProjectFileDialog.master = this;
2742
2743       //SetDriverAndSkin();
2744       return true;
2745    }
2746
2747    void UpdateRecentMenus()
2748    {
2749       int c;
2750       Menu fileMenu = menu.FindMenu($"File");
2751       Menu recentFiles = fileMenu.FindMenu($"Recent Files");
2752       Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
2753       char itemName[MAX_LOCATION + 4];
2754       MenuItem item;
2755
2756       recentFiles.Clear();
2757       c = 0;
2758
2759       for(recent : ideSettings.recentFiles)
2760       {
2761          sprintf(itemName, "%d %s", 1 + c, recent);
2762          MakeSystemPath(itemName);
2763          recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
2764          c++;
2765       }
2766
2767       recentProjects.Clear();
2768       c = 0;
2769       for(recent : ideSettings.recentProjects)
2770       {
2771          sprintf(itemName, "%d %s", 1 + c, recent);
2772          MakeSystemPath(itemName);
2773          recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
2774          c++;
2775       }
2776    }
2777
2778    ~IDEWorkSpace()
2779    {
2780       delete driverItems;
2781       delete skinItems;
2782       delete ideSettings;
2783    }
2784 }
2785
2786 void DestroyDir(char * path)
2787 {
2788    RecursiveDeleteFolderFSI fsi { };
2789    fsi.Iterate(path);
2790    delete fsi;
2791 }
2792
2793 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
2794 {
2795    bool preserveRootFolder;
2796
2797    void OutFolder(char * folderPath, bool isRoot)
2798    {
2799       if(!(preserveRootFolder && isRoot))
2800          RemoveDir(folderPath);
2801    }
2802
2803    bool OnFile(char * filePath)
2804    {
2805       DeleteFile(filePath);
2806       return true;
2807    }
2808 }
2809
2810 class IDEApp : GuiApplication
2811 {
2812    //driver = "Win32Console";
2813    // driver = "OpenGL";
2814    // skin = "Aqua";
2815    //skin = "TVision";
2816    bool Init()
2817    {
2818       SetLoggingMode(stdOut, null);
2819       //SetLoggingMode(debug, null);
2820
2821       settingsContainer.Load();
2822 #if defined(__unix__) || defined(__APPLE__)
2823       app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
2824 #else
2825       app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
2826 #endif
2827       ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
2828
2829       SetInIDE(true);
2830
2831       desktop.text = titleECEREIDE;
2832       /*
2833       int c;
2834       for(c = 1; c<app.argc; c++)
2835       {
2836          char fullPath[MAX_LOCATION];
2837          GetWorkingDir(fullPath, MAX_LOCATION);
2838          PathCat(fullPath, app.argv[c]);
2839          ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
2840       }
2841       */
2842       return true;
2843    }
2844 }
2845
2846 IDEMainFrame ideMainFrame { };
2847
2848 define app = ((IDEApp)__thisModule);
2849 #ifdef _DEBUG
2850 define titleECEREIDE = $"ECERE IDE (Debug)";
2851 #else
2852 define titleECEREIDE = $"ECERE IDE";
2853 #endif