ecere, ide; Instance_COM_Initialize, Tokenize, _DualPipeOpen; multiple fixes. finally...
[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             {
854                DialogResult result;
855                NewProjectDialog newProjectDialog { master = this };
856                result = newProjectDialog.Modal();
857                if(result == ok)
858                {
859                   if(ProjectClose())
860                   {
861                      newProjectDialog.CreateNewProject();
862                      if(projectView)
863                      {
864                         ideSettings.AddRecentProject(projectView.fileName);
865                         ide.UpdateRecentMenus();
866                         settingsContainer.Save();
867                      }
868                   }
869                }
870             }
871             return true;
872          }
873       }
874       MenuItem projectOpenItem
875       {
876          projectMenu, $"Open...", o, Key { o, true, true };
877          bitmap = { ":actions/projOpen.png" };
878          bool NotifySelect(MenuItem selection, Modifiers mods)
879          {
880             if(ideSettings.ideProjectFileDialogLocation)
881                ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
882
883             ideProjectFileDialog.text = openProjectFileDialogTitle;
884             if(ideProjectFileDialog.Modal() == ok)
885             {
886                OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
887                //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
888             }
889             return true;
890          }
891       }
892       MenuItem projectQuickItem
893       {
894          projectMenu, $"Quick...", q, f7, disabled = true;
895          bool NotifySelect(MenuItem selection, Modifiers mods)
896          {
897             if(!projectView)
898                QuickProjectDialog { this }.Modal();
899             return true;
900          }
901       }
902       MenuItem projectAddItem
903       {
904          projectMenu, $"Add project to workspace...", a, Key { a, true, true };
905          bitmap = { ":actions/projAdd.png" };
906          disabled = true;
907          bool NotifySelect(MenuItem selection, Modifiers mods)
908          {
909             if(ideSettings.ideProjectFileDialogLocation)
910                ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
911
912             ideProjectFileDialog.text = addProjectFileDialogTitle;
913             for(;;)
914             {
915                if(ideProjectFileDialog.Modal() == ok)
916                {
917                   if(OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
918                      break;
919                   if(MessageBox { type = yesNo, master = this, text = $"Error opening project file", 
920                         contents = $"Add a different project?" }.Modal() == no)
921                   {
922                      break;
923                   }
924                }
925                else
926                   break;
927             }
928             return true;
929          }
930       }
931       MenuItem projectCloseItem
932       {
933          projectMenu, $"Close", c, disabled = true;
934          bool NotifySelect(MenuItem selection, Modifiers mods)
935          {
936             if(projectView)
937             {
938                if(!ide.DontTerminateDebugSession($"Project Close"))
939                   ProjectClose();
940             }
941             return true;
942          }
943       }
944       MenuDivider { projectMenu };
945       MenuItem projectSettingsItem
946       {
947          projectMenu, $"Settings...", s, altF7, disabled = true;
948          bool NotifySelect(MenuItem selection, Modifiers mods)
949          {
950             projectView.MenuSettings(projectView.active ? selection : null, mods);
951             return true;
952          }
953       }
954       MenuDivider { projectMenu };
955       MenuItem projectBrowseFolderItem
956       {
957          projectMenu, $"Browse Project Folder", p, disabled = true;
958          bool NotifySelect(MenuItem selection, Modifiers mods)
959          {
960             if(projectView)
961                projectView.MenuBrowseFolder(null, mods);
962             return true;
963          }
964       }
965       MenuDivider { projectMenu };
966       MenuItem projectRunItem
967       {
968          projectMenu, $"Run", r, ctrlF5, disabled = true;
969          bitmap = { ":actions/run.png" };
970          bool NotifySelect(MenuItem selection, Modifiers mods)
971          {
972             if(projectView)
973                projectView.Run(null, mods);
974             return true;
975          }
976       }
977       MenuItem projectBuildItem
978       {
979          projectMenu, $"Build", b, f7, disabled = true;
980          bitmap = { ":actions/build.png" };
981          bool NotifySelect(MenuItem selection, Modifiers mods)
982          {
983             if(projectView)
984             {
985                if(projectView.buildInProgress == none)
986                   projectView.ProjectBuild(projectView.active ? selection : null, mods);
987                else
988                   projectView.stopBuild = true;
989             }
990             return true;
991          }
992       }
993       MenuItem projectLinkItem
994       {
995          projectMenu, $"Relink", l, disabled = true;
996          bitmap = { ":actions/relink.png" };
997          bool NotifySelect(MenuItem selection, Modifiers mods)
998          {
999             if(projectView)
1000                projectView.ProjectLink(projectView.active ? selection : null, mods);
1001             return true;
1002          }
1003       }
1004       MenuItem projectRebuildItem
1005       {
1006          projectMenu, $"Rebuild", d, shiftF7, disabled = true;
1007          bitmap = { ":actions/rebuild.png" };
1008          bool NotifySelect(MenuItem selection, Modifiers mods)
1009          {
1010             if(projectView)
1011                projectView.ProjectRebuild(projectView.active ? selection : null, mods);
1012             return true;
1013          }
1014       }
1015       MenuItem projectCleanTargetItem
1016       {
1017          projectMenu, $"Clean Target", g, disabled = true;
1018          bitmap = { ":actions/clean.png" };
1019          bool NotifySelect(MenuItem selection, Modifiers mods)
1020          {
1021             if(projectView)
1022             {
1023                debugger.Stop();
1024                projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
1025             }
1026             return true;
1027          }
1028       }
1029       MenuItem projectCleanItem
1030       {
1031          projectMenu, $"Clean", e, disabled = true;
1032          bitmap = { ":actions/clean.png" };
1033          bool NotifySelect(MenuItem selection, Modifiers mods)
1034          {
1035             if(projectView)
1036             {
1037                debugger.Stop();
1038                projectView.ProjectClean(projectView.active ? selection : null, mods);
1039             }
1040             return true;
1041          }
1042       }
1043       MenuItem projectRealCleanItem
1044       {
1045          projectMenu, $"Real Clean", disabled = true;
1046          bitmap = { ":actions/clean.png" };
1047          bool NotifySelect(MenuItem selection, Modifiers mods)
1048          {
1049             if(projectView)
1050             {
1051                debugger.Stop();
1052                projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1053             }
1054             return true;
1055          }
1056       }
1057       MenuItem projectRegenerateItem
1058       {
1059          projectMenu, $"Regenerate Makefile", m, disabled = true;
1060          bitmap = { ":actions/regMakefile.png" };
1061          bool NotifySelect(MenuItem selection, Modifiers mods)
1062          {
1063             if(projectView)
1064                projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1065             return true;
1066          }
1067       }
1068       MenuItem projectCompileItem;
1069    Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1070       MenuItem debugStartResumeItem
1071       {
1072          debugMenu, $"Start", s, f5, disabled = true;
1073          bitmap = { ":actions/debug.png" };
1074          NotifySelect = MenuDebugStart;
1075       }
1076       bool MenuDebugStart(MenuItem selection, Modifiers mods)
1077       {
1078          if(projectView)
1079          {
1080             debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1081             if(!projectView.DebugStart())
1082                debugStartResumeItem.disabled = false; // same exception
1083          }
1084          return true;
1085       }
1086       bool MenuDebugResume(MenuItem selection, Modifiers mods)
1087       {
1088          if(projectView)
1089             projectView.DebugResume();
1090          return true;
1091       }
1092       MenuItem debugRestartItem
1093       {
1094          debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1095          bitmap = { ":actions/restart.png" };
1096          bool NotifySelect(MenuItem selection, Modifiers mods)
1097          {
1098             if(projectView)
1099                projectView.DebugRestart();
1100             return true;
1101          }
1102       }
1103       MenuItem debugBreakItem
1104       {
1105          debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1106          bitmap = { ":actions/pause.png" };
1107          bool NotifySelect(MenuItem selection, Modifiers mods)
1108          {
1109             if(projectView && projectView.buildInProgress != none)
1110                return true;
1111             if(projectView)
1112                projectView.DebugBreak();
1113             return true;
1114          }
1115       }
1116       MenuItem debugStopItem
1117       {
1118          debugMenu, $"Stop", p, shiftF5, disabled = true;
1119          bitmap = { ":actions/stopDebug.png" };
1120          bool NotifySelect(MenuItem selection, Modifiers mods)
1121          {
1122             if(projectView)
1123                projectView.DebugStop();
1124             return true;
1125          }
1126       }
1127       MenuDivider { debugMenu };
1128       MenuItem debugStepIntoItem
1129       {
1130          debugMenu, $"Step Into", i, f11, disabled = true;
1131          bitmap = { ":actions/stepInto.png" };
1132          bool NotifySelect(MenuItem selection, Modifiers mods)
1133          {
1134             if(projectView)
1135                projectView.DebugStepInto();
1136             return true;
1137          }
1138       }
1139       MenuItem debugStepOverItem
1140       {
1141          debugMenu, $"Step Over", v, f10, disabled = true;
1142          bitmap = { ":actions/stepOver.png" };
1143          bool NotifySelect(MenuItem selection, Modifiers mods)
1144          {
1145             if(projectView)
1146                projectView.DebugStepOver(false);
1147             return true;
1148          }
1149       }
1150       MenuItem debugStepOutItem
1151       {
1152          debugMenu, $"Step Out", o, shiftF11, disabled = true;
1153          bitmap = { ":actions/stepOut.png" };
1154          bool NotifySelect(MenuItem selection, Modifiers mods)
1155          {
1156             if(projectView)
1157                projectView.DebugStepOut(false);
1158             return true;
1159          }
1160       }
1161       MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1162       MenuItem debugSkipStepOverItem
1163       {
1164          debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1165          bool NotifySelect(MenuItem selection, Modifiers mods)
1166          {
1167             if(projectView)
1168                projectView.DebugStepOver(true);
1169             return true;
1170          }
1171       }
1172       MenuItem debugSkipStepOutItem
1173       {
1174          debugMenu, $"Step Out Skipping Breakpoints", t, Key { f11, ctrl = true, shift = true }, disabled = true;
1175          bitmap = { ":actions/skipBreaks.png" };
1176          bool NotifySelect(MenuItem selection, Modifiers mods)
1177          {
1178             if(projectView)
1179                projectView.DebugStepOut(true);
1180             return true;
1181          }
1182       }
1183       MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1184       MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", s };
1185       //MenuDivider { debugMenu };
1186       //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1187    MenuPlacement imageMenu { menu, $"Image", i };
1188    Menu viewMenu { menu, $"View", v };
1189       MenuItem viewProjectItem
1190       {
1191          viewMenu, $"Project View", j, alt0, disabled = true;
1192          bool NotifySelect(MenuItem selection, Modifiers mods)
1193          {
1194             if(projectView)
1195             {
1196                projectView.visible = true;
1197                projectView.Activate();
1198             }
1199             return true;
1200          }
1201       }
1202       MenuPlacement { viewMenu, $"View Designer" };
1203       MenuPlacement { viewMenu, $"View Code" };
1204       MenuPlacement { viewMenu, $"View Properties" };
1205       MenuPlacement { viewMenu, $"View Methods" };
1206       MenuItem viewDesignerItem
1207       {
1208          viewMenu, $"View Designer", d, f8;
1209          bool NotifySelect(MenuItem selection, Modifiers mods)
1210          {
1211             Window client = activeClient;
1212             Class dataType = client._class;
1213             if(!strcmp(dataType.name, "Designer"))
1214             {
1215                client.visible = true;
1216                client.Activate();
1217             }
1218             else
1219                ((CodeEditor)client).ViewDesigner();
1220             return true;
1221          }
1222       }
1223       MenuItem viewCodeItem
1224       {
1225          viewMenu, $"View Code", c, f8;
1226          bool NotifySelect(MenuItem selection, Modifiers mods)
1227          {
1228             Window client = activeClient;
1229             Class dataType = client._class;
1230             if(!strcmp(dataType.name, "Designer"))
1231                client = ((Designer)client).codeEditor;
1232
1233             client.Activate();
1234             // Do this after so the caret isn't moved yet...
1235             client.visible = true;
1236             return true;
1237          }
1238       }
1239       MenuItem viewPropertiesItem
1240       {
1241          viewMenu, $"View Properties", p, f4;
1242          bool NotifySelect(MenuItem selection, Modifiers mods)
1243          {
1244             sheet.visible = true;
1245             sheet.sheetSelected = properties;
1246             sheet.Activate();
1247             return true;
1248          }
1249       }
1250       MenuItem viewMethodsItem
1251       {
1252          viewMenu, $"View Methods", m, f4;
1253          bool NotifySelect(MenuItem selection, Modifiers mods)
1254          {
1255             sheet.visible = true;
1256             sheet.sheetSelected = methods;
1257             sheet.Activate();
1258             return true;
1259          }
1260       }
1261       MenuItem viewToolBoxItem
1262       {
1263          viewMenu, $"View Toolbox", x, f12;
1264          bool NotifySelect(MenuItem selection, Modifiers mods)
1265          {
1266             toolBox.visible = true;
1267             toolBox.Activate();
1268             return true;
1269          }
1270       }
1271       MenuItem viewOutputItem
1272       {
1273          viewMenu, $"Output", o, alt2;
1274          bool NotifySelect(MenuItem selection, Modifiers mods)
1275          {
1276             outputView.Show();
1277             return true;
1278          }
1279       }
1280       MenuItem viewWatchesItem
1281       {
1282          viewMenu, $"Watches", w, alt3;
1283          bool NotifySelect(MenuItem selection, Modifiers mods)
1284          {
1285             watchesView.Show();
1286             return true;
1287          }
1288       }
1289       MenuItem viewThreadsItem
1290       {
1291          viewMenu, $"Threads", t, alt4;
1292          bool NotifySelect(MenuItem selection, Modifiers mods)
1293          {
1294             threadsView.Show();
1295             return true;
1296          }
1297       }
1298       MenuItem viewBreakpointsItem
1299       {
1300          viewMenu, $"Breakpoints", b, alt5;
1301          bool NotifySelect(MenuItem selection, Modifiers mods)
1302          {
1303             breakpointsView.Show();
1304             return true;
1305          }
1306       }
1307       MenuItem viewCallStackItem
1308       {
1309          viewMenu, $"Call Stack", s, alt7;
1310          bool NotifySelect(MenuItem selection, Modifiers mods)
1311          {
1312             callStackView.Show();
1313             return true;
1314          }
1315       }
1316       MenuItem viewAllDebugViews
1317       {
1318          viewMenu, $"All Debug Views", a, alt9;
1319          bool NotifySelect(MenuItem selection, Modifiers mods)
1320          {
1321             outputView.Show();
1322             watchesView.Show();
1323             threadsView.Show();
1324             callStackView.Show();
1325             breakpointsView.Show();
1326             return true;
1327          }
1328       }
1329 #ifdef GDB_DEBUG_GUI
1330       MenuDivider { viewMenu };
1331       MenuItem viewGDBItem
1332       {
1333          viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1334          bool NotifySelect(MenuItem selection, Modifiers mods)
1335          {
1336             gdbDialog.Show();
1337             return true;
1338          }
1339       }
1340 #endif
1341       MenuDivider { viewMenu };
1342       MenuItem viewColorPicker
1343       {
1344          viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1345          bool NotifySelect(MenuItem selection, Modifiers mods)
1346          {
1347             ColorPicker colorPicker { master = this };
1348             colorPicker.Modal();
1349             return true;
1350          }
1351       }
1352       MenuDivider { viewMenu };
1353       /*
1354       MenuItem
1355       {
1356          viewMenu, "Full Screen", f, checkable = true;
1357
1358          bool NotifySelect(MenuItem selection, Modifiers mods)
1359          {
1360             app.fullScreen ^= true;
1361             SetDriverAndSkin();
1362             anchor = { 0, 0, 0, 0 };
1363             return true;
1364          }
1365       };
1366       */
1367       Menu driversMenu { viewMenu, $"Graphics Driver", v };
1368       //Menu skinsMenu { viewMenu, "GUI Skins", k };
1369    Menu windowMenu { menu, $"Window", w };
1370       MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1371       MenuDivider { windowMenu };
1372       MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1373       MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1374       MenuDivider { windowMenu };
1375       MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1376       MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1377       MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1378       MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1379       MenuDivider { windowMenu };
1380       MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1381    Menu helpMenu { menu, $"Help", h };
1382       MenuItem
1383       {
1384          helpMenu, $"API Reference", r, f1;
1385          bool NotifySelect(MenuItem selection, Modifiers mods)
1386          {
1387             char * p = new char[MAX_LOCATION];
1388             p[0] = '\0';
1389             strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1390             PathCat(p, "documentor");
1391 #if defined(__WIN32__)
1392             ChangeExtension(p, "exe", p);
1393 #endif
1394             if(FileExists(p).isFile)
1395                Execute(p);
1396             else
1397                Execute("documentor");
1398             delete p;
1399             return true;
1400          }
1401       }
1402       MenuDivider { helpMenu };
1403       MenuItem
1404       {
1405          helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1406          bool NotifySelect(MenuItem selection, Modifiers mods)
1407          {
1408             FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1409             return true;
1410          }
1411       }
1412       MenuDivider { helpMenu };
1413       MenuItem
1414       {
1415          helpMenu, $"Documentation Folder", d;
1416          bool NotifySelect(MenuItem selection, Modifiers mods)
1417          {
1418             FindAndShellOpenInstalledFolder("doc");
1419             return true;
1420          }
1421       }
1422       MenuItem
1423       {
1424          helpMenu, $"Samples Folder", s;
1425          bool NotifySelect(MenuItem selection, Modifiers mods)
1426          {
1427             FindAndShellOpenInstalledFolder("samples");
1428             return true;
1429          }
1430       }
1431       MenuItem
1432       {
1433          helpMenu, $"Extras Folder", x;
1434          bool NotifySelect(MenuItem selection, Modifiers mods)
1435          {
1436             FindAndShellOpenInstalledFolder("extras");
1437             return true;
1438          }
1439       }
1440       MenuDivider { helpMenu };
1441       MenuItem
1442       {
1443          helpMenu, $"Community Forums", f;
1444          bool NotifySelect(MenuItem selection, Modifiers mods)
1445          {
1446             ShellOpen("http://ecere.com/forums");
1447             return true;
1448          }
1449       }
1450       MenuDivider { helpMenu };
1451       MenuItem
1452       {
1453          helpMenu, $"About...", a;
1454          bool NotifySelect(MenuItem selection, Modifiers mods)
1455          {
1456             AboutIDE { master = this }.Modal();
1457             return true;
1458          }
1459       }
1460
1461    property ToolBox toolBox
1462    {
1463       get { return toolBox; }
1464    }
1465
1466    property Sheet sheet
1467    {
1468       get { return sheet; }
1469    }
1470
1471    property Project project
1472    {
1473       get { return projectView ? projectView.project : null; }
1474    }
1475
1476    property Workspace workspace
1477    {
1478       get { return projectView ? projectView.workspace : null; }
1479    }
1480
1481    FindInFilesDialog findInFilesDialog
1482    {
1483       master = this,
1484       filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1485       filter = 1;
1486    };
1487
1488    bool noParsing;
1489
1490 #ifdef GDB_DEBUG_GUI
1491    GDBDialog gdbDialog
1492    {
1493       master = this, parent = this;
1494       anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1495
1496       void OnCommand(char * string)
1497       {
1498          if(ide)
1499             ide.debugger.SendGDBCommand(string);
1500       }
1501    };
1502 #endif
1503    
1504    bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1505    {
1506       //app.driver = app.drivers[selection.id];
1507 #if defined(__unix__) || defined(__APPLE__)
1508       app.driver = selection.id ? "OpenGL" : "X";
1509 #else
1510       app.driver = selection.id ? "OpenGL" : "GDI";
1511 #endif
1512       delete ideSettings.displayDriver;
1513       ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1514
1515       settingsContainer.Save();
1516       //SetDriverAndSkin();
1517       return true;
1518    }
1519
1520    bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1521    {
1522       app.skin = app.skins[selection.id];
1523       SetDriverAndSkin();
1524       return true;
1525    }
1526
1527    void SetDriverAndSkin()
1528    {
1529       int c;
1530       for(c = 0; c < app.numSkins; c++)
1531          if(!strcmp(app.skins[c], app.skin))
1532          {
1533             skinItems[c].checked = true;
1534             break;
1535          }
1536       for(c = 0; c < app.numDrivers; c++)
1537          if(!strcmp(app.drivers[c], app.driver))
1538          {
1539             driverItems[c].checked = true;
1540             break;
1541          }
1542    }
1543
1544    ProjectView CreateProjectView(Workspace workspace, char * fileName)
1545    {
1546       Project project = workspace.projects.firstIterator.data;
1547       projectView = ProjectView
1548       {
1549          this;
1550          fileName = fileName;
1551          
1552          void NotifyDestroyed(Window window, DialogResult result)
1553          {
1554             projectView = null;
1555             text = titleECEREIDE;
1556             
1557             AdjustMenus();
1558          }
1559       };
1560       projectView.Create();
1561       RepositionWindows(false);
1562
1563       // Leave it after Create to avoid flicker due to seeing IDE without a project view
1564       projectView.workspace = workspace;
1565       projectView.project = project;
1566       ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1567
1568       AdjustMenus();
1569
1570       ide.breakpointsView.LoadFromWorkspace();
1571       ide.watchesView.LoadFromWorkspace();
1572
1573       findInFilesDialog.projectNodeField.userData = projectView;
1574
1575       {
1576          char fileName[MAX_LOCATION];
1577          strcpy(fileName, project.topNode.path);
1578          PathCat(fileName, project.topNode.name);
1579       }
1580       return projectView;
1581    }
1582
1583    bool ProjectClose()
1584    {
1585       projectView.visible = false;
1586       if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1587       {
1588          if(findInFilesDialog)
1589          {
1590             char workingDir[MAX_LOCATION];
1591             GetWorkingDir(workingDir, MAX_LOCATION);
1592             findInFilesDialog.SearchStop();
1593             findInFilesDialog.currentDirectory = workingDir;
1594          }
1595          ideMainFrame.text = titleECEREIDE;
1596          ide.AdjustMenus();
1597          return true;
1598       }
1599       return false;
1600    }
1601
1602    void RepositionWindows(bool expand)
1603    {
1604       if(this)
1605       {
1606          Window child;
1607          bool inDebugMode = debugger.isActive;
1608          bool callStackVisible = expand ? false : callStackView.visible;
1609          bool threadsVisible = expand ? false : threadsView.visible;
1610          bool watchesVisible = expand ? false : watchesView.visible;
1611          bool breakpointsVisible = expand ? false : breakpointsView.visible;
1612          bool toolBoxVisible = toolBox.visible;
1613          bool outputVisible = expand ? false : outputView.visible;
1614          int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1615          int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1616          
1617          for(child = firstChild; child; child = child.next)
1618          {
1619             if(child._class == class(CodeEditor) || child._class == class(Designer) || 
1620                child._class == class(Sheet) || child._class == class(ProjectView))
1621             {
1622                Anchor anchor = child.anchor;
1623                anchor.top = topDistance;
1624                anchor.bottom = bottomDistance;
1625                if(child._class == class(CodeEditor) || child._class == class(Designer))
1626                {
1627                   anchor.right = toolBoxVisible ? 150 : 0;
1628                }
1629                child.anchor = anchor;
1630             }
1631             else if(expand)
1632             {
1633                if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) || 
1634                   child._class == class(BreakpointsView))
1635                   child.visible = false;
1636             }
1637          }
1638          // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1639          Update(null);
1640       }
1641    }
1642
1643    bool ShowCodeEditor()
1644    {
1645       if(activeClient)
1646          activeClient.Activate();
1647       else if(projectView)
1648       { 
1649          projectView.visible = true;
1650          projectView.Activate();
1651       }
1652       else
1653       {
1654          sheet.visible = true;
1655          sheet.Activate();
1656       }
1657       return false;
1658    }
1659
1660    void DocumentSaved(Window document, char * fileName)
1661    {
1662       ideSettings.AddRecentFile(fileName);
1663       ide.UpdateRecentMenus();
1664       ide.AdjustFileMenus();
1665       settingsContainer.Save();
1666    }
1667
1668    bool Window::OnFileModified(FileChange fileChange, char * param)
1669    {
1670       char temp[4096];
1671       sprintf(temp, $"The document %s was modified by another application.\n"
1672             "Would you like to reload it and lose your changes?", this.fileName);
1673       if(MessageBox { type = yesNo, master = this/*.parent*/,
1674             text = $"Document has been modified", contents = temp }.Modal() == yes)
1675       {
1676          bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1677          char * fileName = CopyString(this.fileName);
1678          WindowState state = this.state;
1679          Anchor anchor = this.anchor;
1680          Size size = this.size;
1681
1682          this.modifiedDocument = false;
1683          this.Destroy(0);
1684          this = ide.OpenFile(fileName, normal, true, null, no, normal, noParsing);
1685          if(this)
1686          {
1687             this.anchor = anchor;
1688             this.size = size;
1689             this.SetState(state, true, 0);
1690          }
1691          delete fileName;
1692          return true;
1693       }
1694       return true;
1695    }
1696
1697    void UpdateMakefiles()
1698    {
1699       if(workspace)
1700       {
1701          CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1702          for(prj : workspace.projects)
1703             projectView.ProjectUpdateMakefileForAllConfigs(prj);
1704          delete compiler;
1705       }
1706    }
1707
1708    void UpdateCompilerConfigs(bool mute)
1709    {
1710       UpdateToolBarActiveCompilers();
1711       if(workspace)
1712       {
1713          bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1714          CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1715          if(!silent)
1716          {
1717             projectView.ShowOutputBuildLog(true);
1718             projectView.DisplayCompiler(compiler, false);
1719          }
1720          for(prj : workspace.projects)
1721             projectView.ProjectPrepareCompiler(prj, compiler, silent);
1722          delete compiler;
1723       }
1724    }
1725
1726    void UpdateToolBarActiveCompilers()
1727    {
1728       toolBar.activeCompiler.Clear();
1729       for(compiler : ideSettings.compilerConfigs)
1730       {
1731          DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1732          if(workspace && workspace.compiler && !strcmp(compiler.name, workspace.compiler))
1733             toolBar.activeCompiler.currentRow = row;
1734       }
1735       if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1736          toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1737    }
1738
1739    void UpdateToolBarActiveConfigs(bool selectionOnly)
1740    {
1741       bool commonSelected = false;
1742       DataRow row = toolBar.activeConfig.currentRow;
1743       if(selectionOnly)
1744          row = toolBar.activeConfig.FindRow(1);
1745       else
1746       {
1747          toolBar.activeConfig.Clear();
1748          row = toolBar.activeConfig.AddString($"(Mixed)");
1749          row.tag = 1;
1750       }
1751       if(workspace)
1752       {
1753          char * configName = null;
1754          if(!selectionOnly)
1755          {
1756             Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1757             for(prj : workspace.projects)
1758             {
1759                for(cfg : prj.configurations)
1760                {
1761                   if(cfg.name)
1762                      configs[cfg.name] = 1;
1763                }
1764             }
1765             for(name : configs)
1766             {
1767                toolBar.activeConfig.AddString(&name);
1768             }
1769             delete configs;
1770          }
1771          if(projectView && projectView.project)
1772          {
1773             for(prj : workspace.projects)
1774             {
1775                if(prj.config && prj.config.name)
1776                {
1777                   configName = prj.config.name;
1778                   break;
1779                }
1780             }
1781             if(configName)
1782             {
1783                commonSelected = true;
1784                for(prj : workspace.projects)
1785                {
1786                   if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1787                   {
1788                      commonSelected = false;
1789                      break;
1790                   }
1791                }
1792             }
1793          }
1794          if(commonSelected)
1795          {
1796             commonSelected = false;
1797             for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1798             {
1799                if(!strcmp(row.string, configName))
1800                {
1801                   toolBar.activeConfig.currentRow = row;
1802                   commonSelected = true;
1803                   break;
1804                }
1805             }
1806          }
1807       }
1808       if(!selectionOnly)
1809          toolBar.activeConfig.Sort(null, 0);
1810       if(!commonSelected)
1811          toolBar.activeConfig.currentRow = row;
1812    }
1813
1814    void AdjustMenus()
1815    {
1816       bool unavailable = !project;
1817
1818       projectAddItem.disabled             = unavailable;
1819       toolBar.buttonAddProject.disabled   = unavailable;
1820
1821       projectSettingsItem.disabled        = unavailable;
1822
1823       projectBrowseFolderItem.disabled    = unavailable;
1824
1825       viewProjectItem.disabled            = unavailable;
1826
1827       toolBar.activeConfig.disabled       = unavailable;
1828       toolBar.activeCompiler.disabled     = unavailable;
1829       toolBar.activeBitDepth.disabled     = unavailable;
1830
1831       AdjustFileMenus();
1832       AdjustBuildMenus();
1833       AdjustDebugMenus();
1834    }
1835
1836    property bool hasOpenedCodeEditors
1837    {
1838       get
1839       {
1840          Window w;
1841          for(w = firstChild; w; w = w.next)
1842             if(w._class == class(CodeEditor) &&
1843                   w.isDocument && !w.closing && w.visible && w.created &&
1844                   w.fileName && w.fileName[0])
1845                return true;
1846          return false;
1847       }
1848    }
1849
1850    void AdjustFileMenus()
1851    {
1852       bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
1853
1854       projectQuickItem.disabled           = unavailable;
1855    }
1856
1857    void AdjustBuildMenus()
1858    {
1859       bool unavailable = project && projectView.buildInProgress;
1860
1861       projectNewItem.disabled             = unavailable;
1862       toolBar.buttonNewProject.disabled   = unavailable;
1863       projectOpenItem.disabled            = unavailable;
1864       toolBar.buttonOpenProject.disabled  = unavailable;
1865
1866       unavailable = !project || projectView.buildInProgress;
1867
1868       projectCloseItem.disabled           = unavailable;
1869       // toolBar.buttonCloseProject.disabled = unavailable;
1870
1871       projectRunItem.disabled    = unavailable || project.GetTargetType(project.config) != executable;
1872       toolBar.buttonRun.disabled = unavailable || project.GetTargetType(project.config) != executable;
1873
1874       projectBuildItem.disabled = false;
1875       projectBuildItem.text     = unavailable ? $"Stop Build" : $"Build";
1876       projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
1877
1878       projectLinkItem.disabled                  = unavailable;
1879       toolBar.buttonReLink.disabled             = unavailable;
1880       projectRebuildItem.disabled               = unavailable;
1881       toolBar.buttonRebuild.disabled            = unavailable;
1882       projectCleanItem.disabled                 = unavailable;
1883       toolBar.buttonClean.disabled              = unavailable;
1884       projectCleanTargetItem.disabled           = unavailable;
1885       projectRealCleanItem.disabled             = unavailable;
1886       // toolBar.buttonRealClean.disabled          = unavailable;
1887       projectRegenerateItem.disabled            = unavailable;
1888       toolBar.buttonRegenerateMakefile.disabled = unavailable;
1889       projectCompileItem.disabled               = unavailable;
1890
1891       AdjustPopupBuildMenus();
1892    }
1893
1894    void AdjustPopupBuildMenus()
1895    {
1896       bool unavailable = !project || projectView.buildInProgress;
1897
1898       if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
1899       {
1900          MenuItem menu;
1901          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
1902          if(menu)
1903          {
1904             menu.disabled = false;
1905             menu.text   = unavailable ? $"Stop Build" : $"Build";
1906             menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
1907          }
1908
1909          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0);              if(menu) menu.disabled = unavailable;
1910          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0);           if(menu) menu.disabled = unavailable;
1911          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0);       if(menu) menu.disabled = unavailable;
1912          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0);             if(menu) menu.disabled = unavailable;
1913          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0);         if(menu) menu.disabled = unavailable;
1914          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0);        if(menu) menu.disabled = unavailable;
1915          menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0);            if(menu) menu.disabled = unavailable;
1916          menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0);                if(menu) menu.disabled = unavailable;
1917          menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0);              if(menu) menu.disabled = unavailable;
1918          menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0);      if(menu) menu.disabled = unavailable;
1919          menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0);         if(menu) menu.disabled = unavailable;
1920          menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
1921          projectView.popupMenu.Update(null);
1922       }
1923    }
1924
1925    property bool areDebugMenusUnavailable { get {
1926       return !project ||
1927             project.GetTargetType(project.config) != executable ||
1928             projectView.buildInProgress == buildingMainProject;
1929    } }
1930
1931    property bool isBreakpointTogglingUnavailable { get {
1932       return !project;
1933    } }
1934
1935    property bool isDebuggerExecuting { get {
1936       if(!ide.debugger)
1937          return false;
1938       else
1939          return ide.debugger.state == running;
1940    } }
1941
1942    void AdjustDebugMenus()
1943    {
1944       bool unavailable = areDebugMenusUnavailable;
1945       bool active = debugger.isActive;
1946       bool bpNoToggle = isBreakpointTogglingUnavailable;
1947       bool executing = isDebuggerExecuting;
1948       //bool holding = debugger.state == stopped;
1949
1950       debugStartResumeItem.disabled       = unavailable || executing;
1951       debugStartResumeItem.text           = active ? $"Resume" : $"Start";
1952       debugStartResumeItem.NotifySelect   = active ? MenuDebugResume : MenuDebugStart;
1953       if(toolBar)
1954       {
1955          toolBar.buttonDebugStartResume.disabled      = unavailable || executing;
1956          toolBar.buttonDebugStartResume.toolTip       = active ? $"Resume" : $"Start";
1957       }
1958
1959       debugBreakItem.disabled             = unavailable || !executing;
1960       debugStopItem.disabled              = unavailable || !active;
1961       debugRestartItem.disabled           = unavailable || !active;
1962       if(toolBar)
1963       {
1964          toolBar.buttonDebugPause.disabled            = unavailable || !executing;
1965          toolBar.buttonDebugStop.disabled             = unavailable || !active;
1966          toolBar.buttonDebugRestart.disabled          = unavailable || !active;
1967       }
1968
1969       debugStepIntoItem.disabled          = unavailable || executing;
1970       debugStepOverItem.disabled          = unavailable || executing;
1971       debugStepOutItem.disabled           = unavailable || executing || !active;
1972       debugSkipStepOverItem.disabled      = unavailable || executing;
1973       debugSkipStepOutItem.disabled       = unavailable || executing || !active;
1974       if(toolBar)
1975       {
1976          toolBar.buttonDebugStepInto.disabled         = unavailable || executing;
1977          toolBar.buttonDebugStepOver.disabled         = unavailable || executing;
1978          toolBar.buttonDebugStepOut.disabled          = unavailable || executing || !active;
1979          toolBar.buttonDebugSkipStepOver.disabled     = unavailable || executing;
1980          // toolBar.buttonDebugSkipStepOutItem.disabled  = unavailable || executing;
1981       }
1982       if((Designer)GetActiveDesigner())
1983       {
1984          CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
1985          if(codeEditor)
1986             codeEditor.AdjustDebugMenus(unavailable, bpNoToggle, executing);
1987       }
1988    }
1989
1990    void ChangeFileDialogsDirectory(char * directory, bool saveSettings)
1991    {
1992       char tempString[MAX_LOCATION];
1993       strcpy(tempString, directory);
1994       if(saveSettings && !projectView)
1995       {
1996          ideSettings.ideFileDialogLocation = directory;
1997          settingsContainer.Save();
1998       }
1999
2000       ideFileDialog.currentDirectory = tempString;
2001       codeEditorFileDialog.currentDirectory = tempString;
2002       codeEditorFormFileDialog.currentDirectory = tempString;
2003    }
2004
2005    void ChangeProjectFileDialogDirectory(char * directory)
2006    {
2007       ideSettings.ideProjectFileDialogLocation = directory;
2008       settingsContainer.Save();
2009    }
2010
2011    Window FindWindow(char * filePath)
2012    {
2013       Window document = null;
2014
2015       // TOCHECK: Do we need to change slashes here?
2016       for(document = firstChild; document; document = document.next)
2017       {
2018          char * fileName = document.fileName;
2019          if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2020          {
2021             document.visible = true;
2022             document.Activate();
2023             return document;
2024          }
2025       }
2026       return null;
2027    }
2028
2029    bool DontTerminateDebugSession(char * title)
2030    {
2031       if(debugger.isActive)
2032       {
2033          if(MessageBox { type = yesNo, master = ide, 
2034                            contents = $"Do you want to terminate the debugging session in progress?", 
2035                            text = title }.Modal() == no)
2036             return true;
2037          /*
2038          MessageBox msg { type = yesNo, master = ide, 
2039                            contents = "Do you want to terminate the debugging session in progress?", 
2040                            text = title };
2041          if(msg.Modal() == no)
2042          {
2043             msg.Destroy(0);
2044             delete msg;
2045             return true;
2046          }
2047          msg.Destroy(0);
2048          delete msg;*/
2049       }
2050       return false;
2051    }
2052
2053    Window OpenFile(char * origFilePath, WindowState state, bool visible, char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2054    {
2055       char extension[MAX_EXTENSION] = "";
2056       Window document = null;
2057       bool isProject = false;
2058       bool needFileModified = true;
2059       char winFilePath[MAX_LOCATION];
2060       char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2061
2062       if(!type)
2063       {
2064          GetExtension(filePath, extension);
2065          strlwr(extension);
2066       }
2067       else
2068          strcpy(extension, type);
2069
2070       if(strcmp(extension, ProjectExtension))
2071       {
2072          for(document = firstChild; document; document = document.next)
2073          {
2074             char * fileName = document.fileName;
2075             if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2076             {
2077                document.visible = true;
2078                if(visible)
2079                   document.Activate();
2080                return document;
2081             }
2082          }
2083       }
2084
2085       if(createIfFails == whatever)
2086          ;
2087       else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2088       {
2089          needFileModified = false;
2090          if(openMethod == normal)
2091          {
2092             if(DontTerminateDebugSession($"Open Project"))
2093                return null;
2094             isProject = true;
2095             if(ProjectClose())
2096             {
2097                if(!projectView)
2098                {
2099                   for(;;)
2100                   {
2101                      Project project;
2102                      Workspace workspace = null;
2103                      
2104                      if(FileExists(filePath))
2105                      {
2106                         if(!strcmp(extension, ProjectExtension))
2107                         {
2108                            char workspaceFile[MAX_LOCATION];
2109                            strcpy(workspaceFile, filePath);
2110                            ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2111                            workspace = LoadWorkspace(workspaceFile, filePath);
2112                         }
2113                         else if(!strcmp(extension, WorkspaceExtension))
2114                            workspace = LoadWorkspace(filePath, null);
2115                         else
2116                            return null;
2117                         //project = LoadProject(filePath, null);
2118                      }
2119                      
2120                      if(workspace)
2121                      {
2122                         char absolutePath[MAX_LOCATION];
2123                         CreateProjectView(workspace, filePath);
2124                         document = projectView;
2125
2126                         workspace.DropInvalidBreakpoints();
2127                         workspace.Save();
2128
2129                         ide.projectView.ShowOutputBuildLog(true);
2130                         {
2131                            CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2132                            ide.projectView.DisplayCompiler(compiler, false);
2133                            delete compiler;
2134                         }
2135                         UpdateCompilerConfigs(false);
2136                         UpdateMakefiles();
2137                         {
2138                            char newWorkingDir[MAX_LOCATION];
2139                            StripLastDirectory(filePath, newWorkingDir);
2140                            ChangeFileDialogsDirectory(newWorkingDir, false);
2141                         }
2142                         if(document)
2143                            document.fileName = filePath;
2144
2145                         ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2146
2147                         // this crashes on starting ide with epj file, solution please?
2148                         // app.UpdateDisplay();
2149
2150                         workspace.holdTracking = true;
2151                         for(ofi : workspace.openedFiles)
2152                         {
2153                            if(ofi.state != closed)
2154                            {
2155                               Window file = OpenFile(ofi.path, normal, true, null, no, normal, noParsing);
2156                               if(file)
2157                               {
2158                                  char fileName[MAX_LOCATION];
2159                                  ProjectNode node;
2160                                  GetLastDirectory(ofi.path, fileName);
2161                                  node = projectView.project.topNode.Find(fileName, true);
2162                                  if(node)
2163                                     node.EnsureVisible();
2164                               }
2165                            }
2166                         }
2167                         workspace.holdTracking = false;
2168
2169                         workspace.timer.Start();
2170
2171                         findInFilesDialog.mode = FindInFilesMode::project;
2172                         findInFilesDialog.currentDirectory = ide.project.topNode.path;
2173                         
2174                         {
2175                            char location[MAX_LOCATION];
2176                            StripLastDirectory(ide.project.topNode.path, location);
2177                            ChangeProjectFileDialogDirectory(location);
2178                         }
2179                         
2180                         /*
2181                         if(projectView.debugger)
2182                            projectView.debugger.EvaluateWatches();
2183                         */
2184                         
2185                         break;
2186                      }
2187                      else 
2188                      {
2189                         if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2190                         {
2191                            ideProjectFileDialog.text = openProjectFileDialogTitle;
2192                            if(ideProjectFileDialog.Modal() == cancel)
2193                               return null;
2194                            filePath = ideProjectFileDialog.filePath;
2195                            GetExtension(filePath, extension);
2196                         }
2197                         else
2198                            return null;
2199                      }
2200                   }
2201                }
2202             }
2203             else
2204                return null;
2205          }
2206          else if(openMethod == add)
2207          {
2208             if(workspace)
2209             {
2210                Project prj = null;
2211                char slashFilePath[MAX_LOCATION];
2212                GetSlashPathBuffer(slashFilePath, filePath);
2213                for(p : workspace.projects)
2214                {
2215                   if(!fstrcmp(p.filePath, slashFilePath))
2216                   {
2217                      prj = p;
2218                      break;
2219                   }
2220                }
2221                if(prj)
2222                {
2223                   MessageBox { type = ok, parent = parent, master = this, text = $"Same Project", 
2224                         contents = $"This project is already present in workspace." }.Modal();
2225                }
2226                else
2227                {
2228                   prj = LoadProject(filePath, null);
2229                   if(prj)
2230                   {
2231                      char * activeConfigName = null;
2232                      CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2233                      prj.StartMonitoring();
2234                      workspace.projects.Add(prj);
2235                      if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2236                            toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2237                         activeConfigName = toolBar.activeConfig.currentRow.string;
2238                      if(activeConfigName)
2239                      {
2240                         for(cfg : prj.configurations)
2241                         {
2242                            if(cfg.name && !strcmp(cfg.name, activeConfigName))
2243                            {
2244                               prj.config = cfg;
2245                               break;
2246                            }
2247                         }
2248                      }
2249                      if(projectView)
2250                         projectView.AddNode(prj.topNode, null);
2251                      workspace.modified = true;
2252                      workspace.Save();
2253                      findInFilesDialog.AddProjectItem(prj);
2254                      projectView.ShowOutputBuildLog(true);
2255                      projectView.DisplayCompiler(compiler, false);
2256                      projectView.ProjectUpdateMakefileForAllConfigs(prj);
2257                      delete compiler;
2258
2259                      {
2260                         char location[MAX_LOCATION];
2261                         StripLastDirectory(prj.topNode.path, location);
2262                         ChangeProjectFileDialogDirectory(location);
2263                      }
2264
2265                      // projectView is associated with the main project and not with the one just added but
2266                      return projectView; // just to let the caller know something was opened
2267                   }
2268                }
2269             }
2270             else
2271                return null;
2272          }
2273       }
2274       else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2275             !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2276             !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2277       {
2278          if(FileExists(filePath))
2279             document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable, 
2280                                        hasVertScroll = true, hasHorzScroll = true, parent = this, state = state, 
2281                                        visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2282                                     };
2283          if(!document)
2284             MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2285       }
2286 #ifndef NO3D
2287       else if(!strcmp(extension, "3ds"))
2288       {
2289          if(FileExists(filePath))
2290             document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable, 
2291                                     hasVertScroll = true, hasHorzScroll = true, parent = this, state = state, 
2292                                     visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2293                                     };
2294
2295          if(!document)
2296             MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2297       }
2298 #endif
2299       else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2300             !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2301             !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2302             !strcmp(extension, "css") || !strcmp(extension, "php") ||
2303             !strcmp(extension, "js"))
2304       {
2305          CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2306          editor.updatingCode = true;
2307          if(editor.LoadFile(filePath))
2308          {
2309             document = editor;
2310             editor.visible = true;
2311          }
2312          else
2313             delete editor;
2314          needFileModified = false;
2315       }
2316       else
2317       {
2318          CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2319          if(editor.LoadFile(filePath))
2320          {
2321             document = editor;
2322             editor.visible = true;
2323          }
2324          else
2325             delete editor;
2326          needFileModified = false;
2327       }
2328
2329       if(document && (document._class == class(PictureEdit) ||
2330             document._class == class(ModelView)))
2331       {
2332          document.Create();
2333          if(document)
2334          {
2335             document.fileName = filePath;
2336             if(workspace && !workspace.holdTracking)
2337                workspace.UpdateOpenedFileInfo(filePath, opened);
2338          }
2339       }
2340       
2341       if(!document && createIfFails != no)
2342       {
2343          if(createIfFails != yes && !needFileModified && 
2344                MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2345             createIfFails = yes;
2346          if(createIfFails == yes || createIfFails == whatever)
2347          {
2348             document = (Window)NewCodeEditor(this, state, true);
2349             if(document)
2350                document.fileName = filePath;
2351          }
2352       }
2353
2354       if(document)
2355       {
2356          if(projectView && document._class == class(CodeEditor) && workspace)
2357          {
2358             int lineNumber, position;
2359             Point scroll;
2360             CodeEditor editor = (CodeEditor)document;
2361             editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2362             editor.openedFileInfo.holdTracking = true;
2363             lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2364             position = Max(editor.openedFileInfo.position - 1, 0);
2365             editor.editBox.GoToLineNum(lineNumber);
2366             editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2367             scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2368             scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2369             editor.editBox.scroll = scroll;
2370             editor.openedFileInfo.holdTracking = false;
2371          }
2372          
2373          if(needFileModified)
2374             document.OnFileModified = OnFileModified;
2375          document.NotifySaved = DocumentSaved;
2376          
2377          if(isProject)
2378             ideSettings.AddRecentProject(document.fileName);
2379          else
2380             ideSettings.AddRecentFile(document.fileName);
2381          ide.UpdateRecentMenus();
2382          ide.AdjustFileMenus();
2383          settingsContainer.Save();
2384          
2385          return document;
2386       }
2387       else
2388          return null;
2389    }
2390
2391    // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2392    /*bool Window::GenericDocumentOnClose(bool parentClosing)
2393    {
2394       if(!parentClosing && ide.workspace)
2395          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2396       return true;
2397    }*/
2398    bool ModelView::ModelViewOnClose(bool parentClosing)
2399    {
2400       if(!parentClosing && ide.workspace)
2401          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2402       return true;
2403    }
2404    bool PictureEdit::PictureEditOnClose(bool parentClosing)
2405    {
2406       if(!parentClosing && ide.workspace)
2407          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2408       return true;
2409    }
2410
2411    /*
2412    void OnUnloadGraphics(Window window)
2413    {
2414       display.ClearMaterials();
2415       display.ClearTextures();
2416       display.ClearMeshes();
2417    }
2418    */
2419
2420    bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2421    {
2422       caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2423       num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2424       return true;
2425    }
2426
2427    bool OnKeyDown(Key key, unichar ch)
2428    {
2429       switch(key)
2430       {
2431          case b:
2432             projectView.Update(null);
2433             break;
2434          case capsLock:
2435             caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2436             break;
2437          case numLock:
2438             num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2439             break;
2440       }
2441       return true;
2442    }
2443
2444    void GoToError(const char * line, bool noParsing)
2445    {
2446       if(projectView)
2447          projectView.GoToError(line, noParsing);
2448    }
2449
2450    void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
2451    {
2452       char *path = text;
2453       char *colon = strchr(text, ':');
2454       char filePath[MAX_LOCATION] = "";
2455       char completePath[MAX_LOCATION];
2456       int line = 0, col = 0;
2457       Project prj = null;
2458       FileAttribs fileAttribs;
2459
2460       if(colon && (colon[1] == '/' || colon[1] == '\\'))
2461       {
2462          path = (colon - 1 > path) ? colon - 1 : path;
2463          colon = strstr(colon + 1, ":");
2464       }
2465       while(isspace(*path)) path++;
2466       if(*path == '(')
2467       {
2468          char * close = strchr(path, ')');
2469          if(close)
2470          {
2471             char name[256];
2472             strncpy(name, path+1, close - path - 1);
2473             name[close - path - 1] = '\0';
2474             for(p : ide.workspace.projects)
2475             {
2476                if(!strcmp(p.name, name))
2477                {
2478                   path = close + 1;
2479                   prj = p;
2480                   break;
2481                }
2482             }
2483          }
2484       }
2485       if(!prj)
2486          prj = project ? project : (dir ? null : ide.project);
2487       if(colon)
2488       {
2489          strncpy(filePath, path, colon - path);
2490          filePath[colon - path] = '\0';
2491          line = atoi(colon + 1);
2492          colon = strstr(colon + 1, ":");
2493          if(colon)
2494             col = atoi(colon + 1);
2495       }
2496       else if(path - 1 >= text && *(path - 1) == '\"')
2497       {
2498          colon = strchr(path, '\"');
2499          if(colon)
2500          {
2501             strncpy(filePath, path, colon - path);
2502             filePath[colon - path] = '\0';
2503          }
2504       }
2505       else if(path && !colon)
2506       {
2507          strcpy(filePath, path);
2508       }
2509
2510       if(filePath[0])
2511       {
2512          if(prj)
2513             strcpy(completePath, prj.topNode.path);
2514          else if(dir && dir[0])
2515             strcpy(completePath, dir);
2516          else
2517             completePath[0] = '\0';
2518          PathCat(completePath, filePath);
2519
2520          if((fileAttribs = FileExists(completePath)))
2521             CodeLocationGoTo(completePath, fileAttribs, line, col);
2522          else
2523          {
2524             for(p : ide.workspace.projects)
2525             {
2526                strcpy(completePath, p.topNode.path);
2527                PathCat(completePath, filePath);
2528                if((fileAttribs = FileExists(completePath)))
2529                {
2530                   CodeLocationGoTo(completePath, fileAttribs, line, col);
2531                   break;
2532                }
2533             }
2534          }
2535       }
2536    }
2537
2538    void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2539    {
2540       if(fileAttribs.isFile)
2541       {
2542          CodeEditor codeEditor = (CodeEditor)OpenFile(path, normal, true, "", no, normal, false);
2543          if(codeEditor && line)
2544          {
2545             char ext[MAX_EXTENSION];
2546             GetExtension(path, ext);
2547             if(!strcmp(ext, "mp3") || !strcmp(ext, "flac") || !strcmp(ext, "ogg") || !strcmp(ext, "avi") || !strcmp(ext, "mkv"))
2548                ShellOpen(path);
2549             else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2550             {
2551                char dirPath[MAX_LOCATION];
2552                StripLastDirectory(path, dirPath);
2553                ShellOpen(dirPath);
2554             }
2555             else
2556             {
2557                CodeEditor codeEditor = (CodeEditor)OpenFile(path, normal, true, "", no, normal, false);
2558                if(codeEditor && line)
2559                {
2560                   EditBox editBox = codeEditor.editBox;
2561                   editBox.GoToLineNum(line - 1);
2562                   editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2563                }
2564             }
2565          }
2566          else if(fileAttribs.isDirectory)
2567             ShellOpen(path);
2568       }
2569    }
2570
2571    void OnRedraw(Surface surface)
2572    {
2573       Bitmap bitmap = back.bitmap;
2574       if(bitmap)
2575          surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2576    }
2577
2578    void SheetSelected(SheetType sheetSelected)
2579    {
2580       if(activeChild == sheet)
2581       {
2582          if(sheetSelected == methods)
2583          {
2584             viewPropertiesItem.accelerator = f4;
2585             viewPropertiesItem.parent = viewMenu;
2586             viewMethodsItem.parent = null;
2587          }
2588          else
2589          {
2590             viewMethodsItem.accelerator = f4;
2591             viewMethodsItem.parent = viewMenu;
2592             viewPropertiesItem.parent = null;
2593          }
2594       }
2595       else
2596       {
2597          viewMethodsItem.parent = viewMenu;
2598          viewPropertiesItem.parent = viewMenu;
2599          if(sheetSelected == methods)
2600          {
2601             viewMethodsItem.accelerator = f4;
2602             viewPropertiesItem.accelerator = 0;
2603          }
2604          else
2605          {
2606             viewMethodsItem.accelerator = 0;
2607             viewPropertiesItem.accelerator = f4;
2608          }
2609       }
2610    }
2611
2612    void OnActivateClient(Window client, Window previous)
2613    {
2614       //if(!client || client != previous)
2615       {
2616          Class dataType;
2617          if(!client || client != previous)
2618          {
2619             if(previous)
2620                dataType = previous._class;
2621             if(previous && !strcmp(dataType.name, "CodeEditor"))
2622             {
2623                ((CodeEditor)previous).UpdateFormCode();
2624             }
2625             else if(previous && !strcmp(dataType.name, "Designer"))
2626             {
2627                ((Designer)previous).codeEditor.UpdateFormCode();
2628             }
2629          }
2630
2631          if(client)
2632             dataType = client._class;
2633          if(client && !strcmp(dataType.name, "CodeEditor"))
2634          {
2635             CodeEditor codeEditor = (CodeEditor)client;
2636             SetPrivateModule(codeEditor.privateModule);
2637             SetCurrentContext(codeEditor.globalContext);
2638             SetTopContext(codeEditor.globalContext);
2639             SetGlobalContext(codeEditor.globalContext);
2640             
2641             SetDefines(&codeEditor.defines);
2642             SetImports(&codeEditor.imports);
2643
2644             SetActiveDesigner(codeEditor.designer);
2645             
2646             sheet.codeEditor = codeEditor;
2647             toolBox.codeEditor = codeEditor;
2648
2649             viewDesignerItem.parent = viewMenu;
2650             if(activeChild != codeEditor)
2651             {
2652                viewCodeItem.parent = viewMenu;
2653                viewDesignerItem.accelerator = 0;
2654                viewCodeItem.accelerator = f8;
2655             }
2656             else
2657             {
2658                viewCodeItem.parent = null;
2659                viewDesignerItem.accelerator = f8;
2660             }
2661          }
2662          else if(client && !strcmp(dataType.name, "Designer"))
2663          {
2664             CodeEditor codeEditor = ((Designer)client).codeEditor;
2665             if(codeEditor)
2666             {
2667                SetPrivateModule(codeEditor.privateModule);
2668                SetCurrentContext(codeEditor.globalContext);
2669                SetTopContext(codeEditor.globalContext);
2670                SetGlobalContext(codeEditor.globalContext);
2671                SetDefines(&codeEditor.defines);
2672                SetImports(&codeEditor.imports);
2673             }
2674             else
2675             {
2676                SetPrivateModule(null);
2677                SetCurrentContext(null);
2678                SetTopContext(null);
2679                SetGlobalContext(null);
2680                SetDefines(null);
2681                SetImports(null);
2682             }
2683
2684             SetActiveDesigner((Designer)client);
2685
2686             sheet.codeEditor = codeEditor;
2687             toolBox.codeEditor = codeEditor;
2688
2689             viewCodeItem.parent = viewMenu;
2690             if(activeChild != client)
2691             {
2692                viewDesignerItem.parent = viewMenu;
2693                viewDesignerItem.accelerator = f8;
2694                viewCodeItem.accelerator = 0;
2695             }
2696             else
2697             {
2698                viewDesignerItem.parent = null;
2699                viewCodeItem.accelerator = f8;
2700             }
2701          }
2702          else
2703          {
2704             if(sheet)
2705                sheet.codeEditor = null;
2706             toolBox.codeEditor = null;
2707             SetActiveDesigner(null);
2708
2709             viewDesignerItem.parent = null;
2710             viewCodeItem.parent = null;
2711          }
2712          if(sheet)
2713             SheetSelected(sheet.sheetSelected);
2714       }
2715
2716       projectCompileItem = null;
2717
2718       if(statusBar)
2719       {
2720          statusBar.Clear();
2721          if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
2722          {
2723             CodeEditor codeEditor = (CodeEditor)client;
2724             EditBox editBox = codeEditor.editBox;
2725
2726             statusBar.AddField(pos);
2727
2728             caps = { width = 40, text = $"CAPS", color = app.GetKeyState(capsState) ? black : Color { 128, 128, 128 } };
2729             statusBar.AddField(caps);
2730
2731             ovr = { width = 30, text = $"OVR", color = (editBox && editBox.overwrite) ? black : Color { 128, 128, 128 } };
2732             statusBar.AddField(ovr);
2733
2734             num = { width = 30, text = $"NUM", color = app.GetKeyState(numState) ? black : Color { 128, 128, 128 } };
2735             statusBar.AddField(num);
2736
2737             //statusBar.text = "Ready";
2738
2739             if(projectView && projectView.project)
2740             {
2741                bool isCObject = false;
2742                ProjectNode node = projectView.GetNodeFromWindow(client, null, false);
2743                if(!node && (node = projectView.GetNodeFromWindow(client, null, true)))
2744                   isCObject = true;
2745                if(node)
2746                {
2747                   char nodeName[MAX_FILENAME];
2748                   char name[MAX_FILENAME+96];
2749                   if(isCObject)
2750                      ChangeExtension(node.name, "c", nodeName);
2751                   sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
2752                   projectCompileItem = 
2753                   {
2754                      copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
2755
2756                      bool NotifySelect(MenuItem selection, Modifiers mods)
2757                      {
2758                         if(projectView)
2759                         {
2760                            bool result = false;
2761                            bool isCObject = false;
2762                            ProjectNode node = null;
2763                            for(p : ide.workspace.projects)
2764                            {
2765                               node = projectView.GetNodeFromWindow(activeClient, p, false);
2766                               if(node) break;
2767                            }
2768                            if(!node && (node = projectView.GetNodeFromWindow(activeClient, null, true)))
2769                               isCObject = true;
2770                            if(node)
2771                            {
2772                               List<ProjectNode> nodes { };
2773                               nodes.Add(node);
2774                               projectView.Compile(node.project, nodes, mods.ctrl && mods.shift, isCObject ? cObject : normal);
2775                               delete nodes;
2776                               result = true;
2777                            }
2778                            if(!result && node)
2779                               ide.outputView.buildBox.Logf($"File %s is excluded from current build configuration.\n", node.name);
2780                         }
2781                         return true;
2782                      }
2783                   };
2784                   projectMenu.AddDynamic(projectCompileItem, ide, false);
2785                }
2786             }
2787          }
2788          else
2789          {
2790             caps = ovr = num = null;
2791          }
2792       }
2793    }
2794
2795    bool OnClose(bool parentClosing)
2796    {
2797       //return !projectView.buildInProgress;
2798       if(projectView && projectView.buildInProgress)
2799          return false;
2800       if(DontTerminateDebugSession($"Close IDE"))
2801          return false;
2802       if(findInFilesDialog)
2803          findInFilesDialog.SearchStop();
2804       if(workspace)
2805       {
2806          workspace.timer.Stop();
2807          workspace.Save();
2808       }
2809       ideMainFrame.Destroy(0);
2810       return true;
2811    }
2812
2813    bool OnPostCreate()
2814    {
2815       int c;
2816       bool passThrough = false;
2817       bool debugStart = false;
2818       bool debugWorkDir = false;
2819       char * passDebugWorkDir = null;
2820       bool openAsText = false;
2821       DynamicString passArgs { };
2822       int ptArg = 0;
2823
2824       for(c = 1; c<app.argc; c++)
2825       {
2826          if(passThrough)
2827          {
2828             char * arg = app.argv[c];
2829             char * buf = new char[strlen(arg)*2+1];
2830             if(ptArg++ > 0)
2831                passArgs.concat(" ");
2832             PassArg(buf, arg);
2833             passArgs.concat(buf);
2834             delete buf;
2835          }
2836          else if(debugWorkDir)
2837          {
2838             passDebugWorkDir = CopyString(app.argv[c]);
2839             StripQuotes(passDebugWorkDir, passDebugWorkDir);
2840             debugWorkDir = false;
2841          }
2842          else if(!strcmp(app.argv[c], "-t"))
2843             openAsText = true;
2844          else if(!strcmp(app.argv[c], "-no-parsing"))
2845             ide.noParsing = true;
2846          else if(!strcmp(app.argv[c], "-debug-start"))
2847             debugStart = true;
2848          else if(!strcmp(app.argv[c], "-debug-work-dir"))
2849             debugWorkDir = true;
2850          else if(!strcmp(app.argv[c], "-@"))
2851             passThrough = true;
2852          else
2853          {
2854             char fullPath[MAX_LOCATION];
2855             char parentPath[MAX_LOCATION];
2856             char ext[MAX_EXTENSION];
2857             bool isProject;
2858             FileAttribs dirAttribs;
2859             GetWorkingDir(fullPath, MAX_LOCATION);
2860             PathCat(fullPath, app.argv[c]);
2861             StripLastDirectory(fullPath, parentPath);
2862             GetExtension(app.argv[c], ext);
2863             isProject = !openAsText && !strcmpi(ext, "epj");
2864
2865             if(isProject && c > (debugStart ? 2 : 1)) continue;
2866
2867             // Create directory for projects (only)
2868             if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
2869             {
2870                if(isProject && !FileExists(fullPath))
2871                {
2872                   char name[MAX_LOCATION];
2873                   NewProjectDialog newProjectDialog;
2874
2875                   if(projectView)
2876                   {
2877                      projectView.visible = false;
2878                      if(!projectView.Destroy(0))
2879                         return true;
2880                   }
2881
2882                   newProjectDialog = { master = this };
2883
2884                   strcpy(name, app.argv[c]);
2885                   StripExtension(name);
2886                   GetLastDirectory(name, name);
2887                   newProjectDialog.projectName.contents = name;
2888                   newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
2889                   newProjectDialog.locationEditBox.path = parentPath;
2890                   newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
2891
2892                   incref newProjectDialog;
2893                   newProjectDialog.Modal();
2894                   if(projectView)
2895                   {
2896                      ideSettings.AddRecentProject(projectView.fileName);
2897                      ide.UpdateRecentMenus();
2898                      settingsContainer.Save();
2899                   }
2900                   delete newProjectDialog;
2901                   // Open only one project
2902                   break;
2903                }
2904                else
2905                   ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, openAsText ? "txt" : null, yes, normal, false);
2906             }
2907             else if(strstr(fullPath, "http://") == fullPath)
2908                ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, openAsText ? "txt" : null, yes, normal, false);
2909          }
2910       }
2911       if(passThrough && projectView && projectView.project && workspace)
2912          workspace.commandLineArgs = passArgs;
2913       if(passDebugWorkDir && projectView && projectView.project && workspace)
2914       {
2915          workspace.debugDir = passDebugWorkDir;
2916          delete passDebugWorkDir;
2917       }
2918       if(debugStart)
2919          ;//MenuDebugStart(debugStartResumeItem, 0); // <-- how TODO this without getting into the app.Wait lock
2920
2921       UpdateToolBarActiveConfigs(false);
2922       UpdateToolBarActiveCompilers();
2923       delete passArgs;
2924       return true;
2925    }
2926
2927    void OnDestroy()
2928    {
2929       // IS THIS NEEDED? WASN'T HERE BEFORE...  Crashes on getting node's projectView otherwise
2930       if(projectView)
2931       {
2932          projectView.visible = false;
2933          projectView.Destroy(0);
2934          projectView = null;
2935       }
2936 #ifdef GDB_DEBUG_GUI
2937       gdbDialog.Destroy(0);
2938       delete gdbDialog;
2939 #endif
2940    }
2941
2942    void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
2943    {
2944       int c, len, count;
2945       char * newList;
2946       char * oldPaths[128];
2947       String oldList = new char[maxPathLen];
2948       Array<String> newExePaths { };
2949       //Map<String, bool> exePathExists { };
2950       bool found = false;
2951 #if defined(__unix__) || defined(__APPLE__)
2952       Array<String> newLibPaths { };
2953       Map<String, bool> libPathExists { };
2954 #endif
2955
2956       if(projectsDirs)
2957       {
2958          for(prj : workspace.projects)
2959          {
2960             DirExpression targetDirExp;
2961
2962             // SKIP FIRST PROJECT...
2963             if(prj == workspace.projects.firstIterator.data) continue;
2964
2965             // NOTE: Right now the additional project config dir will be
2966             //       obtained when the debugger is started, so toggling it
2967             //       while building will change which library gets used.
2968             //       To go with the initial state, e.g. when F5 was pressed,
2969             //       we nould need to keep a list of all project's active
2970             //       config upon startup.
2971             targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
2972
2973             /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
2974                cfg = prj.config;
2975             else
2976             {
2977                for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2978                   if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
2979                      break;
2980                if(!cfg)
2981                {
2982                   for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2983                      if(cfg.targetType == sharedLibrary && cfg.debug)
2984                         break;
2985                }
2986             }*/
2987             if(targetDirExp.dir)
2988             {
2989                char buffer[MAX_LOCATION];
2990 #if defined(__WIN32__)
2991                Array<String> paths = newExePaths;
2992 #else
2993                Array<String> paths = newLibPaths;
2994 #endif
2995                GetSystemPathBuffer(buffer, prj.topNode.path);
2996                PathCat(buffer, targetDirExp.dir);
2997                for(p : paths)
2998                {
2999                   if(!fstrcmp(p, buffer))
3000                   {
3001                      found = true;
3002                      break;
3003                   }
3004                }
3005                if(!found)
3006                   paths.Add(CopyString(buffer));
3007             }
3008             delete targetDirExp;
3009          }
3010       }
3011
3012       for(item : compiler.executableDirs)
3013       {
3014          found = false;
3015          for(p : newExePaths)
3016          {
3017             if(!fstrcmp(p, item))
3018             {
3019                found = true;
3020                break;
3021             }
3022          }
3023          if(!found)
3024             newExePaths.Add(CopySystemPath(item));
3025       }
3026
3027       GetEnvironment("PATH", oldList, maxPathLen);
3028 /*#ifdef _DEBUG
3029       printf("Old value of PATH: %s\n", oldList);
3030 #endif*/
3031       count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3032       for(c = 0; c < count; c++)
3033       {
3034          found = false;
3035          for(p : newExePaths)
3036          {
3037             if(!fstrcmp(p, oldPaths[c]))
3038             {
3039                found = true;
3040                break;
3041             }
3042          }
3043          if(!found)
3044             newExePaths.Add(CopySystemPath(oldPaths[c]));
3045       }
3046
3047       len = 0;
3048       for(path : newExePaths)
3049          len += strlen(path) + 1;
3050       newList = new char[len + 1];
3051       newList[0] = '\0';
3052       for(path : newExePaths)
3053       {
3054          strcat(newList, path);
3055          strcat(newList, pathListSep);
3056       }
3057       newList[len - 1] = '\0';
3058       SetEnvironment("PATH", newList);
3059 /*#ifdef _DEBUG
3060       printf("New value of PATH: %s\n", newList);
3061 #endif*/
3062       delete newList;
3063
3064       newExePaths.Free();
3065       delete newExePaths;
3066
3067 #if defined(__unix__) || defined(__APPLE__)
3068
3069       for(item : compiler.libraryDirs)
3070       {
3071          if(!libPathExists[item])  // fstrcmp should be used
3072          {
3073             newLibPaths.Add(item);
3074             libPathExists[item] = true;
3075          }
3076       }
3077
3078 #if defined(__APPLE__)
3079       GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3080 #else
3081       GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3082 #endif
3083 /*#ifdef _DEBUG
3084       printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3085 #endif*/
3086       count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3087       for(c = 0; c < count; c++)
3088       {
3089          if(!libPathExists[oldPaths[c]])  // fstrcmp should be used
3090          {
3091             newLibPaths.Add(oldPaths[c]);
3092             libPathExists[oldPaths[c]] = true;
3093          }
3094       }
3095
3096       len = 0;
3097       for(path : newLibPaths)
3098          len += strlen(path) + 1;
3099       newList = new char[len + 1];
3100       newList[0] = '\0';
3101       for(path : newLibPaths)
3102       {
3103          strcat(newList, path);
3104          strcat(newList, pathListSep);
3105       }
3106       newList[len - 1] = '\0';
3107 #if defined(__APPLE__)
3108       SetEnvironment("DYLD_LIBRARY_PATH", newList);
3109 #else
3110       SetEnvironment("LD_LIBRARY_PATH", newList);
3111 #endif
3112 /*#ifdef _DEBUG
3113       printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3114 #endif*/
3115       delete newList;
3116
3117       delete newLibPaths;
3118       delete libPathExists;
3119 #endif
3120
3121       if(compiler.distccEnabled && compiler.distccHosts)
3122          SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3123
3124       delete oldList;
3125    }
3126
3127    void DestroyTemporaryProjectDir()
3128    {
3129       if(tmpPrjDir && tmpPrjDir[0])
3130       {
3131          if(FileExists(tmpPrjDir).isDirectory)
3132             DestroyDir(tmpPrjDir);
3133          property::tmpPrjDir = null;
3134       }
3135    }
3136
3137    IDEWorkSpace()
3138    {
3139       // Graphics Driver Menu
3140       int c;
3141
3142       /*
3143       app.currentSkin.selectionColor = selectionColor;
3144       app.currentSkin.selectionText = selectionText;
3145       */
3146
3147 /*
3148       driverItems = new MenuItem[app.numDrivers];
3149       for(c = 0; c < app.numDrivers; c++)
3150       {
3151          driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3152          driverItems[c].id = c;
3153          driverItems[c].isRadio = true;         
3154       }
3155 */
3156       driverItems = new MenuItem[2];
3157 #if defined(__unix__)
3158          driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3159          driverItems[0].id = 0;
3160          driverItems[0].isRadio = true;         
3161 #else
3162          driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3163          driverItems[0].id = 0;
3164          driverItems[0].isRadio = true;         
3165 #endif
3166          driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3167          driverItems[1].id = 1;
3168          driverItems[1].isRadio = true;         
3169
3170 /*      skinItems = new MenuItem[app.numSkins];
3171       for(c = 0; c < app.numSkins; c++)
3172       {
3173          skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3174          skinItems[c].id = c;
3175          skinItems[c].isRadio = true;         
3176       }
3177 */
3178       ideFileDialog.master = this;
3179       ideProjectFileDialog.master = this;
3180
3181       //SetDriverAndSkin();
3182       return true;
3183    }
3184
3185    void UpdateRecentMenus()
3186    {
3187       int c;
3188       Menu fileMenu = menu.FindMenu($"File");
3189       Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3190       Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3191       char * itemPath = new char[MAX_LOCATION];
3192       char * itemName = new char[MAX_LOCATION+4];
3193       MenuItem item;
3194
3195       recentFiles.Clear();
3196       c = 0;
3197
3198       for(recent : ideSettings.recentFiles)
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          recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3204          c++;
3205       }
3206
3207       recentProjects.Clear();
3208       c = 0;
3209       for(recent : ideSettings.recentProjects)
3210       {
3211          strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3212          MakeSystemPath(itemPath);
3213          snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3214          recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3215          c++;
3216       }
3217
3218       delete itemPath;
3219       delete itemName;
3220    }
3221
3222    ~IDEWorkSpace()
3223    {
3224       delete driverItems;
3225       delete skinItems;
3226       delete ideSettings;
3227    }
3228 }
3229
3230 void DestroyDir(char * path)
3231 {
3232    RecursiveDeleteFolderFSI fsi { };
3233    fsi.Iterate(path);
3234    delete fsi;
3235 }
3236
3237 #if defined(__WIN32__)
3238 define sdkDirName = "Ecere SDK";
3239 #else
3240 define sdkDirName = "ecere";
3241 #endif
3242
3243 void FindAndShellOpenInstalledFolder(char * name)
3244 {
3245    char * p = new char[MAX_LOCATION];
3246    char * v = new char[maxPathLen];
3247    byte * tokens[256];
3248    int c, numTokens;
3249    Array<String> paths { };
3250    p[0] = v[0] = '\0';
3251    strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3252    StripLastDirectory(p, p);
3253    PathCat(p, name);
3254    paths.Add(CopyString(p));
3255 #if defined(__WIN32__)
3256    GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3257    if(v[0])
3258    {
3259       strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3260       PathCat(p, name); paths.Add(CopyString(p));
3261    }
3262    GetEnvironment("AppData", v, maxPathLen);
3263    if(v[0])
3264    {
3265       strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3266       PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
3267    }
3268    GetEnvironment("ProgramFiles", v, maxPathLen);
3269    if(v[0])
3270    {
3271       strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3272       PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
3273    }
3274    GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3275    if(v[0])
3276    {
3277       strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3278       PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
3279    }
3280    GetEnvironment("SystemDrive", v, maxPathLen);
3281    if(v[0])
3282    {
3283       strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3284       PathCat(p, "Program Files"); PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
3285    }
3286 #else
3287    GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3288    numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3289    for(c=0; c<numTokens; c++)
3290    {
3291       strncpy(p, tokens[c], MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3292       PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
3293    }
3294 #endif
3295    for(path : paths)
3296    {
3297       strncpy(p, path, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3298       if(FileExists(p).isDirectory)
3299       {
3300          ShellOpen(p);
3301          break;
3302       }
3303    }
3304    delete p;
3305    delete v;
3306    paths.Free();
3307    delete paths;
3308 }
3309
3310 void FindAndShellOpenInstalledFile(char * subdir, char * name)
3311 {
3312    char * p = new char[MAX_LOCATION];
3313    char * v = new char[maxPathLen];
3314    byte * tokens[256];
3315    int c, numTokens;
3316    Array<String> paths { };
3317    p[0] = v[0] = '\0';
3318    strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3319    paths.Add(CopyString(p));
3320    StripLastDirectory(p, p);
3321    PathCat(p, subdir);
3322    paths.Add(CopyString(p));
3323 #if defined(__WIN32__)
3324    GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3325    if(v[0])
3326    {
3327       strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3328       PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
3329    }
3330    GetEnvironment("AppData", v, maxPathLen);
3331    if(v[0])
3332    {
3333       strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3334       PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
3335    }
3336    GetEnvironment("ProgramFiles", v, maxPathLen);
3337    if(v[0])
3338    {
3339       strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3340       PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
3341    }
3342    GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3343    if(v[0])
3344    {
3345       strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3346       PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
3347    }
3348    GetEnvironment("SystemDrive", v, maxPathLen);
3349    if(v[0])
3350    {
3351       strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3352       PathCat(p, "Program Files"); PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
3353    }
3354 #else
3355    GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3356    numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3357    for(c=0; c<numTokens; c++)
3358    {
3359       strncpy(p, tokens[c], MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3360       PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
3361    }
3362 #endif
3363    for(path : paths)
3364    {
3365       strncpy(p, path, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3366       PathCat(p, name);
3367       if(FileExists(p).isFile)
3368       {
3369          ShellOpen(p);
3370          break;
3371       }
3372    }
3373    delete p;
3374    delete v;
3375    paths.Free();
3376    delete paths;
3377 }
3378
3379 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3380 {
3381    bool preserveRootFolder;
3382
3383    void OutFolder(char * folderPath, bool isRoot)
3384    {
3385       if(!(preserveRootFolder && isRoot))
3386          RemoveDir(folderPath);
3387    }
3388
3389    bool OnFile(char * filePath)
3390    {
3391       DeleteFile(filePath);
3392       return true;
3393    }
3394 }
3395
3396 class IDEApp : GuiApplication
3397 {
3398    //driver = "Win32Console";
3399    // driver = "OpenGL";
3400    // skin = "Aqua";
3401    //skin = "TVision";
3402
3403    TempFile includeFile { };
3404
3405    bool Init()
3406    {
3407       SetLoggingMode(stdOut, null);
3408       //SetLoggingMode(debug, null);
3409
3410       settingsContainer.Load();
3411 #if defined(__unix__) || defined(__APPLE__)
3412       app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3413 #else
3414       app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3415 #endif
3416       ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3417
3418       SetInIDE(true);
3419
3420       desktop.text = titleECEREIDE;
3421       /*
3422       int c;
3423       for(c = 1; c<app.argc; c++)
3424       {
3425          char fullPath[MAX_LOCATION];
3426          GetWorkingDir(fullPath, MAX_LOCATION);
3427          PathCat(fullPath, app.argv[c]);
3428          ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal, false);
3429       }
3430       */
3431
3432       if(!LoadIncludeFile())
3433          PrintLn("error: unable to load :crossplatform.mk file inside ide binary.");
3434
3435       return true;
3436    }
3437
3438    bool LoadIncludeFile()
3439    {
3440       bool result = false;
3441       File include = FileOpen(":crossplatform.mk", read);
3442       if(include)
3443       {
3444          File f = includeFile;
3445          if(f)
3446          {
3447             for(; !include.Eof(); )
3448             {
3449                char buffer[4096];
3450                int count = include.Read(buffer, 1, 4096);
3451                f.Write(buffer, 1, count);
3452             }
3453             result = true;
3454          }
3455          delete include;
3456       }
3457       return result;
3458    }
3459 }
3460
3461 IDEMainFrame ideMainFrame { };
3462
3463 define app = ((IDEApp)__thisModule);
3464 #ifdef _DEBUG
3465 define titleECEREIDE = $"ECERE IDE (Debug)";
3466 #else
3467 define titleECEREIDE = $"ECERE IDE";
3468 #endif