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