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