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