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