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