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