ecere: Made nativeDecorations default on MessageBox; ide: Took out setting master...
[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       {
1257          char fileName[MAX_LOCATION];
1258          strcpy(fileName, project.topNode.path);
1259          PathCat(fileName, project.topNode.name);
1260       }
1261       return projectView;
1262    }
1263
1264    bool GetDebugMenusDisabled()
1265    {
1266       if(projectView)
1267       {
1268          Project project = projectView.project;
1269          if(project)
1270             if(project.targetType == executable)
1271                return false;
1272            
1273       }
1274       return true;
1275    }
1276
1277    void RepositionWindows(bool expand)
1278    {
1279       if(this)
1280       {
1281          Window child;
1282          bool inDebugMode = debugger.isActive;
1283          bool callStackVisible = expand ? false : callStackView.visible;
1284          bool threadsVisible = expand ? false : threadsView.visible;
1285          bool watchesVisible = expand ? false : watchesView.visible;
1286          bool breakpointsVisible = expand ? false : breakpointsView.visible;
1287          bool toolBoxVisible = toolBox.visible;
1288          bool outputVisible = expand ? false : outputView.visible;
1289          int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1290          int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1291          
1292          for(child = firstChild; child; child = child.next)
1293          {
1294             if(child._class == class(CodeEditor) || child._class == class(Designer) || 
1295                child._class == class(Sheet) || child._class == class(ProjectView))
1296             {
1297                Anchor anchor = child.anchor;
1298                anchor.top = topDistance;
1299                anchor.bottom = bottomDistance;
1300                if(child._class == class(CodeEditor) || child._class == class(Designer))
1301                {
1302                   anchor.right = toolBoxVisible ? 150 : 0;
1303                }
1304                child.anchor = anchor;
1305             }
1306             else if(expand)
1307             {
1308                if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) || 
1309                   child._class == class(BreakpointsView))
1310                   child.visible = false;
1311             }
1312          }
1313          // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1314          Update(null);
1315       }
1316    }
1317
1318    bool ShowCodeEditor()
1319    {
1320       if(activeClient)
1321          activeClient.Activate();
1322       else if(projectView)
1323       { 
1324          projectView.visible = true;
1325          projectView.Activate();
1326       }
1327       else
1328       {
1329          sheet.visible = true;
1330          sheet.Activate();
1331       }
1332       return false;
1333    }
1334
1335    bool ShouldStopBuild()
1336    {
1337       return projectView.stopBuild;
1338    }
1339
1340    void DocumentSaved(Window document, char * fileName)
1341    {
1342       ideSettings.AddRecentFile(fileName);
1343       ide.UpdateRecentMenus();
1344       settingsContainer.Save();
1345    }
1346
1347    bool Window::OnFileModified(FileChange fileChange, char * param)
1348    {
1349       char temp[4096];
1350       sprintf(temp, "The document %s was modified by another application.\n"
1351             "Would you like to reload it and lose your changes?", this.fileName);
1352       if(MessageBox { type = yesNo/*, master = this*//*.parent*/,
1353             text = "Document has been modified", contents = temp }.Modal() == yes)
1354       {
1355          char * fileName = CopyString(this.fileName);
1356          WindowState state = this.state;
1357          Anchor anchor = this.anchor;
1358          Size size = this.size;
1359
1360          this.modifiedDocument = false;
1361          this.Destroy(0);
1362          this = ide.OpenFile(fileName, normal, true, null, no, normal);
1363          if(this)
1364          {
1365             this.anchor = anchor;
1366             this.size = size;
1367             this.SetState(state, true, 0);
1368          }
1369          delete fileName;
1370          return true;
1371       }
1372       return true;
1373    }
1374
1375    void UpdateMakefiles()
1376    {
1377       if(workspace)
1378       {
1379          for(prj : workspace.projects)
1380          {
1381             bool first = prj == workspace.projects.firstIterator.data;
1382             projectView.ProjectUpdateMakefileForAllConfigs(prj, first, first);
1383          }
1384       }
1385    }
1386
1387    void AdjustMenus()
1388    {
1389       bool unavailable = !project;
1390
1391       projectQuickItem.disabled           = !unavailable;
1392
1393       projectAddItem.disabled             = unavailable;
1394
1395       activeCompilerItem.disabled         = unavailable;
1396       projectActiveConfigItem.disabled    = unavailable;
1397       projectSettingsItem.disabled        = unavailable;
1398
1399       projectBrowseFolderItem.disabled    = unavailable;
1400
1401       viewProjectItem.disabled            = unavailable;
1402
1403       AdjustBuildMenus();
1404       AdjustDebugMenus();
1405    }
1406
1407    void AdjustBuildMenus()
1408    {
1409       bool unavailable = project && projectView.buildInProgress;
1410
1411       projectNewItem.disabled          = unavailable;
1412       projectOpenItem.disabled         = unavailable;
1413
1414       unavailable = !project || projectView.buildInProgress;
1415
1416       projectCloseItem.disabled        = unavailable;
1417
1418       projectRunItem.disabled          = unavailable || project.targetType != executable;
1419       projectBuildItem.disabled        = unavailable;
1420       projectLinkItem.disabled         = unavailable;
1421       projectRebuildItem.disabled      = unavailable;
1422       projectCleanItem.disabled        = unavailable;
1423       projectRegenerateItem.disabled   = unavailable;
1424       projectCompileItem.disabled      = unavailable;
1425    }
1426
1427    void AdjustDebugMenus()
1428    {
1429       bool unavailable = !project || project.targetType != executable ||
1430                projectView.buildInProgress == buildingMainProject;
1431       bool active = ide.debugger.isActive;
1432       bool executing = ide.debugger.state == running;
1433       //bool holding = ide.debugger.state == stopped;
1434
1435       debugStartResumeItem.disabled       = unavailable || executing;
1436
1437       debugStartResumeItem.text           = active ? "Resume" : "Start";
1438       debugStartResumeItem.NotifySelect   = active ? MenuDebugResume : MenuDebugStart;
1439
1440       debugBreakItem.disabled             = unavailable || !executing;
1441       debugStopItem.disabled              = unavailable || !active;
1442       debugRestartItem.disabled           = unavailable || !active;
1443
1444       debugStepIntoItem.disabled          = unavailable || executing;
1445       debugStepOverItem.disabled          = unavailable || executing;
1446       debugStepOutItem.disabled           = unavailable || executing || !active;
1447       debugSkipStepOverItem.disabled      = unavailable || executing;
1448       debugSkipStepOutItem.disabled       = unavailable || executing || !active;
1449
1450       if((Designer)GetActiveDesigner())
1451       {
1452          CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
1453          if(codeEditor)
1454          {
1455             codeEditor.debugRunToCursor.disabled      = unavailable || executing;
1456             codeEditor.debugSkipRunToCursor.disabled  = unavailable || executing;
1457          }
1458       }
1459    }
1460
1461    void ChangeFileDialogsDirectory(char * directory, bool saveSettings)
1462    {
1463       char tempString[MAX_LOCATION];
1464       strcpy(tempString, directory);
1465       if(saveSettings && !projectView)
1466       {
1467          ideSettings.ideFileDialogLocation = directory;
1468          settingsContainer.Save();
1469       }
1470
1471       ideFileDialog.currentDirectory = tempString;
1472       codeEditorFileDialog.currentDirectory = tempString;
1473       codeEditorFormFileDialog.currentDirectory = tempString;
1474    }
1475
1476    void ChangeProjectFileDialogDirectory(char * directory)
1477    {
1478       ideSettings.ideProjectFileDialogLocation = directory;
1479       settingsContainer.Save();
1480    }
1481
1482    Window FindWindow(char * filePath)
1483    {
1484       Window document = null;
1485
1486       // TOCHECK: Do we need to change slashes here?
1487       for(document = firstChild; document; document = document.next)
1488       {
1489          char * fileName = document.fileName;
1490          if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
1491          {
1492             document.visible = true;
1493             document.Activate();
1494             return document;
1495          }
1496       }
1497       return null;
1498    }
1499
1500    bool DontTerminateDebugSession(char * title)
1501    {
1502       if(debugger.isActive)
1503       {
1504          if(MessageBox { type = yesNo, /*master = ide, */
1505                            contents = "Do you want to terminate the debugging session in progress?", 
1506                            text = title }.Modal() == no)
1507             return true;
1508          /*
1509          MessageBox msg { type = yesNo, master = ide, 
1510                            contents = "Do you want to terminate the debugging session in progress?", 
1511                            text = title };
1512          if(msg.Modal() == no)
1513          {
1514             msg.Destroy(0);
1515             delete msg;
1516             return true;
1517          }
1518          msg.Destroy(0);
1519          delete msg;*/
1520       }
1521       return false;
1522    }
1523
1524    Window OpenFile(char * origFilePath, WindowState state, bool visible, char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod)
1525    {
1526       char extension[MAX_EXTENSION] = "";
1527       Window document = null;
1528       bool isProject = false;
1529       bool needFileModified = true;
1530       char winFilePath[MAX_LOCATION];
1531       char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
1532
1533       if(!type)
1534       {
1535          GetExtension(filePath, extension);
1536          strlwr(extension);
1537       }
1538       else
1539          strcpy(extension, type);
1540
1541       if(strcmp(extension, ProjectExtension))
1542       {
1543          for(document = firstChild; document; document = document.next)
1544          {
1545             char * fileName = document.fileName;
1546             if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
1547             {
1548                document.visible = true;
1549                document.Activate();
1550                return document;
1551             }
1552          }
1553       }
1554
1555       if(createIfFails == whatever)
1556          ;
1557       else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
1558       {
1559          if(openMethod == normal)
1560          {
1561             if(DontTerminateDebugSession("Open Project"))
1562                return null;
1563             isProject = true;
1564             if(MenuWindowCloseAll(null, 0))
1565             {
1566                if(projectView)
1567                {
1568                   projectView.visible = false;
1569                   projectView.Destroy(0);
1570                   // Where did this come from? projectView = null;
1571                }
1572                if(!projectView)
1573                {
1574                   for(;;)
1575                   {
1576                      Project project;
1577                      Workspace workspace = null;
1578                      
1579                      if(FileExists(filePath))
1580                      {
1581                         if(!strcmp(extension, ProjectExtension))
1582                         {
1583                            char workspaceFile[MAX_LOCATION];
1584                            strcpy(workspaceFile, filePath);
1585                            ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
1586                            workspace = LoadWorkspace(workspaceFile, filePath);
1587                         }
1588                         else if(!strcmp(extension, WorkspaceExtension))
1589                            workspace = LoadWorkspace(filePath, null);
1590                         else
1591                            return null;
1592                         //project = LoadProject(filePath);
1593                      }
1594                      
1595                      if(workspace)
1596                      {
1597                         char absolutePath[MAX_LOCATION];
1598                         CreateProjectView(workspace, filePath);
1599                         document = projectView;
1600
1601                         workspace.DropInvalidBreakpoints();
1602                         workspace.Save();
1603
1604                         ide.projectView.ShowOutputBuildLog(true);
1605                         ide.projectView.DisplayCompiler(false);
1606                         UpdateMakefiles();
1607                         {
1608                            char newWorkingDir[MAX_LOCATION];
1609                            StripLastDirectory(filePath, newWorkingDir);
1610                            ChangeFileDialogsDirectory(newWorkingDir, false);
1611                         }
1612                         if(document)
1613                            document.fileName = filePath;
1614
1615                         SetText("%s - %s", filePath, titleECEREIDE);
1616
1617                         // this crashes on starting ide with epj file, solution please?
1618                         // app.UpdateDisplay();
1619
1620                         workspace.holdTracking = true;
1621                         for(ofi : workspace.openedFiles)
1622                         {
1623                            if(ofi.state != closed)
1624                            {
1625                               Window file = OpenFile(ofi.path, normal, true, null, no, normal);
1626                               if(file)
1627                               {
1628                                  char fileName[MAX_LOCATION];
1629                                  ProjectNode node;
1630                                  GetLastDirectory(ofi.path, fileName);
1631                                  node = projectView.project.topNode.Find(fileName, true);
1632                                  if(node)
1633                                     node.EnsureVisible();
1634                               }
1635                            }
1636                         }
1637                         workspace.holdTracking = false;
1638
1639                         workspace.timer.Start();
1640
1641                         findInFilesDialog.mode = FindInFilesMode::project;
1642                         findInFilesDialog.currentDirectory = ide.project.topNode.path;
1643                         
1644                         {
1645                            char location[MAX_LOCATION];
1646                            StripLastDirectory(ide.project.topNode.path, location);
1647                            ChangeProjectFileDialogDirectory(location);
1648                         }
1649                         
1650                         /*
1651                         if(projectView.debugger)
1652                            projectView.debugger.EvaluateWatches();
1653                         */
1654                         
1655                         break;
1656                      }
1657                      else 
1658                      {
1659                         if(MessageBox { type = yesNo, parent = this, text = "Error opening project", contents = "Open a different project?" }.Modal() == yes)
1660                         {
1661                            if(ideProjectFileDialog.Modal() == cancel)
1662                               return null;
1663                            filePath = ideProjectFileDialog.filePath;
1664                            GetExtension(filePath, extension);
1665                         }
1666                         else
1667                            return null;
1668                      }
1669                   }
1670                }
1671             }
1672             else
1673                return document;
1674          }
1675          else if(openMethod == add)
1676          {
1677             if(workspace)
1678             {
1679                Project prj = null;
1680                char slashFilePath[MAX_LOCATION];
1681                GetSlashPathBuffer(slashFilePath, filePath);
1682                for(p : workspace.projects)
1683                {
1684                   if(!fstrcmp(p.filePath, slashFilePath))
1685                   {
1686                      prj = p;
1687                      break;
1688                   }
1689                }
1690                if(prj)
1691                {
1692                   MessageBox { type = ok, parent = parent, /*master = this, */text = "Same Project", 
1693                         contents = "This project is already present in workspace." }.Modal();
1694                }
1695                else
1696                {
1697                   prj = LoadProject(filePath);
1698                   if(prj)
1699                   {
1700                      workspace.projects.Add(prj);
1701                      if(projectView)
1702                         projectView.AddNode(prj.topNode, null);
1703                      workspace.modified = true;
1704                      workspace.Save();
1705                      findInFilesDialog.AddProjectItem(prj);
1706                      projectView.ProjectUpdateMakefileForAllConfigs(prj, true, true);
1707                      // projectView is associated with the main project and not with the one just added but
1708                      return projectView; // just to let the caller know something was opened
1709                   }
1710                }
1711             }
1712             else
1713                return null;
1714          }
1715       }
1716       else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
1717             !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
1718             !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
1719       {
1720          if(FileExists(filePath))
1721             document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable, 
1722                                        hasVertScroll = true, hasHorzScroll = true, parent = this, state = state, 
1723                                        visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
1724                                     };
1725          if(!document)
1726             MessageBox { type = ok, parent = this, text = filePath, contents = "File doesn't exist." }.Modal();
1727       }
1728 #ifndef NO3D
1729       else if(!strcmp(extension, "3ds"))
1730       {
1731          if(FileExists(filePath))
1732             document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable, 
1733                                     hasVertScroll = true, hasHorzScroll = true, parent = this, state = state, 
1734                                     visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
1735                                     };
1736
1737          if(!document)
1738             MessageBox { type = ok, parent = this, text = filePath, contents = "File doesn't exist." }.Modal();
1739       }
1740 #endif
1741       else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
1742             !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
1743             !strcmp(extension, "htm") || !strcmp(extension, "html") ||
1744             !strcmp(extension, "css") || !strcmp(extension, "php") ||
1745             !strcmp(extension, "js"))
1746       {
1747          CodeEditor editor { parent = this, state = state, visible = false };
1748          editor.updatingCode = true;
1749          if(editor.LoadFile(filePath))
1750          {
1751             document = editor;
1752             editor.visible = true;
1753          }
1754          else
1755             delete editor;
1756          needFileModified = false;
1757       }
1758       else
1759       {
1760          CodeEditor editor { parent = this, state = state, visible = false };
1761          if(editor.LoadFile(filePath))
1762          {
1763             document = editor;
1764             editor.visible = true;
1765          }
1766          else
1767             delete editor;
1768          needFileModified = false;
1769       }
1770
1771       if(document && (document._class == class(PictureEdit) ||
1772             document._class == class(ModelView)))
1773       {
1774          document.Create();
1775          if(document)
1776          {
1777             document.fileName = filePath;
1778             if(workspace && !workspace.holdTracking)
1779                workspace.UpdateOpenedFileInfo(filePath, opened);
1780          }
1781       }
1782       
1783       if(!document && createIfFails != no)
1784       {
1785          if(createIfFails != yes && !needFileModified && 
1786                MessageBox { type = yesNo, parent = this, text = filePath, contents = "File doesn't exist. Create?" }.Modal() == yes)
1787             createIfFails = yes;
1788          if(createIfFails == yes || createIfFails == whatever)
1789          {
1790             document = (Window)NewCodeEditor(this, state, true);
1791             if(document)
1792                document.fileName = filePath;
1793          }
1794       }
1795
1796       if(document)
1797       {
1798          if(projectView && document._class == class(CodeEditor) && workspace)
1799          {
1800             int lineNumber, position;
1801             Point scroll;
1802             CodeEditor editor = (CodeEditor)document;
1803             editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
1804             editor.openedFileInfo.holdTracking = true;
1805             lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
1806             position = Max(editor.openedFileInfo.position - 1, 0);
1807             editor.editBox.GoToLineNum(lineNumber);
1808             editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
1809             scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
1810             scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
1811             editor.editBox.scroll = scroll;
1812             editor.openedFileInfo.holdTracking = false;
1813          }
1814          
1815          if(needFileModified)
1816             document.OnFileModified = OnFileModified;
1817          document.NotifySaved = DocumentSaved;
1818          
1819          if(isProject)
1820             ideSettings.AddRecentProject(document.fileName);
1821          else
1822             ideSettings.AddRecentFile(document.fileName);
1823          ide.UpdateRecentMenus();
1824          settingsContainer.Save();
1825          
1826          return document;
1827       }
1828       else
1829          return null;
1830    }
1831
1832    // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
1833    /*bool Window::GenericDocumentOnClose(bool parentClosing)
1834    {
1835       if(!parentClosing && ide.workspace)
1836          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
1837       return true;
1838    }*/
1839    bool ModelView::ModelViewOnClose(bool parentClosing)
1840    {
1841       if(!parentClosing && ide.workspace)
1842          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
1843       return true;
1844    }
1845    bool PictureEdit::PictureEditOnClose(bool parentClosing)
1846    {
1847       if(!parentClosing && ide.workspace)
1848          ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
1849       return true;
1850    }
1851
1852    /*
1853    void OnUnloadGraphics(Window window)
1854    {
1855       display.ClearMaterials();
1856       display.ClearTextures();
1857       display.ClearMeshes();
1858    }
1859    */
1860
1861    bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
1862    {
1863       caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
1864       num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
1865       return true;
1866    }
1867
1868    bool OnKeyDown(Key key, unichar ch)
1869    {
1870       switch(key)
1871       {
1872          case b:
1873             projectView.Update(null);
1874             break;
1875          case capsLock:
1876             caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
1877             break;
1878          case numLock:
1879             num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
1880             break;
1881       }
1882       return true;
1883    }
1884
1885    void GoToError(const char * line)
1886    {
1887       if(projectView)
1888          projectView.GoToError(line);
1889    }
1890
1891    void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
1892    {
1893       char *path = text;
1894       char *colon = strchr(text, ':');
1895       char filePath[MAX_LOCATION];
1896       char completePath[MAX_LOCATION];
1897       int line = 0, col = 0;
1898       Project prj = null;
1899
1900       if(text[3] == '(')
1901       {
1902          char * close = strchr(text, ')');
1903          if(close)
1904          {
1905             char name[256];
1906             strncpy(name, &text[4], close - text - 4);
1907             name[close - text - 4] = '\0';
1908             for(p : ide.workspace.projects)
1909             {
1910                if(!strcmp(p.name, name))
1911                {
1912                   path = close + 1;
1913                   prj = p;
1914                   break;
1915                }
1916             }
1917          }
1918       }
1919       if(!prj)
1920          prj = project ? project : (dir ? null : ide.project);
1921       if(colon && (colon[1] == '/' || colon[1] == '\\'))
1922       {
1923          path = (colon - 1 > path) ? colon - 1 : path;
1924          colon = strstr(colon + 1, ":");
1925       }
1926       while(isspace(*path)) path++;
1927       if(colon)
1928       {
1929          strncpy(filePath, path, colon - path);
1930          filePath[colon - path] = '\0';
1931          line = atoi(colon + 1);
1932          colon = strstr(colon + 1, ":");
1933          if(colon)
1934             col = atoi(colon + 1);
1935       }
1936       else if(path - 1 >= path && *(path - 1) == '\"')
1937       {
1938          colon = strchr(path, '\"');
1939          if(colon)
1940          {
1941             strncpy(filePath, path, colon - path);
1942             filePath[colon - path] = '\0';
1943          }
1944       }
1945
1946       if(prj)
1947          strcpy(completePath, prj.topNode.path);
1948       else if(dir && dir[0])
1949          strcpy(completePath, dir);
1950       else
1951          completePath[0] = '\0';
1952       PathCat(completePath, filePath);
1953
1954       if(FileExists(completePath).isFile)
1955       {
1956          CodeEditor codeEditor = (CodeEditor)OpenFile(completePath, normal, true, "", no, normal);
1957          if(codeEditor && line)
1958          {
1959             EditBox editBox = codeEditor.editBox;
1960             editBox.GoToLineNum(line - 1);
1961             editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
1962          }
1963       }
1964    }
1965
1966    void OnRedraw(Surface surface)
1967    {
1968       Bitmap bitmap = back.bitmap;
1969       if(bitmap)
1970          surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
1971    }
1972
1973    void SheetSelected(SheetType sheetSelected)
1974    {
1975       if(activeChild == sheet)
1976       {
1977          if(sheetSelected == methods)
1978          {
1979             viewPropertiesItem.accelerator = f4;
1980             viewPropertiesItem.parent = viewMenu;
1981             viewMethodsItem.parent = null;
1982          }
1983          else
1984          {
1985             viewMethodsItem.accelerator = f4;
1986             viewMethodsItem.parent = viewMenu;
1987             viewPropertiesItem.parent = null;
1988          }
1989       }
1990       else
1991       {
1992          viewMethodsItem.parent = viewMenu;
1993          viewPropertiesItem.parent = viewMenu;
1994          if(sheetSelected == methods)
1995          {
1996             viewMethodsItem.accelerator = f4;
1997             viewPropertiesItem.accelerator = 0;
1998          }
1999          else
2000          {
2001             viewMethodsItem.accelerator = 0;
2002             viewPropertiesItem.accelerator = f4;
2003          }
2004       }
2005    }
2006
2007    void OnActivateClient(Window client, Window previous)
2008    {
2009       //if(!client || client != previous)
2010       {
2011          Class dataType;
2012          if(!client || client != previous)
2013          {
2014             if(previous)
2015                dataType = previous._class;
2016             if(previous && !strcmp(dataType.name, "CodeEditor"))
2017             {
2018                ((CodeEditor)previous).UpdateFormCode();
2019             }
2020             else if(previous && !strcmp(dataType.name, "Designer"))
2021             {
2022                ((Designer)previous).codeEditor.UpdateFormCode();
2023             }
2024          }
2025
2026          if(client)
2027             dataType = client._class;
2028          if(client && !strcmp(dataType.name, "CodeEditor"))
2029          {
2030             CodeEditor codeEditor = (CodeEditor)client;
2031             SetPrivateModule(codeEditor.privateModule);
2032             SetCurrentContext(codeEditor.globalContext);
2033             SetTopContext(codeEditor.globalContext);
2034             SetGlobalContext(codeEditor.globalContext);
2035             
2036             SetDefines(&codeEditor.defines);
2037             SetImports(&codeEditor.imports);
2038
2039             SetActiveDesigner(codeEditor.designer);
2040             
2041             sheet.codeEditor = codeEditor;
2042             toolBox.codeEditor = codeEditor;
2043
2044             viewDesignerItem.parent = viewMenu;
2045             if(activeChild != codeEditor)
2046             {
2047                viewCodeItem.parent = viewMenu;
2048                viewDesignerItem.accelerator = 0;
2049                viewCodeItem.accelerator = f8;
2050             }
2051             else
2052             {
2053                viewCodeItem.parent = null;
2054                viewDesignerItem.accelerator = f8;
2055             }
2056          }
2057          else if(client && !strcmp(dataType.name, "Designer"))
2058          {
2059             CodeEditor codeEditor = ((Designer)client).codeEditor;
2060             if(codeEditor)
2061             {
2062                SetPrivateModule(codeEditor.privateModule);
2063                SetCurrentContext(codeEditor.globalContext);
2064                SetTopContext(codeEditor.globalContext);
2065                SetGlobalContext(codeEditor.globalContext);
2066                SetDefines(&codeEditor.defines);
2067                SetImports(&codeEditor.imports);
2068             }
2069             else
2070             {
2071                SetPrivateModule(null);
2072                SetCurrentContext(null);
2073                SetTopContext(null);
2074                SetGlobalContext(null);
2075                SetDefines(null);
2076                SetImports(null);
2077             }
2078
2079             SetActiveDesigner((Designer)client);
2080
2081             sheet.codeEditor = codeEditor;
2082             toolBox.codeEditor = codeEditor;
2083
2084             viewCodeItem.parent = viewMenu;
2085             if(activeChild != client)
2086             {
2087                viewDesignerItem.parent = viewMenu;
2088                viewDesignerItem.accelerator = f8;
2089                viewCodeItem.accelerator = 0;
2090             }
2091             else
2092             {
2093                viewDesignerItem.parent = null;
2094                viewCodeItem.accelerator = f8;
2095             }
2096          }
2097          else
2098          {
2099             if(sheet)
2100                sheet.codeEditor = null;
2101             toolBox.codeEditor = null;
2102             SetActiveDesigner(null);
2103
2104             viewDesignerItem.parent = null;
2105             viewCodeItem.parent = null;
2106          }
2107          if(sheet)
2108             SheetSelected(sheet.sheetSelected);
2109       }
2110
2111       projectCompileItem = null;
2112
2113       if(statusBar)
2114       {
2115          statusBar.Clear();
2116          if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
2117          {
2118             CodeEditor codeEditor = (CodeEditor)client;
2119             EditBox editBox = codeEditor.editBox;
2120
2121             statusBar.AddField(pos);
2122
2123             caps = { width = 40, text = "CAPS", color = app.GetKeyState(capsState) ? black : Color { 128, 128, 128 } };
2124             statusBar.AddField(caps);
2125
2126             ovr = { width = 30, text = "OVR", color = editBox.overwrite ? black : Color { 128, 128, 128 } };
2127             statusBar.AddField(ovr);
2128
2129             num = { width = 30, text = "NUM", color = app.GetKeyState(numState) ? black : Color { 128, 128, 128 } };
2130             statusBar.AddField(num);
2131
2132             //statusBar.text = "Ready";
2133
2134             if(projectView && projectView.project)
2135             {
2136                ProjectNode node = projectView.GetNodeFromWindow(client, null);
2137                if(node)
2138                {
2139                   char name[1024];
2140                   sprintf(name, "Compile %s", node.name);
2141                   projectCompileItem = 
2142                   {
2143                      copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
2144
2145                      bool NotifySelect(MenuItem selection, Modifiers mods)
2146                      {
2147                         if(projectView)
2148                         {
2149                            ProjectNode node = projectView.GetNodeFromWindow(activeClient, null);
2150                            if(node)
2151                               projectView.Compile(node);
2152                         }
2153                         return true;
2154                      }
2155                   };
2156                   projectMenu.AddDynamic(projectCompileItem, null, false);
2157                }
2158             }
2159          }
2160          else
2161          {
2162             caps = ovr = num = null;
2163          }
2164       }
2165    }
2166
2167    bool OnClose(bool parentClosing)
2168    {
2169       //return !projectView.buildInProgress;
2170       if(projectView && projectView.buildInProgress)
2171          return false;
2172       if(DontTerminateDebugSession("Close IDE"))
2173          return false;
2174       if(findInFilesDialog)
2175          findInFilesDialog.SearchStop();
2176       if(workspace)
2177       {
2178          workspace.timer.Stop();
2179          workspace.Save();
2180       }
2181       return true;
2182    }
2183
2184    bool OnPostCreate()
2185    {
2186       int c;
2187       for(c = 1; c<app.argc; c++)
2188       {
2189          char fullPath[MAX_LOCATION];
2190          GetWorkingDir(fullPath, MAX_LOCATION);
2191          PathCat(fullPath, app.argv[c]);
2192          if(FileExists(fullPath))
2193             ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
2194       }
2195       return true;
2196    }
2197
2198    void OnDestroy()
2199    {
2200       // IS THIS NEEDED? WASN'T HERE BEFORE...
2201       if(projectView)
2202       {
2203          projectView.visible = false;
2204          projectView.Destroy(0);
2205          projectView = null;
2206       }
2207 #ifdef GDB_DEBUG_GUI
2208       gdbDialog.Destroy(0);
2209       delete gdbDialog;
2210 #endif
2211    }
2212
2213    void SetPath(bool projectsDirs)
2214    {
2215       int c, len, count;
2216       char * newList;
2217       char * oldPaths[128];
2218       char oldList[MAX_LOCATION * 128];
2219       Array<String> newExePaths { };
2220       //Map<String, bool> exePathExists { };
2221       bool found = false;
2222 #if defined(__unix__) || defined(__APPLE__)
2223       Array<String> newLibPaths { };
2224       Map<String, bool> libPathExists { };
2225 #endif
2226       CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2227
2228       if(projectsDirs)
2229       {
2230          for(prj : workspace.projects)
2231          {
2232             DirExpression targetDirExp;
2233
2234             // SKIP FIRST PROJECT...
2235             if(prj == workspace.projects.firstIterator.data) continue;
2236
2237             targetDirExp = prj.targetDir;
2238             
2239             /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
2240                cfg = prj.config;
2241             else
2242             {
2243                for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2244                   if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
2245                      break;
2246                if(!cfg)
2247                {
2248                   for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2249                      if(cfg.targetType == sharedLibrary && cfg.debug)
2250                         break;
2251                }
2252             }*/
2253             if(targetDirExp.dir)
2254             {
2255                char buffer[MAX_LOCATION];
2256 #if defined(__WIN32__)
2257                Array<String> paths = newExePaths;
2258 #else
2259                Array<String> paths = newLibPaths;
2260 #endif
2261                GetSystemPathBuffer(buffer, prj.topNode.path);
2262                PathCat(buffer, targetDirExp.dir);
2263                for(p : paths)
2264                {
2265                   if(!fstrcmp(p, buffer))
2266                   {
2267                      found = true;
2268                      break;
2269                   }
2270                }
2271                if(!found)
2272                   paths.Add(CopyString(buffer));
2273             }
2274             delete targetDirExp;
2275          }
2276       }
2277
2278       for(item : compiler.executableDirs)
2279       {
2280          found = false;
2281          for(p : newExePaths)
2282          {
2283             if(!fstrcmp(p, item))
2284             {
2285                found = true;
2286                break;
2287             }
2288          }
2289          if(!found)
2290             newExePaths.Add(CopySystemPath(item));
2291       }
2292
2293       GetEnvironment("PATH", oldList, sizeof(oldList));
2294 /*#ifdef _DEBUG
2295       printf("Old value of PATH: %s\n", oldList);
2296 #endif*/
2297       count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
2298       for(c = 0; c < count; c++)
2299       {
2300          found = false;
2301          for(p : newExePaths)
2302          {
2303             if(!fstrcmp(p, oldPaths[c]))
2304             {
2305                found = true;
2306                break;
2307             }
2308          }
2309          if(!found)
2310             newExePaths.Add(CopySystemPath(oldPaths[c]));
2311       }
2312       
2313       len = 0;
2314       for(path : newExePaths)
2315          len += strlen(path) + 1;
2316       newList = new char[len + 1];
2317       newList[0] = '\0';
2318       for(path : newExePaths)
2319       {
2320          strcat(newList, path);
2321          strcat(newList, pathListSep);
2322       }
2323       newList[len - 1] = '\0';
2324       SetEnvironment("PATH", newList);
2325 /*#ifdef _DEBUG
2326       printf("New value of PATH: %s\n", newList);
2327 #endif*/
2328       delete newList;
2329
2330       newExePaths.Free();
2331       delete newExePaths;
2332
2333 #if defined(__unix__) || defined(__APPLE__)
2334
2335       for(item : compiler.libraryDirs)
2336       {
2337          if(!libPathExists[item])  // fstrcmp should be used
2338          {
2339             newLibPaths.Add(item);
2340             libPathExists[item] = true;
2341          }
2342       }
2343
2344 #if defined(__APPLE__)
2345       GetEnvironment("DYLD_LIBRARY_PATH", oldList, sizeof(oldList));
2346 #else
2347       GetEnvironment("LD_LIBRARY_PATH", oldList, sizeof(oldList));
2348 #endif
2349 /*#ifdef _DEBUG
2350       printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
2351 #endif*/
2352       count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
2353       for(c = 0; c < count; c++)
2354       {
2355          if(!libPathExists[oldPaths[c]])  // fstrcmp should be used
2356          {
2357             newLibPaths.Add(oldPaths[c]);
2358             libPathExists[oldPaths[c]] = true;
2359          }
2360       }
2361       
2362       len = 0;
2363       for(path : newLibPaths)
2364          len += strlen(path) + 1;
2365       newList = new char[len + 1];
2366       newList[0] = '\0';
2367       for(path : newLibPaths)
2368       {
2369          strcat(newList, path);
2370          strcat(newList, pathListSep);
2371       }
2372       newList[len - 1] = '\0';
2373 #if defined(__APPLE__)
2374       SetEnvironment("DYLD_LIBRARY_PATH", newList);
2375 #else
2376       SetEnvironment("LD_LIBRARY_PATH", newList);
2377 #endif
2378 /*#ifdef _DEBUG
2379       printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
2380 #endif*/
2381       delete newList;
2382
2383       delete newLibPaths;
2384       delete libPathExists;
2385 #endif
2386       delete compiler;
2387    }
2388
2389    void DestroyTemporaryProjectDir()
2390    {
2391       if(tmpPrjDir && tmpPrjDir[0])
2392       {
2393          if(FileExists(tmpPrjDir).isDirectory)
2394             DestroyDir(tmpPrjDir);
2395          property::tmpPrjDir = null;
2396       }
2397    }
2398
2399    IDE()
2400    {
2401       // Graphics Driver Menu
2402       int c;
2403
2404       /*
2405       app.currentSkin.selectionColor = selectionColor;
2406       app.currentSkin.selectionText = selectionText;
2407       */
2408
2409 /*
2410       driverItems = new MenuItem[app.numDrivers];
2411       for(c = 0; c < app.numDrivers; c++)
2412       {
2413          driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
2414          driverItems[c].id = c;
2415          driverItems[c].isRadio = true;         
2416       }
2417 */
2418       driverItems = new MenuItem[2];
2419 #if defined(__unix__)
2420          driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
2421          driverItems[0].id = 0;
2422          driverItems[0].isRadio = true;         
2423 #else
2424          driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
2425          driverItems[0].id = 0;
2426          driverItems[0].isRadio = true;         
2427 #endif
2428          driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
2429          driverItems[1].id = 1;
2430          driverItems[1].isRadio = true;         
2431
2432 /*      skinItems = new MenuItem[app.numSkins];
2433       for(c = 0; c < app.numSkins; c++)
2434       {
2435          skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
2436          skinItems[c].id = c;
2437          skinItems[c].isRadio = true;         
2438       }
2439 */    /*
2440       ideFileDialog.master = this;
2441       ideProjectFileDialog.master = this;*/
2442
2443       //SetDriverAndSkin();
2444       return true;
2445    }
2446
2447    void UpdateRecentMenus()
2448    {
2449       int c;
2450       Menu fileMenu = menu.FindMenu("File");
2451       Menu recentFiles = fileMenu.FindMenu("Recent Files");
2452       Menu recentProjects = fileMenu.FindMenu("Recent Projects");
2453       char itemName[MAX_LOCATION + 4];
2454       MenuItem item;
2455
2456       recentFiles.Clear();
2457       c = 0;
2458
2459       for(recent : ideSettings.recentFiles)
2460       {
2461          sprintf(itemName, "%d %s", 1 + c, recent);
2462          MakeSystemPath(itemName);
2463          recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, null, true);
2464          c++;
2465       }
2466
2467       recentProjects.Clear();
2468       c = 0;
2469       for(recent : ideSettings.recentProjects)
2470       {
2471          sprintf(itemName, "%d %s", 1 + c, recent);
2472          MakeSystemPath(itemName);
2473          recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, null, true);
2474          c++;
2475       }
2476    }
2477
2478    ~IDE()
2479    {
2480       delete driverItems;
2481       delete skinItems;
2482    }
2483 }
2484
2485 void DestroyDir(char * path)
2486 {
2487    RecursiveDeleteFolderFSI fsi { };
2488    fsi.Iterate(path);
2489    delete fsi;
2490 }
2491
2492 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
2493 {
2494    bool preserveRootFolder;
2495
2496    void OutFolder(char * folderPath, bool isRoot)
2497    {
2498       if(!(preserveRootFolder && isRoot))
2499          RemoveDir(folderPath);
2500    }
2501
2502    bool OnFile(char * filePath)
2503    {
2504       DeleteFile(filePath);
2505       return true;
2506    }
2507 }
2508
2509 class IDEApp : GuiApplication
2510 {
2511    //driver = "Win32Console";
2512    // driver = "OpenGL";
2513    // skin = "Aqua";
2514    //skin = "TVision";
2515    bool Init()
2516    {
2517       SetLoggingMode(stdOut, null);
2518       //SetLoggingMode(debug, null);
2519
2520       settingsContainer.Load();
2521 #if defined(__unix__) || defined(__APPLE__)
2522       app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
2523 #else
2524       app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
2525 #endif
2526       ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
2527
2528       SetInIDE(true);
2529
2530       desktop.text = titleECEREIDE;
2531       /*
2532       int c;
2533       for(c = 1; c<app.argc; c++)
2534       {
2535          char fullPath[MAX_LOCATION];
2536          GetWorkingDir(fullPath, MAX_LOCATION);
2537          PathCat(fullPath, app.argv[c]);
2538          ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
2539       }
2540       */
2541       return true;
2542    }
2543 }
2544
2545 IDE ide { };
2546
2547 define app = ((IDEApp)__thisModule);
2548 #ifdef _DEBUG
2549 define titleECEREIDE = "ECERE IDE (Debug)";
2550 #else
2551 define titleECEREIDE = "ECERE IDE";
2552 #endif