ide/Toolbar: Fix for Save tool button not working
[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
646       {
647          fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
648
649          // For the toolbar button; clients can still override that for the menu item
650          bool Window::NotifySelect(MenuItem selection, Modifiers mods)
651          {
652             Window w = activeClient;
653             if(w)
654                w.MenuFileSave(null, 0);
655             return true;
656          }
657       };
658       MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
659       MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
660       MenuDivider { fileMenu };
661       MenuItem findInFiles
662       {
663          fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
664          bool NotifySelect(MenuItem selection, Modifiers mods)
665          {
666             findInFilesDialog.replaceMode = false;
667             findInFilesDialog.Show();
668             return true;
669          }
670       }
671       MenuItem replaceInFiles
672       {
673          fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
674          bool NotifySelect(MenuItem selection, Modifiers mods)
675          {
676             findInFilesDialog.replaceMode = true;
677             findInFilesDialog.Show();
678             return true;
679          }
680       }
681       MenuDivider { fileMenu };
682       MenuItem globalSettingsItem
683       {
684          fileMenu, $"Global Settings...", g;
685          bool NotifySelect(MenuItem selection, Modifiers mods)
686          {
687             globalSettingsDialog.master = this;
688             if(ide.workspace && ide.workspace.compiler)
689                globalSettingsDialog.workspaceActiveCompiler = ide.workspace.compiler;
690             else if(ideSettings.defaultCompiler)
691                globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
692             globalSettingsDialog.Modal();
693             return true;
694          }
695       }
696       MenuDivider { fileMenu };
697       Menu recentFiles { fileMenu, $"Recent Files", r };
698       Menu recentProjects { fileMenu, $"Recent Projects", p };
699       MenuDivider { fileMenu };
700       MenuItem exitItem
701       {
702          fileMenu, $"Exit", x, altF4, NotifySelect = MenuFileExit;
703
704          bool NotifySelect(MenuItem selection, Modifiers mods)
705          {
706             ideMainFrame.Destroy(0);
707             return true;
708          }
709       };
710
711       bool FileRecentFile(MenuItem selection, Modifiers mods)
712       {
713          int id = 0;
714          for(file : ideSettings.recentFiles)
715          {
716             if(id == selection.id)
717             {
718                OpenFile(file, normal, true, null, no, normal);
719                break;
720             }
721             id++;
722          }
723          return true;
724       }
725
726       bool FileRecentProject(MenuItem selection, Modifiers mods)
727       {
728          int id = 0;
729          for(file : ideSettings.recentProjects)
730          {
731             if(id == selection.id)
732             {
733                OpenFile(file, normal, true, null, no, normal);
734                break;
735             }
736             id++;
737          }
738          return true;
739       }
740
741    MenuPlacement editMenu { menu, $"Edit", e };
742    
743    Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
744       MenuItem projectNewItem
745       {
746          projectMenu, $"New...", n, Key { n, true, true };
747          bitmap = { ":actions/projNew.png" };
748          bool NotifySelect(MenuItem selection, Modifiers mods)
749          {
750             if(!DontTerminateDebugSession($"New Project"))
751                if(MenuWindowCloseAll(null, 0))
752                {
753                   NewProjectDialog newProjectDialog;
754
755                   if(projectView)
756                   {
757                      projectView.visible = false;
758                      if(!projectView.Destroy(0))
759                         return true;
760                   }
761                   
762                   newProjectDialog = { master = this };
763                   newProjectDialog.Modal();
764                   if(projectView)
765                   {
766                      ideSettings.AddRecentProject(projectView.fileName);
767                      ide.UpdateRecentMenus();
768                      settingsContainer.Save();
769                   }
770                }
771             return true;
772          }
773       }
774       MenuItem projectOpenItem
775       {
776          projectMenu, $"Open...", o, Key { o, true, true };
777          bitmap = { ":actions/projOpen.png" };
778          bool NotifySelect(MenuItem selection, Modifiers mods)
779          {
780             if(ideSettings.ideProjectFileDialogLocation)
781                ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
782
783             ideProjectFileDialog.text = openProjectFileDialogTitle;
784             if(ideProjectFileDialog.Modal() == ok)
785             {
786                OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal);
787                //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
788             }
789             return true;
790          }
791       }
792       MenuItem projectQuickItem
793       {
794          projectMenu, $"Quick...", q, f7, disabled = true;
795          bool NotifySelect(MenuItem selection, Modifiers mods)
796          {
797             if(!projectView)
798                QuickProjectDialog{ this }.Modal();
799             return true;
800          }
801       }
802       MenuItem projectAddItem
803       {
804          projectMenu, $"Add project to workspace...", a, Key { a, true, true };
805          bitmap = { ":actions/projAdd.png" };
806          disabled = true;
807          bool NotifySelect(MenuItem selection, Modifiers mods)
808          {
809             if(ideSettings.ideProjectFileDialogLocation)
810                ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
811
812             ideProjectFileDialog.text = addProjectFileDialogTitle;
813             for(;;)
814             {
815                if(ideProjectFileDialog.Modal() == ok)
816                {
817                   if(OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add))
818                      break;
819                   if(MessageBox { type = yesNo, master = this, text = $"Error opening project file", 
820                         contents = $"Add a different project?" }.Modal() == no)
821                   {
822                      break;
823                   }
824                }
825                else
826                   break;
827             }
828             return true;
829          }
830       }
831       MenuItem projectCloseItem
832       {
833          projectMenu, $"Close", c, disabled = true;
834          bool NotifySelect(MenuItem selection, Modifiers mods)
835          {
836             if(projectView)
837             {
838                if(!ide.DontTerminateDebugSession($"Project Close"))
839                {
840                   if(findInFilesDialog)
841                      findInFilesDialog.SearchStop();
842                   projectView.visible = false;
843                   if(projectView.Destroy(0))
844                      MenuWindowCloseAll(null, 0);
845                   {
846                      char workingDir[MAX_LOCATION];
847                      GetWorkingDir(workingDir, MAX_LOCATION);
848                      findInFilesDialog.currentDirectory = workingDir;
849                      ideMainFrame.text = titleECEREIDE;
850                   }
851                }
852             }
853             return true;
854          }
855       }
856       MenuDivider { projectMenu };
857       MenuItem activeCompilerItem
858       {
859          projectMenu, $"Active Compiler...", g, /*altF5, */disabled = true;
860          bool NotifySelect(MenuItem selection, Modifiers mods)
861          {
862             projectView.MenuCompiler(null, mods);
863             return true;
864          }
865       }
866       MenuItem projectActiveConfigItem
867       {
868          projectMenu, $"Active Configuration...", g, altF5, disabled = true;
869          bool NotifySelect(MenuItem selection, Modifiers mods)
870          {
871             projectView.MenuConfig(projectView.active ? selection : null, mods);
872             return true;
873          }
874       }
875       MenuItem projectSettingsItem
876       {
877          projectMenu, $"Settings...", s, altF7, disabled = true;
878          bool NotifySelect(MenuItem selection, Modifiers mods)
879          {
880             projectView.MenuSettings(projectView.active ? selection : null, mods);
881             return true;
882          }
883       }
884       MenuDivider { projectMenu };
885       MenuItem projectBrowseFolderItem
886       {
887          projectMenu, $"Browse Project Folder", p, disabled = true;
888          bool NotifySelect(MenuItem selection, Modifiers mods)
889          {
890             if(projectView)
891                projectView.MenuBrowseFolder(null, mods);
892             return true;
893          }
894       }
895       MenuDivider { projectMenu };
896       MenuItem projectRunItem
897       {
898          projectMenu, $"Run", r, ctrlF5, disabled = true;
899          bitmap = { ":actions/run.png" };
900          bool NotifySelect(MenuItem selection, Modifiers mods)
901          {
902             if(projectView)
903                projectView.Run(null, mods);
904             return true;
905          }
906       }
907       MenuItem projectBuildItem
908       {
909          projectMenu, $"Build", b, f7, disabled = true;
910          bitmap = { ":actions/build.png" };
911          bool NotifySelect(MenuItem selection, Modifiers mods)
912          {
913             if(projectView)
914                projectView.ProjectBuild(projectView.active ? selection : null, mods);
915             return true;
916          }
917       }
918       MenuItem projectLinkItem
919       {
920          projectMenu, $"Relink", l, disabled = true;
921          bitmap = { ":actions/relink.png" };
922          bool NotifySelect(MenuItem selection, Modifiers mods)
923          {
924             if(projectView)
925                projectView.ProjectLink(projectView.active ? selection : null, mods);
926             return true;
927          }
928       }
929       MenuItem projectRebuildItem
930       {
931          projectMenu, $"Rebuild", d, shiftF7, disabled = true;
932          bitmap = { ":actions/rebuild.png" };
933          bool NotifySelect(MenuItem selection, Modifiers mods)
934          {
935             if(projectView)
936                projectView.ProjectRebuild(projectView.active ? selection : null, mods);
937             return true;
938          }
939       }
940       MenuItem projectCleanItem
941       {
942          projectMenu, $"Clean", e, disabled = true;
943          bitmap = { ":actions/clean.png" };
944          bool NotifySelect(MenuItem selection, Modifiers mods)
945          {
946             if(projectView)
947             {
948                debugger.Stop();
949                projectView.ProjectClean(projectView.active ? selection : null, mods);
950             }
951             return true;
952          }
953       }
954       MenuItem projectRealCleanItem
955       {
956          projectMenu, $"Real Clean", disabled = true;
957          bitmap = { ":actions/clean.png" };
958          bool NotifySelect(MenuItem selection, Modifiers mods)
959          {
960             if(projectView)
961             {
962                debugger.Stop();
963                projectView.ProjectRealClean(projectView.active ? selection : null, mods);
964             }
965             return true;
966          }
967       }
968       MenuItem projectRegenerateItem
969       {
970          projectMenu, $"Regenerate Makefile", m, disabled = true;
971          bitmap = { ":actions/regMakefile.png" };
972          bool NotifySelect(MenuItem selection, Modifiers mods)
973          {
974             if(projectView)
975                projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
976             return true;
977          }
978       }
979       MenuItem projectCompileItem;
980    Menu debugMenu { menu, $"Debug", d, hasMargin = true };
981       MenuItem debugStartResumeItem
982       {
983          debugMenu, $"Start", s, f5, disabled = true;
984          bitmap = { ":actions/debug.png" };
985          NotifySelect = MenuDebugStart;
986       }
987       bool MenuDebugStart(MenuItem selection, Modifiers mods)
988       {
989          if(projectView)
990          {
991             debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
992             if(!projectView.DebugStart())
993                debugStartResumeItem.disabled = false; // same exception
994          }
995          return true;
996       }
997       bool MenuDebugResume(MenuItem selection, Modifiers mods)
998       {
999          if(projectView)
1000             projectView.DebugResume();
1001          return true;
1002       }
1003       MenuItem debugRestartItem
1004       {
1005          debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1006          bitmap = { ":actions/restart.png" };
1007          bool NotifySelect(MenuItem selection, Modifiers mods)
1008          {
1009             if(projectView)
1010                projectView.DebugRestart();
1011             return true;
1012          }
1013       }
1014       MenuItem debugBreakItem
1015       {
1016          debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1017          bitmap = { ":actions/pause.png" };
1018          bool NotifySelect(MenuItem selection, Modifiers mods)
1019          {
1020             if(projectView)
1021                projectView.DebugBreak();
1022             return true;
1023          }
1024       }
1025       MenuItem debugStopItem
1026       {
1027          debugMenu, $"Stop", p, shiftF5, disabled = true;
1028          bitmap = { ":actions/stopDebug.png" };
1029          bool NotifySelect(MenuItem selection, Modifiers mods)
1030          {
1031             if(projectView)
1032                projectView.DebugStop();
1033             return true;
1034          }
1035       }
1036       MenuDivider { debugMenu };
1037       MenuItem debugStepIntoItem
1038       {
1039          debugMenu, $"Step Into", i, f11, disabled = true;
1040          bitmap = { ":actions/stepInto.png" };
1041          bool NotifySelect(MenuItem selection, Modifiers mods)
1042          {
1043             if(projectView)
1044                projectView.DebugStepInto();
1045             return true;
1046          }
1047       }
1048       MenuItem debugStepOverItem
1049       {
1050          debugMenu, $"Step Over", v, f10, disabled = true;
1051          bitmap = { ":actions/stepOver.png" };
1052          bool NotifySelect(MenuItem selection, Modifiers mods)
1053          {
1054             if(projectView)
1055                projectView.DebugStepOver(false);
1056             return true;
1057          }
1058       }
1059       MenuItem debugStepOutItem
1060       {
1061          debugMenu, $"Step Out", o, shiftF11, disabled = true;
1062          bitmap = { ":actions/stepOut.png" };
1063          bool NotifySelect(MenuItem selection, Modifiers mods)
1064          {
1065             if(projectView)
1066                projectView.DebugStepOut(false);
1067             return true;
1068          }
1069       }
1070       MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1071       MenuItem debugSkipStepOverItem
1072       {
1073          debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1074          bool NotifySelect(MenuItem selection, Modifiers mods)
1075          {
1076             if(projectView)
1077                projectView.DebugStepOver(true);
1078             return true;
1079          }
1080       }
1081       MenuItem debugSkipStepOutItem
1082       {
1083          debugMenu, $"Step Out Skipping Breakpoints", t, Key { f11, ctrl = true, shift = true }, disabled = true;
1084          bitmap = { ":actions/skipBreaks.png" };
1085          bool NotifySelect(MenuItem selection, Modifiers mods)
1086          {
1087             if(projectView)
1088                projectView.DebugStepOut(true);
1089             return true;
1090          }
1091       }
1092       MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1093       //MenuDivider { debugMenu };
1094       //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1095    MenuPlacement imageMenu { menu, $"Image", i };
1096    Menu viewMenu { menu, $"View", v };
1097       MenuItem viewProjectItem
1098       {
1099          viewMenu, $"Project View", j, alt0, disabled = true;
1100          bool NotifySelect(MenuItem selection, Modifiers mods)
1101          {
1102             if(projectView)
1103             {
1104                projectView.visible = true;
1105                projectView.Activate();
1106             }
1107             return true;
1108          }
1109       }
1110       MenuPlacement { viewMenu, $"View Designer" };
1111       MenuPlacement { viewMenu, $"View Code" };
1112       MenuPlacement { viewMenu, $"View Properties" };
1113       MenuPlacement { viewMenu, $"View Methods" };
1114       MenuItem viewDesignerItem
1115       {
1116          viewMenu, $"View Designer", d, f8;
1117          bool NotifySelect(MenuItem selection, Modifiers mods)
1118          {
1119             Window client = activeClient;
1120             Class dataType = client._class;
1121             if(!strcmp(dataType.name, "Designer"))
1122             {
1123                client.visible = true;
1124                client.Activate();
1125             }
1126             else
1127                ((CodeEditor)client).ViewDesigner();
1128             return true;
1129          }
1130       }
1131       MenuItem viewCodeItem
1132       {
1133          viewMenu, $"View Code", c, f8;
1134          bool NotifySelect(MenuItem selection, Modifiers mods)
1135          {
1136             Window client = activeClient;
1137             Class dataType = client._class;
1138             if(!strcmp(dataType.name, "Designer"))
1139                client = ((Designer)client).codeEditor;
1140
1141             client.Activate();
1142             // Do this after so the caret isn't moved yet...
1143             client.visible = true;
1144             return true;
1145          }
1146       }
1147       MenuItem viewPropertiesItem
1148       {
1149          viewMenu, $"View Properties", p, f4;
1150          bool NotifySelect(MenuItem selection, Modifiers mods)
1151          {
1152             sheet.visible = true;
1153             sheet.sheetSelected = properties;
1154             sheet.Activate();
1155             return true;
1156          }
1157       }
1158       MenuItem viewMethodsItem
1159       {
1160          viewMenu, $"View Methods", m, f4;
1161          bool NotifySelect(MenuItem selection, Modifiers mods)
1162          {
1163             sheet.visible = true;
1164             sheet.sheetSelected = methods;
1165             sheet.Activate();
1166             return true;
1167          }
1168       }
1169       MenuItem viewToolBoxItem
1170       {
1171          viewMenu, $"View Toolbox", x, f12;
1172          bool NotifySelect(MenuItem selection, Modifiers mods)
1173          {
1174             toolBox.visible = true;
1175             toolBox.Activate();
1176             return true;
1177          }
1178       }
1179       MenuItem viewOutputItem
1180       {
1181          viewMenu, $"Output", o, alt2;
1182          bool NotifySelect(MenuItem selection, Modifiers mods)
1183          {
1184             outputView.Show();
1185             return true;
1186          }
1187       }
1188       MenuItem viewWatchesItem
1189       {
1190          viewMenu, $"Watches", w, alt3;
1191          bool NotifySelect(MenuItem selection, Modifiers mods)
1192          {
1193             watchesView.Show();
1194             return true;
1195          }
1196       }
1197       MenuItem viewThreadsItem
1198       {
1199          viewMenu, $"Threads", t, alt4;
1200          bool NotifySelect(MenuItem selection, Modifiers mods)
1201          {
1202             threadsView.Show();
1203             return true;
1204          }
1205       }
1206       MenuItem viewBreakpointsItem
1207       {
1208          viewMenu, $"Breakpoints", b, alt5;
1209          bool NotifySelect(MenuItem selection, Modifiers mods)
1210          {
1211             breakpointsView.Show();
1212             return true;
1213          }
1214       }
1215       MenuItem viewCallStackItem
1216       {
1217          viewMenu, $"Call Stack", s, alt7;
1218          bool NotifySelect(MenuItem selection, Modifiers mods)
1219          {
1220             callStackView.Show();
1221             return true;
1222          }
1223       }
1224       MenuItem viewAllDebugViews
1225       {
1226          viewMenu, $"All Debug Views", a, alt9;
1227          bool NotifySelect(MenuItem selection, Modifiers mods)
1228          {
1229             outputView.Show();
1230             watchesView.Show();
1231             threadsView.Show();
1232             callStackView.Show();
1233             breakpointsView.Show();
1234             return true;
1235          }
1236       }
1237 #ifdef GDB_DEBUG_GUI
1238       MenuDivider { viewMenu };
1239       MenuItem viewGDBItem
1240       {
1241          viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1242          bool NotifySelect(MenuItem selection, Modifiers mods)
1243          {
1244             gdbDialog.Show();
1245             return true;
1246          }
1247       }
1248 #endif
1249       MenuDivider { viewMenu };
1250       MenuItem viewColorPicker
1251       {
1252          viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1253          bool NotifySelect(MenuItem selection, Modifiers mods)
1254          {
1255             ColorPicker colorPicker { master = this, parent = this, stayOnTop = true };
1256             colorPicker.Create();
1257             return true;
1258          }
1259       }
1260       MenuDivider { viewMenu };
1261       /*
1262       MenuItem
1263       {
1264          viewMenu, "Full Screen", f, checkable = true;
1265
1266          bool NotifySelect(MenuItem selection, Modifiers mods)
1267          {
1268             app.fullScreen ^= true;
1269             SetDriverAndSkin();
1270             anchor = { 0, 0, 0, 0 };
1271             return true;
1272          }
1273       };
1274       */
1275       Menu driversMenu { viewMenu, $"Graphics Driver", v };
1276       //Menu skinsMenu { viewMenu, "GUI Skins", k };
1277    Menu windowMenu { menu, $"Window", w };
1278       MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1279       MenuDivider { windowMenu };
1280       MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1281       MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1282       MenuDivider { windowMenu };
1283       MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1284       MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1285       MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1286       MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1287       MenuDivider { windowMenu };
1288       MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1289    Menu helpMenu { menu, $"Help", h };
1290       MenuItem
1291       {
1292          helpMenu, $"API Reference", r, f1;
1293          bool NotifySelect(MenuItem selection, Modifiers mods)
1294          {
1295             Execute("documentor");
1296             return true;
1297          }
1298       }
1299       MenuDivider { helpMenu };
1300       MenuItem
1301       {
1302          helpMenu, $"About...", a;
1303          bool NotifySelect(MenuItem selection, Modifiers mods)
1304          {
1305             AboutIDE { master = this }.Modal();
1306             return true;
1307          }
1308       }
1309
1310    property ToolBox toolBox
1311    {
1312       get { return toolBox; }
1313    }
1314
1315    property Sheet sheet
1316    {
1317       get { return sheet; }
1318    }
1319
1320    property Project project
1321    {
1322       get { return projectView ? projectView.project : null; }
1323    }
1324
1325    property Workspace workspace
1326    {
1327       get { return projectView ? projectView.workspace : null; }
1328    }
1329
1330    FindInFilesDialog findInFilesDialog
1331    {
1332       master = this, parent = this;
1333       filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1334       filter = 1;
1335    };
1336
1337 #ifdef GDB_DEBUG_GUI
1338    GDBDialog gdbDialog
1339    {
1340       master = this, parent = this;
1341       anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1342
1343       void OnCommand(char * string)
1344       {
1345          if(ide)
1346             ide.debugger.SendGDBCommand(string);
1347       }
1348    };
1349 #endif
1350    
1351    bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1352    {
1353       //app.driver = app.drivers[selection.id];
1354 #ifdef __unix__
1355       app.driver = selection.id ? "OpenGL" : "X";
1356 #else
1357       app.driver = selection.id ? "OpenGL" : "GDI";
1358 #endif
1359       delete ideSettings.displayDriver;
1360       ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1361
1362       settingsContainer.Save();
1363       //SetDriverAndSkin();
1364       return true;
1365    }
1366
1367    bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1368    {
1369       app.skin = app.skins[selection.id];
1370       SetDriverAndSkin();
1371       return true;
1372    }
1373
1374    void SetDriverAndSkin()
1375    {
1376       int c;
1377       for(c = 0; c < app.numSkins; c++)
1378          if(!strcmp(app.skins[c], app.skin))
1379          {
1380             skinItems[c].checked = true;
1381             break;
1382          }
1383       for(c = 0; c < app.numDrivers; c++)
1384          if(!strcmp(app.drivers[c], app.driver))
1385          {
1386             driverItems[c].checked = true;
1387             break;
1388          }
1389    }
1390
1391    ProjectView CreateProjectView(Workspace workspace, char * fileName)
1392    {
1393       Project project = workspace.projects.firstIterator.data;
1394       projectView = ProjectView
1395       {
1396          this;
1397          fileName = fileName;
1398          
1399          void NotifyDestroyed(Window window, DialogResult result)
1400          {
1401             projectView = null;
1402             text = titleECEREIDE;
1403             
1404             AdjustMenus();
1405          }
1406       };
1407       projectView.Create();
1408       RepositionWindows(false);
1409
1410       // Leave it after Create to avoid flicker due to seeing IDE without a project view
1411       projectView.workspace = workspace;
1412       projectView.project = project;
1413       ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1414
1415       AdjustMenus();
1416
1417       ide.breakpointsView.LoadFromWorkspace();
1418       ide.watchesView.LoadFromWorkspace();
1419
1420       findInFilesDialog.projectNodeField.userData = projectView;
1421
1422       {
1423          char fileName[MAX_LOCATION];
1424          strcpy(fileName, project.topNode.path);
1425          PathCat(fileName, project.topNode.name);
1426       }
1427       return projectView;
1428    }
1429
1430    bool GetDebugMenusDisabled()
1431    {
1432       if(projectView)
1433       {
1434          Project project = projectView.project;
1435          if(project)
1436             if(project.GetTargetType(project.config) == executable)
1437                return false;
1438            
1439       }
1440       return true;
1441    }
1442
1443    void RepositionWindows(bool expand)
1444    {
1445       if(this)
1446       {
1447          Window child;
1448          bool inDebugMode = debugger.isActive;
1449          bool callStackVisible = expand ? false : callStackView.visible;
1450          bool threadsVisible = expand ? false : threadsView.visible;
1451          bool watchesVisible = expand ? false : watchesView.visible;
1452          bool breakpointsVisible = expand ? false : breakpointsView.visible;
1453          bool toolBoxVisible = toolBox.visible;
1454          bool outputVisible = expand ? false : outputView.visible;
1455          int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1456          int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1457          
1458          for(child = firstChild; child; child = child.next)
1459          {
1460             if(child._class == class(CodeEditor) || child._class == class(Designer) || 
1461                child._class == class(Sheet) || child._class == class(ProjectView))
1462             {
1463                Anchor anchor = child.anchor;
1464                anchor.top = topDistance;
1465                anchor.bottom = bottomDistance;
1466                if(child._class == class(CodeEditor) || child._class == class(Designer))
1467                {
1468                   anchor.right = toolBoxVisible ? 150 : 0;
1469                }
1470                child.anchor = anchor;
1471             }
1472             else if(expand)
1473             {
1474                if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) || 
1475                   child._class == class(BreakpointsView))
1476                   child.visible = false;
1477             }
1478          }
1479          // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1480          Update(null);
1481       }
1482    }
1483
1484    bool ShowCodeEditor()
1485    {
1486       if(activeClient)
1487          activeClient.Activate();
1488       else if(projectView)
1489       { 
1490          projectView.visible = true;
1491          projectView.Activate();
1492       }
1493       else
1494       {
1495          sheet.visible = true;
1496          sheet.Activate();
1497       }
1498       return false;
1499    }
1500
1501    bool ShouldStopBuild()
1502    {
1503       return projectView.stopBuild;
1504    }
1505
1506    void DocumentSaved(Window document, char * fileName)
1507    {
1508       ideSettings.AddRecentFile(fileName);
1509       ide.UpdateRecentMenus();
1510       ide.AdjustFileMenus();
1511       settingsContainer.Save();
1512    }
1513
1514    bool Window::OnFileModified(FileChange fileChange, char * param)
1515    {
1516       char temp[4096];
1517       sprintf(temp, $"The document %s was modified by another application.\n"
1518             "Would you like to reload it and lose your changes?", this.fileName);
1519       if(MessageBox { type = yesNo, master = this/*.parent*/,
1520             text = $"Document has been modified", contents = temp }.Modal() == yes)
1521       {
1522          char * fileName = CopyString(this.fileName);
1523          WindowState state = this.state;
1524          Anchor anchor = this.anchor;
1525          Size size = this.size;
1526
1527          this.modifiedDocument = false;
1528          this.Destroy(0);
1529          this = ide.OpenFile(fileName, normal, true, null, no, normal);
1530          if(this)
1531          {
1532             this.anchor = anchor;
1533             this.size = size;
1534             this.SetState(state, true, 0);
1535          }
1536          delete fileName;
1537          return true;
1538       }
1539       return true;
1540    }
1541
1542    void UpdateMakefiles()
1543    {
1544       if(workspace)
1545       {
1546          CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1547          projectView.ShowOutputBuildLog(true);
1548          projectView.DisplayCompiler(compiler, false);
1549          for(prj : workspace.projects)
1550             projectView.ProjectUpdateMakefileForAllConfigs(prj);
1551          delete compiler;
1552       }
1553    }
1554
1555    void AdjustMenus()
1556    {
1557       bool unavailable = !project;
1558
1559       projectAddItem.disabled             = unavailable;
1560       toolBar.buttonAddProject.disabled   = unavailable;
1561
1562       activeCompilerItem.disabled         = unavailable;
1563       projectActiveConfigItem.disabled    = unavailable;
1564       projectSettingsItem.disabled        = unavailable;
1565
1566       projectBrowseFolderItem.disabled    = unavailable;
1567
1568       viewProjectItem.disabled            = unavailable;
1569
1570       AdjustFileMenus();
1571       AdjustBuildMenus();
1572       AdjustDebugMenus();
1573    }
1574
1575    property bool hasOpenedCodeEditors
1576    {
1577       get
1578       {
1579          Window w;
1580          for(w = firstChild; w; w = w.next)
1581             if(w._class == class(CodeEditor) &&
1582                   w.isDocument && !w.closing && w.visible && w.created &&
1583                   w.fileName && w.fileName[0])
1584                return true;
1585          return false;
1586       }
1587    }
1588
1589    void AdjustFileMenus()
1590    {
1591       bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
1592
1593       projectQuickItem.disabled           = unavailable;
1594    }
1595
1596    void AdjustBuildMenus()
1597    {
1598       bool unavailable = project && projectView.buildInProgress;
1599
1600       projectNewItem.disabled             = unavailable;
1601       toolBar.buttonNewProject.disabled   = unavailable;
1602       projectOpenItem.disabled            = unavailable;
1603       toolBar.buttonOpenProject.disabled  = unavailable;
1604
1605       unavailable = !project || projectView.buildInProgress;
1606
1607       projectCloseItem.disabled           = unavailable;
1608       // toolBar.buttonCloseProject.disabled = unavailable;
1609
1610       projectRunItem.disabled    = unavailable || project.GetTargetType(project.config) != executable;
1611       toolBar.buttonRun.disabled = unavailable || project.GetTargetType(project.config) != executable;
1612       projectBuildItem.disabled                 = unavailable;
1613       toolBar.buttonBuild.disabled              = unavailable;
1614       projectLinkItem.disabled                  = unavailable;
1615       toolBar.buttonReLink.disabled             = unavailable;
1616       projectRebuildItem.disabled               = unavailable;
1617       toolBar.buttonRebuild.disabled            = unavailable;
1618       projectCleanItem.disabled                 = unavailable;
1619       toolBar.buttonClean.disabled              = unavailable;
1620       projectRealCleanItem.disabled             = unavailable;
1621       // toolBar.buttonRealClean.disabled          = unavailable;
1622       projectRegenerateItem.disabled            = unavailable;
1623       toolBar.buttonRegenerateMakefile.disabled = unavailable;
1624       projectCompileItem.disabled               = unavailable;
1625
1626       if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
1627       {
1628          MenuItem menu;
1629          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);      if(menu) menu.disabled = unavailable;
1630          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0);       if(menu) menu.disabled = unavailable;
1631          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0);    if(menu) menu.disabled = unavailable;
1632          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0);      if(menu) menu.disabled = unavailable;
1633          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0);  if(menu) menu.disabled = unavailable;
1634          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
1635          projectView.popupMenu.Update(null);
1636       }
1637    }
1638
1639    void AdjustDebugMenus()
1640    {
1641       bool unavailable = !project || project.GetTargetType(project.config) != executable ||
1642                projectView.buildInProgress == buildingMainProject;
1643       bool active = ide.debugger.isActive;
1644       bool executing = ide.debugger.state == running;
1645       //bool holding = ide.debugger.state == stopped;
1646
1647       debugStartResumeItem.disabled       = unavailable || executing;
1648       debugStartResumeItem.text           = active ? $"Resume" : $"Start";
1649       debugStartResumeItem.NotifySelect   = active ? MenuDebugResume : MenuDebugStart;
1650       if(toolBar)
1651       {
1652          toolBar.buttonDebugStartResume.disabled      = unavailable || executing;
1653          toolBar.buttonDebugStartResume.toolTip       = active ? $"Resume" : $"Start";
1654       }
1655
1656       debugBreakItem.disabled             = unavailable || !executing;
1657       debugStopItem.disabled              = unavailable || !active;
1658       debugRestartItem.disabled           = unavailable || !active;
1659       if(toolBar)
1660       {
1661          toolBar.buttonDebugPause.disabled            = unavailable || !executing;
1662          toolBar.buttonDebugStop.disabled             = unavailable || !active;
1663          toolBar.buttonDebugRestart.disabled          = unavailable || !active;
1664       }
1665
1666       debugStepIntoItem.disabled          = unavailable || executing;
1667       debugStepOverItem.disabled          = unavailable || executing;
1668       debugStepOutItem.disabled           = unavailable || executing || !active;
1669       debugSkipStepOverItem.disabled      = unavailable || executing;
1670       debugSkipStepOutItem.disabled       = unavailable || executing || !active;
1671       if(toolBar)
1672       {
1673          toolBar.buttonDebugStepInto.disabled         = unavailable || executing;
1674          toolBar.buttonDebugStepOver.disabled         = unavailable || executing;
1675          toolBar.buttonDebugStepOut.disabled          = unavailable || executing || !active;
1676          toolBar.buttonDebugSkipStepOver.disabled     = unavailable || executing;
1677          // toolBar.buttonDebugSkipStepOutItem.disabled  = unavailable || executing;
1678       }
1679       if((Designer)GetActiveDesigner())
1680       {
1681          CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
1682          if(codeEditor)
1683          {
1684             codeEditor.debugRunToCursor.disabled      = unavailable || executing;
1685             codeEditor.debugSkipRunToCursor.disabled  = unavailable || executing;
1686          }
1687       }
1688    }
1689
1690    void ChangeFileDialogsDirectory(char * directory, bool saveSettings)
1691    {
1692       char tempString[MAX_LOCATION];
1693       strcpy(tempString, directory);
1694       if(saveSettings && !projectView)
1695       {
1696          ideSettings.ideFileDialogLocation = directory;
1697          settingsContainer.Save();
1698       }
1699
1700       ideFileDialog.currentDirectory = tempString;
1701       codeEditorFileDialog.currentDirectory = tempString;
1702       codeEditorFormFileDialog.currentDirectory = tempString;
1703    }
1704
1705    void ChangeProjectFileDialogDirectory(char * directory)
1706    {
1707       ideSettings.ideProjectFileDialogLocation = directory;
1708       settingsContainer.Save();
1709    }
1710
1711    Window FindWindow(char * filePath)
1712    {
1713       Window document = null;
1714
1715       // TOCHECK: Do we need to change slashes here?
1716       for(document = firstChild; document; document = document.next)
1717       {
1718          char * fileName = document.fileName;
1719          if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
1720          {
1721             document.visible = true;
1722             document.Activate();
1723             return document;
1724          }
1725       }
1726       return null;
1727    }
1728
1729    bool DontTerminateDebugSession(char * title)
1730    {
1731       if(debugger.isActive)
1732       {
1733          if(MessageBox { type = yesNo, master = ide, 
1734                            contents = $"Do you want to terminate the debugging session in progress?", 
1735                            text = title }.Modal() == no)
1736             return true;
1737          /*
1738          MessageBox msg { type = yesNo, master = ide, 
1739                            contents = "Do you want to terminate the debugging session in progress?", 
1740                            text = title };
1741          if(msg.Modal() == no)
1742          {
1743             msg.Destroy(0);
1744             delete msg;
1745             return true;
1746          }
1747          msg.Destroy(0);
1748          delete msg;*/
1749       }
1750       return false;
1751    }
1752
1753    Window OpenFile(char * origFilePath, WindowState state, bool visible, char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod)
1754    {
1755       char extension[MAX_EXTENSION] = "";
1756       Window document = null;
1757       bool isProject = false;
1758       bool needFileModified = true;
1759       char winFilePath[MAX_LOCATION];
1760       char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
1761
1762       if(!type)
1763       {
1764          GetExtension(filePath, extension);
1765          strlwr(extension);
1766       }
1767       else
1768          strcpy(extension, type);
1769
1770       if(strcmp(extension, ProjectExtension))
1771       {
1772          for(document = firstChild; document; document = document.next)
1773          {
1774             char * fileName = document.fileName;
1775             if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
1776             {
1777                document.visible = true;
1778                if(visible)
1779                   document.Activate();
1780                return document;
1781             }
1782          }
1783       }
1784
1785       if(createIfFails == whatever)
1786          ;
1787       else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
1788       {
1789          needFileModified = false;
1790          if(openMethod == normal)
1791          {
1792             if(DontTerminateDebugSession($"Open Project"))
1793                return null;
1794             isProject = true;
1795             if(MenuWindowCloseAll(null, 0))
1796             {
1797                if(projectView)
1798                {
1799                   projectView.visible = false;
1800                   projectView.Destroy(0);
1801                   // Where did this come from? projectView = null;
1802                }
1803                if(!projectView)
1804                {
1805                   for(;;)
1806                   {
1807                      Project project;
1808                      Workspace workspace = null;
1809                      
1810                      if(FileExists(filePath))
1811                      {
1812                         if(!strcmp(extension, ProjectExtension))
1813                         {
1814                            char workspaceFile[MAX_LOCATION];
1815                            strcpy(workspaceFile, filePath);
1816                            ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
1817                            workspace = LoadWorkspace(workspaceFile, filePath);
1818                         }
1819                         else if(!strcmp(extension, WorkspaceExtension))
1820                            workspace = LoadWorkspace(filePath, null);
1821                         else
1822                            return null;
1823                         //project = LoadProject(filePath);
1824                      }
1825                      
1826                      if(workspace)
1827                      {
1828                         char absolutePath[MAX_LOCATION];
1829                         CreateProjectView(workspace, filePath);
1830                         document = projectView;
1831
1832                         workspace.DropInvalidBreakpoints();
1833                         workspace.Save();
1834
1835                         ide.projectView.ShowOutputBuildLog(true);
1836                         {
1837                            CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
1838                            ide.projectView.DisplayCompiler(compiler, false);
1839                            delete compiler;
1840                         }
1841                         UpdateMakefiles();
1842                         {
1843                            char newWorkingDir[MAX_LOCATION];
1844                            StripLastDirectory(filePath, newWorkingDir);
1845                            ChangeFileDialogsDirectory(newWorkingDir, false);
1846                         }
1847                         if(document)
1848                            document.fileName = filePath;
1849
1850                         ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
1851
1852                         // this crashes on starting ide with epj file, solution please?
1853                         // app.UpdateDisplay();
1854
1855                         workspace.holdTracking = true;
1856                         for(ofi : workspace.openedFiles)
1857                         {
1858                            if(ofi.state != closed)
1859                            {
1860                               Window file = OpenFile(ofi.path, normal, true, null, no, normal);
1861                               if(file)
1862                               {
1863                                  char fileName[MAX_LOCATION];
1864                                  ProjectNode node;
1865                                  GetLastDirectory(ofi.path, fileName);
1866                                  node = projectView.project.topNode.Find(fileName, true);
1867                                  if(node)
1868                                     node.EnsureVisible();
1869                               }
1870                            }
1871                         }
1872                         workspace.holdTracking = false;
1873
1874                         workspace.timer.Start();
1875
1876                         findInFilesDialog.mode = FindInFilesMode::project;
1877                         findInFilesDialog.currentDirectory = ide.project.topNode.path;
1878                         
1879                         {
1880                            char location[MAX_LOCATION];
1881                            StripLastDirectory(ide.project.topNode.path, location);
1882                            ChangeProjectFileDialogDirectory(location);
1883                         }
1884                         
1885                         /*
1886                         if(projectView.debugger)
1887                            projectView.debugger.EvaluateWatches();
1888                         */
1889                         
1890                         break;
1891                      }
1892                      else 
1893                      {
1894                         if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
1895                         {
1896                            ideProjectFileDialog.text = openProjectFileDialogTitle;
1897                            if(ideProjectFileDialog.Modal() == cancel)
1898                               return null;
1899                            filePath = ideProjectFileDialog.filePath;
1900                            GetExtension(filePath, extension);
1901                         }
1902                         else
1903                            return null;
1904                      }
1905                   }
1906                }
1907             }
1908             else
1909                return null;
1910          }
1911          else if(openMethod == add)
1912          {
1913             if(workspace)
1914             {
1915                Project prj = null;
1916                char slashFilePath[MAX_LOCATION];
1917                GetSlashPathBuffer(slashFilePath, filePath);
1918                for(p : workspace.projects)
1919                {
1920                   if(!fstrcmp(p.filePath, slashFilePath))
1921                   {
1922                      prj = p;
1923                      break;
1924                   }
1925                }
1926                if(prj)
1927                {
1928                   MessageBox { type = ok, parent = parent, master = this, text = $"Same Project", 
1929                         contents = $"This project is already present in workspace." }.Modal();
1930                }
1931                else
1932                {
1933                   prj = LoadProject(filePath);
1934                   if(prj)
1935                   {
1936                      CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1937                      prj.StartMonitoring();
1938                      workspace.projects.Add(prj);
1939                      if(projectView)
1940                         projectView.AddNode(prj.topNode, null);
1941                      workspace.modified = true;
1942                      workspace.Save();
1943                      findInFilesDialog.AddProjectItem(prj);
1944                      projectView.ShowOutputBuildLog(true);
1945                      projectView.DisplayCompiler(compiler, false);
1946                      projectView.ProjectUpdateMakefileForAllConfigs(prj);
1947                      delete compiler;
1948
1949                      {
1950                         char location[MAX_LOCATION];
1951                         StripLastDirectory(prj.topNode.path, location);
1952                         ChangeProjectFileDialogDirectory(location);
1953                      }
1954
1955                      // projectView is associated with the main project and not with the one just added but
1956                      return projectView; // just to let the caller know something was opened
1957                   }
1958                }
1959             }
1960             else
1961                return null;
1962          }
1963       }
1964       else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
1965             !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
1966             !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
1967       {
1968          if(FileExists(filePath))
1969             document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable, 
1970                                        hasVertScroll = true, hasHorzScroll = true, parent = this, state = state, 
1971                                        visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
1972                                     };
1973          if(!document)
1974             MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
1975       }
1976 #ifndef NO3D
1977       else if(!strcmp(extension, "3ds"))
1978       {
1979          if(FileExists(filePath))
1980             document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable, 
1981                                     hasVertScroll = true, hasHorzScroll = true, parent = this, state = state, 
1982                                     visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
1983                                     };
1984
1985          if(!document)
1986             MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
1987       }
1988 #endif
1989       else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
1990             !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
1991             !strcmp(extension, "htm") || !strcmp(extension, "html") ||
1992             !strcmp(extension, "css") || !strcmp(extension, "php") ||
1993             !strcmp(extension, "js"))
1994       {
1995          CodeEditor editor { parent = this, state = state, visible = false };
1996          editor.updatingCode = true;
1997          if(editor.LoadFile(filePath))
1998          {
1999             document = editor;
2000             editor.visible = true;
2001          }
2002          else
2003             delete editor;
2004          needFileModified = false;
2005       }
2006       else
2007       {
2008          CodeEditor editor { parent = this, state = state, visible = false };
2009          if(editor.LoadFile(filePath))
2010          {
2011             document = editor;
2012             editor.visible = true;
2013          }
2014          else
2015             delete editor;
2016          needFileModified = false;
2017       }
2018
2019       if(document && (document._class == class(PictureEdit) ||
2020             document._class == class(ModelView)))
2021       {
2022          document.Create();
2023          if(document)
2024          {
2025             document.fileName = filePath;
2026             if(workspace && !workspace.holdTracking)
2027                workspace.UpdateOpenedFileInfo(filePath, opened);
2028          }
2029       }
2030       
2031       if(!document && createIfFails != no)
2032       {
2033          if(createIfFails != yes && !needFileModified && 
2034                MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2035             createIfFails = yes;
2036          if(createIfFails == yes || createIfFails == whatever)
2037          {
2038             document = (Window)NewCodeEditor(this, state, true);
2039             if(document)
2040                document.fileName = filePath;
2041          }
2042       }
2043
2044       if(document)
2045       {
2046          if(projectView && document._class == class(CodeEditor) && workspace)
2047          {
2048             int lineNumber, position;
2049             Point scroll;
2050             CodeEditor editor = (CodeEditor)document;
2051             editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2052             editor.openedFileInfo.holdTracking = true;
2053             lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2054             position = Max(editor.openedFileInfo.position - 1, 0);
2055             editor.editBox.GoToLineNum(lineNumber);
2056             editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2057             scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2058             scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2059             editor.editBox.scroll = scroll;
2060             editor.openedFileInfo.holdTracking = false;
2061          }
2062          
2063          if(needFileModified)
2064             document.OnFileModified = OnFileModified;
2065          document.NotifySaved = DocumentSaved;
2066          
2067          if(isProject)
2068             ideSettings.AddRecentProject(document.fileName);
2069          else
2070             ideSettings.AddRecentFile(document.fileName);
2071          ide.UpdateRecentMenus();
2072          ide.AdjustFileMenus();
2073          settingsContainer.Save();
2074          
2075          return document;
2076       }
2077       else
2078          return null;
2079    }
2080
2081    // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2082    /*bool Window::GenericDocumentOnClose(bool parentClosing)
2083    {
2084       if(!parentClosing && ide.workspace)
2085          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2086       return true;
2087    }*/
2088    bool ModelView::ModelViewOnClose(bool parentClosing)
2089    {
2090       if(!parentClosing && ide.workspace)
2091          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2092       return true;
2093    }
2094    bool PictureEdit::PictureEditOnClose(bool parentClosing)
2095    {
2096       if(!parentClosing && ide.workspace)
2097          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2098       return true;
2099    }
2100
2101    /*
2102    void OnUnloadGraphics(Window window)
2103    {
2104       display.ClearMaterials();
2105       display.ClearTextures();
2106       display.ClearMeshes();
2107    }
2108    */
2109
2110    bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2111    {
2112       caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2113       num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2114       return true;
2115    }
2116
2117    bool OnKeyDown(Key key, unichar ch)
2118    {
2119       switch(key)
2120       {
2121          case b:
2122             projectView.Update(null);
2123             break;
2124          case capsLock:
2125             caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2126             break;
2127          case numLock:
2128             num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2129             break;
2130       }
2131       return true;
2132    }
2133
2134    void GoToError(const char * line)
2135    {
2136       if(projectView)
2137          projectView.GoToError(line);
2138    }
2139
2140    void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
2141    {
2142       char *path = text;
2143       char *colon = strchr(text, ':');
2144       char filePath[MAX_LOCATION];
2145       char completePath[MAX_LOCATION];
2146       int line = 0, col = 0;
2147       Project prj = null;
2148
2149       if(text[3] == '(')
2150       {
2151          char * close = strchr(text, ')');
2152          if(close)
2153          {
2154             char name[256];
2155             strncpy(name, &text[4], close - text - 4);
2156             name[close - text - 4] = '\0';
2157             for(p : ide.workspace.projects)
2158             {
2159                if(!strcmp(p.name, name))
2160                {
2161                   path = close + 1;
2162                   prj = p;
2163                   break;
2164                }
2165             }
2166          }
2167       }
2168       if(!prj)
2169          prj = project ? project : (dir ? null : ide.project);
2170       if(colon && (colon[1] == '/' || colon[1] == '\\'))
2171       {
2172          path = (colon - 1 > path) ? colon - 1 : path;
2173          colon = strstr(colon + 1, ":");
2174       }
2175       while(isspace(*path)) path++;
2176       if(colon)
2177       {
2178          strncpy(filePath, path, colon - path);
2179          filePath[colon - path] = '\0';
2180          line = atoi(colon + 1);
2181          colon = strstr(colon + 1, ":");
2182          if(colon)
2183             col = atoi(colon + 1);
2184       }
2185       else if(path - 1 >= path && *(path - 1) == '\"')
2186       {
2187          colon = strchr(path, '\"');
2188          if(colon)
2189          {
2190             strncpy(filePath, path, colon - path);
2191             filePath[colon - path] = '\0';
2192          }
2193       }
2194
2195       if(prj)
2196          strcpy(completePath, prj.topNode.path);
2197       else if(dir && dir[0])
2198          strcpy(completePath, dir);
2199       else
2200          completePath[0] = '\0';
2201       PathCat(completePath, filePath);
2202
2203       if(FileExists(completePath).isFile)
2204       {
2205          CodeEditor codeEditor = (CodeEditor)OpenFile(completePath, normal, true, "", no, normal);
2206          if(codeEditor && line)
2207          {
2208             EditBox editBox = codeEditor.editBox;
2209             editBox.GoToLineNum(line - 1);
2210             editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2211          }
2212       }
2213    }
2214
2215    void OnRedraw(Surface surface)
2216    {
2217       Bitmap bitmap = back.bitmap;
2218       if(bitmap)
2219          surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2220    }
2221
2222    void SheetSelected(SheetType sheetSelected)
2223    {
2224       if(activeChild == sheet)
2225       {
2226          if(sheetSelected == methods)
2227          {
2228             viewPropertiesItem.accelerator = f4;
2229             viewPropertiesItem.parent = viewMenu;
2230             viewMethodsItem.parent = null;
2231          }
2232          else
2233          {
2234             viewMethodsItem.accelerator = f4;
2235             viewMethodsItem.parent = viewMenu;
2236             viewPropertiesItem.parent = null;
2237          }
2238       }
2239       else
2240       {
2241          viewMethodsItem.parent = viewMenu;
2242          viewPropertiesItem.parent = viewMenu;
2243          if(sheetSelected == methods)
2244          {
2245             viewMethodsItem.accelerator = f4;
2246             viewPropertiesItem.accelerator = 0;
2247          }
2248          else
2249          {
2250             viewMethodsItem.accelerator = 0;
2251             viewPropertiesItem.accelerator = f4;
2252          }
2253       }
2254    }
2255
2256    void OnActivateClient(Window client, Window previous)
2257    {
2258       //if(!client || client != previous)
2259       {
2260          Class dataType;
2261          if(!client || client != previous)
2262          {
2263             if(previous)
2264                dataType = previous._class;
2265             if(previous && !strcmp(dataType.name, "CodeEditor"))
2266             {
2267                ((CodeEditor)previous).UpdateFormCode();
2268             }
2269             else if(previous && !strcmp(dataType.name, "Designer"))
2270             {
2271                ((Designer)previous).codeEditor.UpdateFormCode();
2272             }
2273          }
2274
2275          if(client)
2276             dataType = client._class;
2277          if(client && !strcmp(dataType.name, "CodeEditor"))
2278          {
2279             CodeEditor codeEditor = (CodeEditor)client;
2280             SetPrivateModule(codeEditor.privateModule);
2281             SetCurrentContext(codeEditor.globalContext);
2282             SetTopContext(codeEditor.globalContext);
2283             SetGlobalContext(codeEditor.globalContext);
2284             
2285             SetDefines(&codeEditor.defines);
2286             SetImports(&codeEditor.imports);
2287
2288             SetActiveDesigner(codeEditor.designer);
2289             
2290             sheet.codeEditor = codeEditor;
2291             toolBox.codeEditor = codeEditor;
2292
2293             viewDesignerItem.parent = viewMenu;
2294             if(activeChild != codeEditor)
2295             {
2296                viewCodeItem.parent = viewMenu;
2297                viewDesignerItem.accelerator = 0;
2298                viewCodeItem.accelerator = f8;
2299             }
2300             else
2301             {
2302                viewCodeItem.parent = null;
2303                viewDesignerItem.accelerator = f8;
2304             }
2305          }
2306          else if(client && !strcmp(dataType.name, "Designer"))
2307          {
2308             CodeEditor codeEditor = ((Designer)client).codeEditor;
2309             if(codeEditor)
2310             {
2311                SetPrivateModule(codeEditor.privateModule);
2312                SetCurrentContext(codeEditor.globalContext);
2313                SetTopContext(codeEditor.globalContext);
2314                SetGlobalContext(codeEditor.globalContext);
2315                SetDefines(&codeEditor.defines);
2316                SetImports(&codeEditor.imports);
2317             }
2318             else
2319             {
2320                SetPrivateModule(null);
2321                SetCurrentContext(null);
2322                SetTopContext(null);
2323                SetGlobalContext(null);
2324                SetDefines(null);
2325                SetImports(null);
2326             }
2327
2328             SetActiveDesigner((Designer)client);
2329
2330             sheet.codeEditor = codeEditor;
2331             toolBox.codeEditor = codeEditor;
2332
2333             viewCodeItem.parent = viewMenu;
2334             if(activeChild != client)
2335             {
2336                viewDesignerItem.parent = viewMenu;
2337                viewDesignerItem.accelerator = f8;
2338                viewCodeItem.accelerator = 0;
2339             }
2340             else
2341             {
2342                viewDesignerItem.parent = null;
2343                viewCodeItem.accelerator = f8;
2344             }
2345          }
2346          else
2347          {
2348             if(sheet)
2349                sheet.codeEditor = null;
2350             toolBox.codeEditor = null;
2351             SetActiveDesigner(null);
2352
2353             viewDesignerItem.parent = null;
2354             viewCodeItem.parent = null;
2355          }
2356          if(sheet)
2357             SheetSelected(sheet.sheetSelected);
2358       }
2359
2360       projectCompileItem = null;
2361
2362       if(statusBar)
2363       {
2364          statusBar.Clear();
2365          if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
2366          {
2367             CodeEditor codeEditor = (CodeEditor)client;
2368             EditBox editBox = codeEditor.editBox;
2369
2370             statusBar.AddField(pos);
2371
2372             caps = { width = 40, text = $"CAPS", color = app.GetKeyState(capsState) ? black : Color { 128, 128, 128 } };
2373             statusBar.AddField(caps);
2374
2375             ovr = { width = 30, text = $"OVR", color = editBox.overwrite ? black : Color { 128, 128, 128 } };
2376             statusBar.AddField(ovr);
2377
2378             num = { width = 30, text = $"NUM", color = app.GetKeyState(numState) ? black : Color { 128, 128, 128 } };
2379             statusBar.AddField(num);
2380
2381             //statusBar.text = "Ready";
2382
2383             if(projectView && projectView.project)
2384             {
2385                ProjectNode node = projectView.GetNodeFromWindow(client, null);
2386                if(node)
2387                {
2388                   char name[1024];
2389                   sprintf(name, $"Compile %s", node.name);
2390                   projectCompileItem = 
2391                   {
2392                      copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
2393
2394                      bool NotifySelect(MenuItem selection, Modifiers mods)
2395                      {
2396                         if(projectView)
2397                         {
2398                            bool result = false;
2399                            ProjectNode node = null;
2400                            for(p : ide.workspace.projects)
2401                            {
2402                               node = projectView.GetNodeFromWindow(activeClient, p);
2403                               if(node && projectView.Compile(node))
2404                               {
2405                                  result = true;
2406                                  break;
2407                               }
2408                            }
2409                            if(!result && node)
2410                               ide.outputView.buildBox.Logf($"File %s is excluded from current build configuration.\n", node.name);
2411                         }
2412                         return true;
2413                      }
2414                   };
2415                   projectMenu.AddDynamic(projectCompileItem, ide, false);
2416                }
2417             }
2418          }
2419          else
2420          {
2421             caps = ovr = num = null;
2422          }
2423       }
2424    }
2425
2426    bool OnClose(bool parentClosing)
2427    {
2428       //return !projectView.buildInProgress;
2429       if(projectView && projectView.buildInProgress)
2430          return false;
2431       if(DontTerminateDebugSession($"Close IDE"))
2432          return false;
2433       if(findInFilesDialog)
2434          findInFilesDialog.SearchStop();
2435       if(workspace)
2436       {
2437          workspace.timer.Stop();
2438          workspace.Save();
2439       }
2440       ideMainFrame.Destroy(0);
2441       return true;
2442    }
2443
2444    bool OnPostCreate()
2445    {
2446       int c;
2447       for(c = 1; c<app.argc; c++)
2448       {
2449          char fullPath[MAX_LOCATION];
2450          char parentPath[MAX_LOCATION];
2451          char ext[MAX_EXTENSION];
2452          bool isProject;
2453          FileAttribs dirAttribs;
2454          GetWorkingDir(fullPath, MAX_LOCATION);
2455          PathCat(fullPath, app.argv[c]);
2456          StripLastDirectory(fullPath, parentPath);
2457          GetExtension(app.argv[c], ext);
2458          isProject = !strcmpi(ext, "epj");
2459
2460          if(isProject && c > 1) continue;
2461
2462          // Create directory for projects (only)
2463          if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
2464          {
2465             if(isProject && !FileExists(fullPath))
2466             {
2467                // The NewProject will handle directory creation
2468                /*if(!dirAttribs.isDirectory)
2469                {
2470                   MakeDir(parentPath);
2471                   dirAttribs = FileExists(parentPath);
2472                }
2473                if(dirAttribs.isDirectory)*/
2474                {
2475                   char name[MAX_LOCATION];
2476                   NewProjectDialog newProjectDialog;
2477
2478                   if(projectView)
2479                   {
2480                      projectView.visible = false;
2481                      if(!projectView.Destroy(0))
2482                         return true;
2483                   }
2484
2485                   newProjectDialog = { master = this };
2486
2487                   strcpy(name, app.argv[c]);
2488                   StripExtension(name);
2489                   GetLastDirectory(name, name);
2490                   newProjectDialog.projectName.contents = name;
2491                   newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
2492                   newProjectDialog.locationEditBox.path = parentPath;
2493                   newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
2494
2495                   newProjectDialog.Modal();
2496                   if(projectView)
2497                   {
2498                      ideSettings.AddRecentProject(projectView.fileName);
2499                      ide.UpdateRecentMenus();
2500                      settingsContainer.Save();
2501                   }
2502                }
2503                // Open only one project
2504                break;
2505             }
2506             else
2507                ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
2508          }
2509       }
2510       return true;
2511    }
2512
2513    void OnDestroy()
2514    {
2515       // IS THIS NEEDED? WASN'T HERE BEFORE...  Crashes on getting node's projectView otherwise
2516       if(projectView)
2517       {
2518          projectView.visible = false;
2519          projectView.Destroy(0);
2520          projectView = null;
2521       }
2522 #ifdef GDB_DEBUG_GUI
2523       gdbDialog.Destroy(0);
2524       delete gdbDialog;
2525 #endif
2526    }
2527
2528    void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config)
2529    {
2530       int c, len, count;
2531       char * newList;
2532       char * oldPaths[128];
2533       String oldList = new char[maxPathLen];
2534       Array<String> newExePaths { };
2535       //Map<String, bool> exePathExists { };
2536       bool found = false;
2537 #if defined(__unix__) || defined(__APPLE__)
2538       Array<String> newLibPaths { };
2539       Map<String, bool> libPathExists { };
2540 #endif
2541
2542       if(projectsDirs)
2543       {
2544          for(prj : workspace.projects)
2545          {
2546             DirExpression targetDirExp;
2547
2548             // SKIP FIRST PROJECT...
2549             if(prj == workspace.projects.firstIterator.data) continue;
2550
2551             // NOTE: Right now the additional project config dir will be
2552             //       obtained when the debugger is started, so toggling it
2553             //       while building will change which library gets used.
2554             //       To go with the initial state, e.g. when F5 was pressed,
2555             //       we nould need to keep a list of all project's active
2556             //       config upon startup.
2557             targetDirExp = prj.GetTargetDir(compiler, prj.config);
2558
2559             /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
2560                cfg = prj.config;
2561             else
2562             {
2563                for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2564                   if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
2565                      break;
2566                if(!cfg)
2567                {
2568                   for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2569                      if(cfg.targetType == sharedLibrary && cfg.debug)
2570                         break;
2571                }
2572             }*/
2573             if(targetDirExp.dir)
2574             {
2575                char buffer[MAX_LOCATION];
2576 #if defined(__WIN32__)
2577                Array<String> paths = newExePaths;
2578 #else
2579                Array<String> paths = newLibPaths;
2580 #endif
2581                GetSystemPathBuffer(buffer, prj.topNode.path);
2582                PathCat(buffer, targetDirExp.dir);
2583                for(p : paths)
2584                {
2585                   if(!fstrcmp(p, buffer))
2586                   {
2587                      found = true;
2588                      break;
2589                   }
2590                }
2591                if(!found)
2592                   paths.Add(CopyString(buffer));
2593             }
2594             delete targetDirExp;
2595          }
2596       }
2597
2598       for(item : compiler.executableDirs)
2599       {
2600          found = false;
2601          for(p : newExePaths)
2602          {
2603             if(!fstrcmp(p, item))
2604             {
2605                found = true;
2606                break;
2607             }
2608          }
2609          if(!found)
2610             newExePaths.Add(CopySystemPath(item));
2611       }
2612
2613       GetEnvironment("PATH", oldList, maxPathLen);
2614 /*#ifdef _DEBUG
2615       printf("Old value of PATH: %s\n", oldList);
2616 #endif*/
2617       count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
2618       for(c = 0; c < count; c++)
2619       {
2620          found = false;
2621          for(p : newExePaths)
2622          {
2623             if(!fstrcmp(p, oldPaths[c]))
2624             {
2625                found = true;
2626                break;
2627             }
2628          }
2629          if(!found)
2630             newExePaths.Add(CopySystemPath(oldPaths[c]));
2631       }
2632
2633       len = 0;
2634       for(path : newExePaths)
2635          len += strlen(path) + 1;
2636       newList = new char[len + 1];
2637       newList[0] = '\0';
2638       for(path : newExePaths)
2639       {
2640          strcat(newList, path);
2641          strcat(newList, pathListSep);
2642       }
2643       newList[len - 1] = '\0';
2644       SetEnvironment("PATH", newList);
2645 /*#ifdef _DEBUG
2646       printf("New value of PATH: %s\n", newList);
2647 #endif*/
2648       delete newList;
2649
2650       newExePaths.Free();
2651       delete newExePaths;
2652
2653 #if defined(__unix__) || defined(__APPLE__)
2654
2655       for(item : compiler.libraryDirs)
2656       {
2657          if(!libPathExists[item])  // fstrcmp should be used
2658          {
2659             newLibPaths.Add(item);
2660             libPathExists[item] = true;
2661          }
2662       }
2663
2664 #if defined(__APPLE__)
2665       GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
2666 #else
2667       GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
2668 #endif
2669 /*#ifdef _DEBUG
2670       printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
2671 #endif*/
2672       count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
2673       for(c = 0; c < count; c++)
2674       {
2675          if(!libPathExists[oldPaths[c]])  // fstrcmp should be used
2676          {
2677             newLibPaths.Add(oldPaths[c]);
2678             libPathExists[oldPaths[c]] = true;
2679          }
2680       }
2681
2682       len = 0;
2683       for(path : newLibPaths)
2684          len += strlen(path) + 1;
2685       newList = new char[len + 1];
2686       newList[0] = '\0';
2687       for(path : newLibPaths)
2688       {
2689          strcat(newList, path);
2690          strcat(newList, pathListSep);
2691       }
2692       newList[len - 1] = '\0';
2693 #if defined(__APPLE__)
2694       SetEnvironment("DYLD_LIBRARY_PATH", newList);
2695 #else
2696       SetEnvironment("LD_LIBRARY_PATH", newList);
2697 #endif
2698 /*#ifdef _DEBUG
2699       printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
2700 #endif*/
2701       delete newList;
2702
2703       delete newLibPaths;
2704       delete libPathExists;
2705 #endif
2706
2707       if(compiler.distccEnabled && compiler.distccHosts)
2708          SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
2709
2710       delete oldList;
2711    }
2712
2713    void DestroyTemporaryProjectDir()
2714    {
2715       if(tmpPrjDir && tmpPrjDir[0])
2716       {
2717          if(FileExists(tmpPrjDir).isDirectory)
2718             DestroyDir(tmpPrjDir);
2719          property::tmpPrjDir = null;
2720       }
2721    }
2722
2723    IDEWorkSpace()
2724    {
2725       // Graphics Driver Menu
2726       int c;
2727
2728       /*
2729       app.currentSkin.selectionColor = selectionColor;
2730       app.currentSkin.selectionText = selectionText;
2731       */
2732
2733 /*
2734       driverItems = new MenuItem[app.numDrivers];
2735       for(c = 0; c < app.numDrivers; c++)
2736       {
2737          driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
2738          driverItems[c].id = c;
2739          driverItems[c].isRadio = true;         
2740       }
2741 */
2742       driverItems = new MenuItem[2];
2743 #if defined(__unix__)
2744          driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
2745          driverItems[0].id = 0;
2746          driverItems[0].isRadio = true;         
2747 #else
2748          driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
2749          driverItems[0].id = 0;
2750          driverItems[0].isRadio = true;         
2751 #endif
2752          driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
2753          driverItems[1].id = 1;
2754          driverItems[1].isRadio = true;         
2755
2756 /*      skinItems = new MenuItem[app.numSkins];
2757       for(c = 0; c < app.numSkins; c++)
2758       {
2759          skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
2760          skinItems[c].id = c;
2761          skinItems[c].isRadio = true;         
2762       }
2763 */
2764       ideFileDialog.master = this;
2765       ideProjectFileDialog.master = this;
2766
2767       //SetDriverAndSkin();
2768       return true;
2769    }
2770
2771    void UpdateRecentMenus()
2772    {
2773       int c;
2774       Menu fileMenu = menu.FindMenu($"File");
2775       Menu recentFiles = fileMenu.FindMenu($"Recent Files");
2776       Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
2777       char itemName[MAX_LOCATION + 4];
2778       MenuItem item;
2779
2780       recentFiles.Clear();
2781       c = 0;
2782
2783       for(recent : ideSettings.recentFiles)
2784       {
2785          sprintf(itemName, "%d %s", 1 + c, recent);
2786          MakeSystemPath(itemName);
2787          recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
2788          c++;
2789       }
2790
2791       recentProjects.Clear();
2792       c = 0;
2793       for(recent : ideSettings.recentProjects)
2794       {
2795          sprintf(itemName, "%d %s", 1 + c, recent);
2796          MakeSystemPath(itemName);
2797          recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
2798          c++;
2799       }
2800    }
2801
2802    ~IDEWorkSpace()
2803    {
2804       delete driverItems;
2805       delete skinItems;
2806       delete ideSettings;
2807    }
2808 }
2809
2810 void DestroyDir(char * path)
2811 {
2812    RecursiveDeleteFolderFSI fsi { };
2813    fsi.Iterate(path);
2814    delete fsi;
2815 }
2816
2817 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
2818 {
2819    bool preserveRootFolder;
2820
2821    void OutFolder(char * folderPath, bool isRoot)
2822    {
2823       if(!(preserveRootFolder && isRoot))
2824          RemoveDir(folderPath);
2825    }
2826
2827    bool OnFile(char * filePath)
2828    {
2829       DeleteFile(filePath);
2830       return true;
2831    }
2832 }
2833
2834 class IDEApp : GuiApplication
2835 {
2836    //driver = "Win32Console";
2837    // driver = "OpenGL";
2838    // skin = "Aqua";
2839    //skin = "TVision";
2840    bool Init()
2841    {
2842       SetLoggingMode(stdOut, null);
2843       //SetLoggingMode(debug, null);
2844
2845       settingsContainer.Load();
2846 #if defined(__unix__) || defined(__APPLE__)
2847       app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
2848 #else
2849       app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
2850 #endif
2851       ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
2852
2853       SetInIDE(true);
2854
2855       desktop.text = titleECEREIDE;
2856       /*
2857       int c;
2858       for(c = 1; c<app.argc; c++)
2859       {
2860          char fullPath[MAX_LOCATION];
2861          GetWorkingDir(fullPath, MAX_LOCATION);
2862          PathCat(fullPath, app.argv[c]);
2863          ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
2864       }
2865       */
2866       return true;
2867    }
2868 }
2869
2870 IDEMainFrame ideMainFrame { };
2871
2872 define app = ((IDEApp)__thisModule);
2873 #ifdef _DEBUG
2874 define titleECEREIDE = $"ECERE IDE (Debug)";
2875 #else
2876 define titleECEREIDE = $"ECERE IDE";
2877 #endif