2 public import static "ecere"
3 public import static "ec"
9 import "GlobalSettingsDialog"
10 import "NewProjectDialog"
11 import "FindInFilesDialog"
12 import "ActiveCompilerDialog"
19 import "ProjectActiveConfig"
20 import "ProjectConfig"
22 import "NodeProperties"
23 import "ProjectSettings"
35 import "BreakpointsView"
36 import "CallStackView"
47 import "FileSystemIterator"
49 #if defined(__WIN32__)
50 define pathListSep = ";";
52 define pathListSep = ":";
55 define maxPathLen = 65 * MAX_LOCATION;
57 class PathBackup : struct
64 oldPath = new char[maxPathLen];
65 oldLDPath = new char[maxPathLen];
67 GetEnvironment("PATH", oldPath, maxPathLen);
68 #if defined(__APPLE__)
69 GetEnvironment("DYLD_LIBRARY_PATH", oldLDPath, maxPathLen);
71 GetEnvironment("LD_LIBRARY_PATH", oldLDPath, maxPathLen);
77 SetEnvironment("PATH", oldPath);
78 #if defined(__APPLE__)
79 SetEnvironment("DYLD_LIBRARY_PATH", oldLDPath);
81 SetEnvironment("LD_LIBRARY_PATH", oldLDPath);
88 enum OpenCreateIfFails { no, yes, something, whatever };
89 enum OpenMethod { normal, add };
91 static Array<FileFilter> fileFilters
93 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
94 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
95 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
96 { $"Text files (*.txt, *.text, *.nfo, *.info)", "txt, text, nfo, info" },
97 { $"Web files (*.html, *.htm, *.xhtml, *.css, *.php, *.js, *.jsi, *.rb, *.xml)", "html, htm, xhtml, css, php, js, jsi, rb, xml" },
98 { $"Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", "jpg, jpeg, bmp, pcx, png, gif" },
99 { $"3D Studio Model Files (*.3ds)", "3ds" },
100 { $"All files", null }
103 static Array<FileType> fileTypes
105 { $"Based on extension", null },
108 { $"3D Studio Model", "3ds" }
111 static Array<FileFilter> projectFilters
113 { $"Project Files (*.epj)", ProjectExtension }
116 static Array<FileType> projectTypes
118 { $"Project File", ProjectExtension }
121 static Array<FileFilter> findInFilesFileFilters
123 { $"eC Files (*.ec, *.eh)", "ec, eh" },
124 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
125 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
126 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
127 { $"Text files (*.txt)", "txt" },
128 { $"All files", null }
131 FileDialog ideFileDialog
133 type = multiOpen, text = $"Open";
134 types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType), filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter);
137 define openProjectFileDialogTitle = $"Open Project";
138 define addProjectFileDialogTitle = $"Open Additional Project";
139 FileDialog ideProjectFileDialog
142 types = projectTypes.array, sizeTypes = projectTypes.count * sizeof(FileType), filters = projectFilters.array, sizeFilters = projectFilters.count * sizeof(FileFilter);
145 GlobalSettingsDialog globalSettingsDialog
147 ideSettings = ideSettings;
148 settingsContainer = settingsContainer;
150 void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange)
152 switch(globalSettingsChange)
157 for(child = ide.firstChild; child; child = child.next)
159 if(child._class == class(CodeEditor))
161 CodeEditor codeEditor = (CodeEditor) child;
162 codeEditor.editBox.freeCaret = ideSettings.useFreeCaret;
163 // codeEditor.editBox.lineNumbers = ideSettings.showLineNumbers;
164 codeEditor.editBox.caretFollowsScrolling = ideSettings.caretFollowsScrolling;
165 codeEditor.OnPostCreate(); // Update editBox margin size
172 case compilerSettings:
174 ide.UpdateMakefiles();
181 void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
186 lineY = (line - 1) * lineH;
187 if(lineY + lineH > scrollY && lineY + lineH < scrollY + boxH)
189 Bitmap bitmap = resource.bitmap;
191 surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
196 // NOTE: We will move ToolBar and ToolButton classes to libecere...
197 public class ToolBar : public Stacker
199 direction = horizontal;
200 background = activeBorder;
204 anchor = Anchor { left = 0, right = 0 };
205 clientSize = { h = 32 };
211 for(w = firstChild; w; w = w.next)
216 public class ToolButton : public Button
219 size = Size { 24, 24 };
221 bitmapAlignment = center;
222 MenuItem * menuItemPtr;
228 Window master = this.master;
229 if(master && master.parent && !eClass_IsDerived(master._class, class(Stacker)))
231 MenuItem menuItem = this.menuItem;
233 if(menuItem && (bmp = menuItem.bitmap))
239 NotifyClicked = SelectMenuItem;
241 bool Window::SelectMenuItem(Button button, int x, int y, Modifiers mods)
243 ToolButton toolButton = (ToolButton)button;
244 MenuItem menuItem = toolButton.menuItem;
245 return menuItem.NotifySelect(this, menuItem, 0);
249 property MenuItem * menuItemPtr { set { menuItemPtr = value; } }
250 property MenuItem menuItem
254 MenuItem menuItem = *(MenuItem *)((byte *)master + (uint)menuItemPtr);
260 #define IDEItem(x) (&((IDEWorkSpace)0).x)
262 class IDEToolbar : ToolBar
264 ToolButton buttonNewProject { this, toolTip = $"New Project", menuItemPtr = IDEItem(projectNewItem) };
267 class IDEMainFrame : Window
269 background = activeBorder;
270 borderStyle = sizable;
275 minClientSize = { 600, 300 };
276 nativeDecorations = true;
277 borderStyle = sizable;
282 icon = { ":icon.png" };
283 text = titleECEREIDE;
287 anchor = { top = 0, right = 0, bottom = 0 };
290 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
297 isActiveClient = true;
299 direction = vertical;
300 background = activeBorder;
301 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
303 IDEToolbar toolBar { master = ideWorkSpace, parent = stack };
304 IDEWorkSpace ideWorkSpace { master = this, parent = stack };
307 define ide = ideMainFrame.ideWorkSpace;
309 class IDEWorkSpace : Window
311 background = Color { 85, 85, 85 };
314 hasVertScroll = true;
315 hasHorzScroll = true;
317 isActiveClient = true;
318 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
321 MenuItem * driverItems, * skinItems;
322 StatusField pos { width = 150 };
323 StatusField ovr, caps, num;
325 BitmapResource back { ":ecereBack.jpg", window = this };
326 BitmapResource bmpBp { ":codeMarks/breakpoint.png", window = this };
327 BitmapResource bmpBpDisabled { ":codeMarks/breakpointDisabled.png", window = this };
328 BitmapResource bmpBpHalf { ":codeMarks/breakpointHalf.png", window = this };
329 BitmapResource bmpBpHalfDisabled { ":codeMarks/breakpointHalfDisabled.png", window = this };
330 BitmapResource bmpCursor { ":codeMarks/cursor.png", window = this };
331 BitmapResource bmpCursorError { ":codeMarks/cursorError.png", window = this };
332 BitmapResource bmpTopFrame { ":codeMarks/topFrame.png", window = this };
333 BitmapResource bmpTopFrameError { ":codeMarks/topFrameError.png", window = this };
334 BitmapResource bmpTopFrameHalf { ":codeMarks/topFrameHalf.png", window = this };
335 BitmapResource bmpTopFrameHalfError { ":codeMarks/topFrameHalfError.png", window = this };
337 Debugger debugger { };
339 ProjectView projectView;
341 OutputView outputView
345 void OnGotoError(char * line)
350 void OnCodeLocationParseAndGoTo(char * line)
352 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir);
355 bool OnKeyDown(Key key, unichar ch)
360 if(!ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
361 ide.ShowCodeEditor();
364 ide.projectView.stopBuild = true;
368 OutputView::OnKeyDown(key, ch);
375 bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
378 ide.RepositionWindows(false);
382 bool OnClose(bool parentClosing)
386 ide.RepositionWindows(false);
387 return parentClosing;
391 CallStackView callStackView
393 parent = this, font = { panelFont.faceName, panelFont.size };
395 void OnGotoLine(char * line)
398 stackLvl = atoi(line);
399 ide.debugger.GoToStackFrameLine(stackLvl, true);
402 void OnSelectFrame(int lineNumber)
404 ide.debugger.SelectFrame(lineNumber);
407 void OnToggleBreakpoint()
409 Debugger debugger = ide.debugger;
410 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
412 int line = debugger.activeFrame.line;
413 char name[MAX_LOCATION];
415 // TOFIX: Improve on this, don't use only filename, make a function
416 GetLastDirectory(debugger.activeFrame.absoluteFile, name);
417 if(ide && ide.workspace)
419 for(p : ide.workspace.projects)
421 if(p.topNode.Find(name, false))
429 for(p : ide.workspace.projects)
431 if(eString_PathInsideOf(debugger.activeFrame.absoluteFile, p.topNode.path))
439 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line, prj);
442 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
443 if(codeEditor) { codeEditor.Update(null); Activate(); }
448 bool OnKeyDown(Key key, unichar ch)
452 case escape: ide.ShowCodeEditor(); break;
457 bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
460 ide.RepositionWindows(false);
464 bool OnClose(bool parentClosing)
468 ide.RepositionWindows(false);
469 return parentClosing;
472 void OnRedraw(Surface surface)
475 int lineCursor, lineTopFrame, activeThread, hitThread;
476 int lineH, scrollY, boxH;
478 Breakpoint bp = null;
479 Debugger debugger = ide.debugger;
480 Frame activeFrame = debugger.activeFrame;
483 scrollY = editBox.scroll.y;
484 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
486 activeThread = debugger.activeThread;
487 hitThread = debugger.hitThread;
488 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
490 if(activeFrame && activeFrame.absoluteFile)
492 for(i : ide.workspace.breakpoints; i.type == user)
494 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
495 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
496 activeFrame.line == i.line)
505 DrawLineMarginIcon(surface,
506 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
507 lineCursor /*1*/, lineH, scrollY, boxH);
510 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
511 DrawLineMarginIcon(surface,
512 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
513 1, lineH, scrollY, boxH);
515 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
516 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
517 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
519 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
520 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
521 if(editBox.horzScroll && editBox.horzScroll.visible)
523 surface.SetBackground(control);
524 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
529 WatchesView watchesView { parent = this };
530 ThreadsView threadsView
532 parent = this, font = { panelFont.faceName, panelFont.size };
534 bool OnKeyDown(Key key, unichar ch)
538 case escape: ide.ShowCodeEditor(); break;
543 bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
546 ide.RepositionWindows(false);
550 bool OnClose(bool parentClosing)
554 ide.RepositionWindows(false);
555 return parentClosing;
558 void OnSelectThread(int threadId)
561 ide.debugger.SelectThread(threadId);
564 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
567 Debugger debugger = ide.debugger;
568 *activeThread = debugger.activeThread;
569 *hitThread = debugger.hitThread;
570 *signalThread = debugger.signalThread;
575 BreakpointsView breakpointsView { parent = this };
577 ToolBox toolBox { parent = this };
578 Sheet sheet { parent = this };
581 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
583 Menu fileMenu { menu, $"File", f };
586 fileMenu, $"New", n, ctrlN;
587 bool NotifySelect(MenuItem selection, Modifiers mods)
589 Window document = (Window)NewCodeEditor(this, normal, false);
590 document.NotifySaved = DocumentSaved;
594 MenuItem fileOpenItem
596 fileMenu, $"Open...", o, ctrlO;
597 bool NotifySelect(MenuItem selection, Modifiers mods)
599 if(!projectView && ideSettings.ideFileDialogLocation)
600 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
603 if(ideFileDialog.Modal() == ok)
605 bool gotWhatWeWant = false;
607 int numSelections = ideFileDialog.numSelections;
608 char ** multiFilePaths = ideFileDialog.multiFilePaths;
610 for(c = 0; c < numSelections; c++)
612 if(OpenFile(multiFilePaths[c], normal, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal))
613 gotWhatWeWant = true;
616 MessageBox { type = yesNo, master = this, text = $"Error opening file",
617 contents = $"Open a different file?" }.Modal() == no)
619 if(!projectView && gotWhatWeWant)
620 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
630 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
631 MenuDivider { fileMenu };
632 MenuItem fileSaveItem { fileMenu, $"Save", s, ctrlS };
633 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
634 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll };
635 MenuDivider { fileMenu };
638 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
639 bool NotifySelect(MenuItem selection, Modifiers mods)
641 findInFilesDialog.replaceMode = false;
642 findInFilesDialog.Show();
646 MenuItem replaceInFiles
648 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
649 bool NotifySelect(MenuItem selection, Modifiers mods)
651 findInFilesDialog.replaceMode = true;
652 findInFilesDialog.Show();
656 MenuDivider { fileMenu };
657 MenuItem globalSettingsItem
659 fileMenu, $"Global Settings...", g;
660 bool NotifySelect(MenuItem selection, Modifiers mods)
662 globalSettingsDialog.master = this;
663 if(ide.workspace && ide.workspace.compiler)
664 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.compiler;
665 else if(ideSettings.defaultCompiler)
666 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
667 globalSettingsDialog.Modal();
671 MenuDivider { fileMenu };
672 Menu recentFiles { fileMenu, $"Recent Files", r };
673 Menu recentProjects { fileMenu, $"Recent Projects", p };
674 MenuDivider { fileMenu };
677 fileMenu, $"Exit", x, altF4, NotifySelect = MenuFileExit;
679 bool NotifySelect(MenuItem selection, Modifiers mods)
681 ideMainFrame.Destroy(0);
686 bool FileRecentFile(MenuItem selection, Modifiers mods)
689 for(file : ideSettings.recentFiles)
691 if(id == selection.id)
693 OpenFile(file, normal, true, null, no, normal);
701 bool FileRecentProject(MenuItem selection, Modifiers mods)
704 for(file : ideSettings.recentProjects)
706 if(id == selection.id)
708 OpenFile(file, normal, true, null, no, normal);
716 MenuPlacement editMenu { menu, $"Edit", e };
718 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
719 MenuItem projectNewItem
721 projectMenu, $"New...", n, Key { n, true, true };
722 bitmap = { "<:ecere>actions/listAdd.png" };
723 bool NotifySelect(MenuItem selection, Modifiers mods)
725 if(!DontTerminateDebugSession($"New Project"))
726 if(MenuWindowCloseAll(null, 0))
728 NewProjectDialog newProjectDialog;
732 projectView.visible = false;
733 if(!projectView.Destroy(0))
737 newProjectDialog = { master = this };
738 newProjectDialog.Modal();
741 ideSettings.AddRecentProject(projectView.fileName);
742 ide.UpdateRecentMenus();
743 settingsContainer.Save();
749 MenuItem projectOpenItem
751 projectMenu, $"Open...", o, Key { o, true, true };
752 bool NotifySelect(MenuItem selection, Modifiers mods)
754 if(ideSettings.ideProjectFileDialogLocation)
755 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
757 ideProjectFileDialog.text = openProjectFileDialogTitle;
758 if(ideProjectFileDialog.Modal() == ok)
760 OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal);
761 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
766 MenuItem projectQuickItem
768 projectMenu, $"Quick...", q, f7;
769 bool NotifySelect(MenuItem selection, Modifiers mods)
772 QuickProjectDialog{ this }.Modal();
776 MenuItem projectAddItem
778 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
780 bool NotifySelect(MenuItem selection, Modifiers mods)
782 if(ideSettings.ideProjectFileDialogLocation)
783 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
785 ideProjectFileDialog.text = addProjectFileDialogTitle;
788 if(ideProjectFileDialog.Modal() == ok)
790 if(OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add))
792 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
793 contents = $"Add a different project?" }.Modal() == no)
804 MenuItem projectCloseItem
806 projectMenu, $"Close", c, disabled = true;
807 bool NotifySelect(MenuItem selection, Modifiers mods)
811 if(!ide.DontTerminateDebugSession($"Project Close"))
813 if(findInFilesDialog)
814 findInFilesDialog.SearchStop();
815 projectView.visible = false;
816 if(projectView.Destroy(0))
817 MenuWindowCloseAll(null, 0);
819 char workingDir[MAX_LOCATION];
820 GetWorkingDir(workingDir, MAX_LOCATION);
821 findInFilesDialog.currentDirectory = workingDir;
828 MenuDivider { projectMenu };
829 MenuItem activeCompilerItem
831 projectMenu, $"Active Compiler...", g, /*altF5, */disabled = true;
832 bool NotifySelect(MenuItem selection, Modifiers mods)
834 projectView.MenuCompiler(null, mods);
838 MenuItem projectActiveConfigItem
840 projectMenu, $"Active Configuration...", g, altF5, disabled = true;
841 bool NotifySelect(MenuItem selection, Modifiers mods)
843 projectView.MenuConfig(projectView.active ? selection : null, mods);
847 MenuItem projectSettingsItem
849 projectMenu, $"Settings...", s, altF7, disabled = true;
850 bool NotifySelect(MenuItem selection, Modifiers mods)
852 projectView.MenuSettings(projectView.active ? selection : null, mods);
856 MenuDivider { projectMenu };
857 MenuItem projectBrowseFolderItem
859 projectMenu, $"Browse Project Folder", p, disabled = true;
860 bool NotifySelect(MenuItem selection, Modifiers mods)
863 projectView.MenuBrowseFolder(null, mods);
867 MenuDivider { projectMenu };
868 MenuItem projectRunItem
870 projectMenu, $"Run", r, ctrlF5, disabled = true;
871 bool NotifySelect(MenuItem selection, Modifiers mods)
874 projectView.Run(null, mods);
878 MenuItem projectBuildItem
880 projectMenu, $"Build", b, f7, disabled = true;
881 bool NotifySelect(MenuItem selection, Modifiers mods)
884 projectView.ProjectBuild(projectView.active ? selection : null, mods);
888 MenuItem projectLinkItem
890 projectMenu, $"Relink", l, disabled = true;
891 bool NotifySelect(MenuItem selection, Modifiers mods)
894 projectView.ProjectLink(projectView.active ? selection : null, mods);
898 MenuItem projectRebuildItem
900 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
901 bool NotifySelect(MenuItem selection, Modifiers mods)
904 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
908 MenuItem projectCleanItem
910 projectMenu, $"Clean", e, disabled = true;
911 bool NotifySelect(MenuItem selection, Modifiers mods)
916 projectView.ProjectClean(projectView.active ? selection : null, mods);
921 MenuItem projectRegenerateItem
923 projectMenu, $"Regenerate Makefile", m, disabled = true;
924 bool NotifySelect(MenuItem selection, Modifiers mods)
927 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
931 MenuItem projectCompileItem;
932 Menu debugMenu { menu, $"Debug", d };
933 MenuItem debugStartResumeItem
935 debugMenu, $"Start", s, f5, disabled = true;
936 NotifySelect = MenuDebugStart;
938 bool MenuDebugStart(MenuItem selection, Modifiers mods)
942 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
943 if(!projectView.DebugStart())
944 debugStartResumeItem.disabled = false; // same exception
948 bool MenuDebugResume(MenuItem selection, Modifiers mods)
951 projectView.DebugResume();
954 MenuItem debugRestartItem
956 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
957 bool NotifySelect(MenuItem selection, Modifiers mods)
960 projectView.DebugRestart();
964 MenuItem debugBreakItem
966 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
967 bool NotifySelect(MenuItem selection, Modifiers mods)
970 projectView.DebugBreak();
974 MenuItem debugStopItem
976 debugMenu, $"Stop", p, shiftF5, disabled = true;
977 bool NotifySelect(MenuItem selection, Modifiers mods)
980 projectView.DebugStop();
984 MenuDivider { debugMenu };
985 MenuItem debugStepIntoItem
987 debugMenu, $"Step Into", i, f11, disabled = true;
988 bool NotifySelect(MenuItem selection, Modifiers mods)
991 projectView.DebugStepInto();
995 MenuItem debugStepOverItem
997 debugMenu, $"Step Over", v, f10, disabled = true;
998 bool NotifySelect(MenuItem selection, Modifiers mods)
1001 projectView.DebugStepOver(false);
1005 MenuItem debugStepOutItem
1007 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1008 bool NotifySelect(MenuItem selection, Modifiers mods)
1011 projectView.DebugStepOut(false);
1015 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1016 MenuItem debugSkipStepOverItem
1018 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1019 bool NotifySelect(MenuItem selection, Modifiers mods)
1022 projectView.DebugStepOver(true);
1026 MenuItem debugSkipStepOutItem
1028 debugMenu, $"Step Out Skipping Breakpoints", t, Key { f11, ctrl = true, shift = true }, disabled = true;
1029 bool NotifySelect(MenuItem selection, Modifiers mods)
1032 projectView.DebugStepOut(true);
1036 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1037 //MenuDivider { debugMenu };
1038 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1039 MenuPlacement imageMenu { menu, $"Image", i };
1040 Menu viewMenu { menu, $"View", v };
1041 MenuItem viewProjectItem
1043 viewMenu, $"Project View", j, alt0, disabled = true;
1044 bool NotifySelect(MenuItem selection, Modifiers mods)
1048 projectView.visible = true;
1049 projectView.Activate();
1054 MenuPlacement { viewMenu, $"View Designer" };
1055 MenuPlacement { viewMenu, $"View Code" };
1056 MenuPlacement { viewMenu, $"View Properties" };
1057 MenuPlacement { viewMenu, $"View Methods" };
1058 MenuItem viewDesignerItem
1060 viewMenu, $"View Designer", d, f8;
1061 bool NotifySelect(MenuItem selection, Modifiers mods)
1063 Window client = activeClient;
1064 Class dataType = client._class;
1065 if(!strcmp(dataType.name, "Designer"))
1067 client.visible = true;
1071 ((CodeEditor)client).ViewDesigner();
1075 MenuItem viewCodeItem
1077 viewMenu, $"View Code", c, f8;
1078 bool NotifySelect(MenuItem selection, Modifiers mods)
1080 Window client = activeClient;
1081 Class dataType = client._class;
1082 if(!strcmp(dataType.name, "Designer"))
1083 client = ((Designer)client).codeEditor;
1086 // Do this after so the caret isn't moved yet...
1087 client.visible = true;
1091 MenuItem viewPropertiesItem
1093 viewMenu, $"View Properties", p, f4;
1094 bool NotifySelect(MenuItem selection, Modifiers mods)
1096 sheet.visible = true;
1097 sheet.sheetSelected = properties;
1102 MenuItem viewMethodsItem
1104 viewMenu, $"View Methods", m, f4;
1105 bool NotifySelect(MenuItem selection, Modifiers mods)
1107 sheet.visible = true;
1108 sheet.sheetSelected = methods;
1113 MenuItem viewToolBoxItem
1115 viewMenu, $"View Toolbox", x, f12;
1116 bool NotifySelect(MenuItem selection, Modifiers mods)
1118 toolBox.visible = true;
1123 MenuItem viewOutputItem
1125 viewMenu, $"Output", o, alt2;
1126 bool NotifySelect(MenuItem selection, Modifiers mods)
1132 MenuItem viewWatchesItem
1134 viewMenu, $"Watches", w, alt3;
1135 bool NotifySelect(MenuItem selection, Modifiers mods)
1141 MenuItem viewThreadsItem
1143 viewMenu, $"Threads", t, alt4;
1144 bool NotifySelect(MenuItem selection, Modifiers mods)
1150 MenuItem viewBreakpointsItem
1152 viewMenu, $"Breakpoints", b, alt5;
1153 bool NotifySelect(MenuItem selection, Modifiers mods)
1155 breakpointsView.Show();
1159 MenuItem viewCallStackItem
1161 viewMenu, $"Call Stack", s, alt7;
1162 bool NotifySelect(MenuItem selection, Modifiers mods)
1164 callStackView.Show();
1168 MenuItem viewAllDebugViews
1170 viewMenu, $"All Debug Views", a, alt9;
1171 bool NotifySelect(MenuItem selection, Modifiers mods)
1176 callStackView.Show();
1177 breakpointsView.Show();
1181 #ifdef GDB_DEBUG_GUI
1182 MenuDivider { viewMenu };
1183 MenuItem viewGDBItem
1185 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1186 bool NotifySelect(MenuItem selection, Modifiers mods)
1193 MenuDivider { viewMenu };
1194 MenuItem viewColorPicker
1196 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1197 bool NotifySelect(MenuItem selection, Modifiers mods)
1199 ColorPicker colorPicker { master = this, parent = this, stayOnTop = true };
1200 colorPicker.Create();
1204 MenuDivider { viewMenu };
1208 viewMenu, "Full Screen", f, checkable = true;
1210 bool NotifySelect(MenuItem selection, Modifiers mods)
1212 app.fullScreen ^= true;
1214 anchor = { 0, 0, 0, 0 };
1219 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1220 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1221 Menu windowMenu { menu, $"Window", w };
1222 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1223 MenuDivider { windowMenu };
1224 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1225 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1226 MenuDivider { windowMenu };
1227 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1228 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1229 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1230 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1231 MenuDivider { windowMenu };
1232 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1233 Menu helpMenu { menu, $"Help", h };
1236 helpMenu, $"API Reference", r, f1;
1237 bool NotifySelect(MenuItem selection, Modifiers mods)
1239 Execute("documentor");
1243 MenuDivider { helpMenu };
1246 helpMenu, $"About...", a;
1247 bool NotifySelect(MenuItem selection, Modifiers mods)
1249 AboutIDE { master = this }.Modal();
1254 property ToolBox toolBox
1256 get { return toolBox; }
1259 property Sheet sheet
1261 get { return sheet; }
1264 property Project project
1266 get { return projectView ? projectView.project : null; }
1269 property Workspace workspace
1271 get { return projectView ? projectView.workspace : null; }
1274 FindInFilesDialog findInFilesDialog
1276 master = this, parent = this;
1277 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1281 #ifdef GDB_DEBUG_GUI
1284 master = this, parent = this;
1285 anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1287 void OnCommand(char * string)
1290 ide.debugger.SendGDBCommand(string);
1295 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1297 //app.driver = app.drivers[selection.id];
1299 app.driver = selection.id ? "OpenGL" : "X";
1301 app.driver = selection.id ? "OpenGL" : "GDI";
1303 delete ideSettings.displayDriver;
1304 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1306 settingsContainer.Save();
1307 //SetDriverAndSkin();
1311 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1313 app.skin = app.skins[selection.id];
1318 void SetDriverAndSkin()
1321 for(c = 0; c < app.numSkins; c++)
1322 if(!strcmp(app.skins[c], app.skin))
1324 skinItems[c].checked = true;
1327 for(c = 0; c < app.numDrivers; c++)
1328 if(!strcmp(app.drivers[c], app.driver))
1330 driverItems[c].checked = true;
1335 ProjectView CreateProjectView(Workspace workspace, char * fileName)
1337 Project project = workspace.projects.firstIterator.data;
1338 projectView = ProjectView
1341 fileName = fileName;
1343 void NotifyDestroyed(Window window, DialogResult result)
1346 text = titleECEREIDE;
1351 projectView.Create();
1352 RepositionWindows(false);
1354 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1355 projectView.workspace = workspace;
1356 projectView.project = project;
1357 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1361 ide.breakpointsView.LoadFromWorkspace();
1362 ide.watchesView.LoadFromWorkspace();
1364 findInFilesDialog.projectNodeField.userData = projectView;
1367 char fileName[MAX_LOCATION];
1368 strcpy(fileName, project.topNode.path);
1369 PathCat(fileName, project.topNode.name);
1374 bool GetDebugMenusDisabled()
1378 Project project = projectView.project;
1380 if(project.GetTargetType(project.config) == executable)
1387 void RepositionWindows(bool expand)
1392 bool inDebugMode = debugger.isActive;
1393 bool callStackVisible = expand ? false : callStackView.visible;
1394 bool threadsVisible = expand ? false : threadsView.visible;
1395 bool watchesVisible = expand ? false : watchesView.visible;
1396 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1397 bool toolBoxVisible = toolBox.visible;
1398 bool outputVisible = expand ? false : outputView.visible;
1399 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1400 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1402 for(child = firstChild; child; child = child.next)
1404 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1405 child._class == class(Sheet) || child._class == class(ProjectView))
1407 Anchor anchor = child.anchor;
1408 anchor.top = topDistance;
1409 anchor.bottom = bottomDistance;
1410 if(child._class == class(CodeEditor) || child._class == class(Designer))
1412 anchor.right = toolBoxVisible ? 150 : 0;
1414 child.anchor = anchor;
1418 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1419 child._class == class(BreakpointsView))
1420 child.visible = false;
1423 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1428 bool ShowCodeEditor()
1431 activeClient.Activate();
1432 else if(projectView)
1434 projectView.visible = true;
1435 projectView.Activate();
1439 sheet.visible = true;
1445 bool ShouldStopBuild()
1447 return projectView.stopBuild;
1450 void DocumentSaved(Window document, char * fileName)
1452 ideSettings.AddRecentFile(fileName);
1453 ide.UpdateRecentMenus();
1454 settingsContainer.Save();
1457 bool Window::OnFileModified(FileChange fileChange, char * param)
1460 sprintf(temp, $"The document %s was modified by another application.\n"
1461 "Would you like to reload it and lose your changes?", this.fileName);
1462 if(MessageBox { type = yesNo, master = this/*.parent*/,
1463 text = $"Document has been modified", contents = temp }.Modal() == yes)
1465 char * fileName = CopyString(this.fileName);
1466 WindowState state = this.state;
1467 Anchor anchor = this.anchor;
1468 Size size = this.size;
1470 this.modifiedDocument = false;
1472 this = ide.OpenFile(fileName, normal, true, null, no, normal);
1475 this.anchor = anchor;
1477 this.SetState(state, true, 0);
1485 void UpdateMakefiles()
1489 for(prj : workspace.projects)
1491 bool first = prj == workspace.projects.firstIterator.data;
1492 projectView.ProjectUpdateMakefileForAllConfigs(prj, first, first);
1499 bool unavailable = !project;
1501 projectQuickItem.disabled = !unavailable;
1503 projectAddItem.disabled = unavailable;
1505 activeCompilerItem.disabled = unavailable;
1506 projectActiveConfigItem.disabled = unavailable;
1507 projectSettingsItem.disabled = unavailable;
1509 projectBrowseFolderItem.disabled = unavailable;
1511 viewProjectItem.disabled = unavailable;
1517 void AdjustBuildMenus()
1519 bool unavailable = project && projectView.buildInProgress;
1521 projectNewItem.disabled = unavailable;
1522 projectOpenItem.disabled = unavailable;
1524 unavailable = !project || projectView.buildInProgress;
1526 projectCloseItem.disabled = unavailable;
1528 projectRunItem.disabled = unavailable || project.GetTargetType(project.config) != executable;
1529 projectBuildItem.disabled = unavailable;
1530 projectLinkItem.disabled = unavailable;
1531 projectRebuildItem.disabled = unavailable;
1532 projectCleanItem.disabled = unavailable;
1533 projectRegenerateItem.disabled = unavailable;
1534 projectCompileItem.disabled = unavailable;
1537 void AdjustDebugMenus()
1539 bool unavailable = !project || project.GetTargetType(project.config) != executable ||
1540 projectView.buildInProgress == buildingMainProject;
1541 bool active = ide.debugger.isActive;
1542 bool executing = ide.debugger.state == running;
1543 //bool holding = ide.debugger.state == stopped;
1545 debugStartResumeItem.disabled = unavailable || executing;
1547 debugStartResumeItem.text = active ? $"Resume" : $"Start";
1548 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
1550 debugBreakItem.disabled = unavailable || !executing;
1551 debugStopItem.disabled = unavailable || !active;
1552 debugRestartItem.disabled = unavailable || !active;
1554 debugStepIntoItem.disabled = unavailable || executing;
1555 debugStepOverItem.disabled = unavailable || executing;
1556 debugStepOutItem.disabled = unavailable || executing || !active;
1557 debugSkipStepOverItem.disabled = unavailable || executing;
1558 debugSkipStepOutItem.disabled = unavailable || executing || !active;
1560 if((Designer)GetActiveDesigner())
1562 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
1565 codeEditor.debugRunToCursor.disabled = unavailable || executing;
1566 codeEditor.debugSkipRunToCursor.disabled = unavailable || executing;
1571 void ChangeFileDialogsDirectory(char * directory, bool saveSettings)
1573 char tempString[MAX_LOCATION];
1574 strcpy(tempString, directory);
1575 if(saveSettings && !projectView)
1577 ideSettings.ideFileDialogLocation = directory;
1578 settingsContainer.Save();
1581 ideFileDialog.currentDirectory = tempString;
1582 codeEditorFileDialog.currentDirectory = tempString;
1583 codeEditorFormFileDialog.currentDirectory = tempString;
1586 void ChangeProjectFileDialogDirectory(char * directory)
1588 ideSettings.ideProjectFileDialogLocation = directory;
1589 settingsContainer.Save();
1592 Window FindWindow(char * filePath)
1594 Window document = null;
1596 // TOCHECK: Do we need to change slashes here?
1597 for(document = firstChild; document; document = document.next)
1599 char * fileName = document.fileName;
1600 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
1602 document.visible = true;
1603 document.Activate();
1610 bool DontTerminateDebugSession(char * title)
1612 if(debugger.isActive)
1614 if(MessageBox { type = yesNo, master = ide,
1615 contents = $"Do you want to terminate the debugging session in progress?",
1616 text = title }.Modal() == no)
1619 MessageBox msg { type = yesNo, master = ide,
1620 contents = "Do you want to terminate the debugging session in progress?",
1622 if(msg.Modal() == no)
1634 Window OpenFile(char * origFilePath, WindowState state, bool visible, char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod)
1636 char extension[MAX_EXTENSION] = "";
1637 Window document = null;
1638 bool isProject = false;
1639 bool needFileModified = true;
1640 char winFilePath[MAX_LOCATION];
1641 char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
1645 GetExtension(filePath, extension);
1649 strcpy(extension, type);
1651 if(strcmp(extension, ProjectExtension))
1653 for(document = firstChild; document; document = document.next)
1655 char * fileName = document.fileName;
1656 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
1658 document.visible = true;
1659 document.Activate();
1665 if(createIfFails == whatever)
1667 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
1669 if(openMethod == normal)
1671 if(DontTerminateDebugSession($"Open Project"))
1674 if(MenuWindowCloseAll(null, 0))
1678 projectView.visible = false;
1679 projectView.Destroy(0);
1680 // Where did this come from? projectView = null;
1687 Workspace workspace = null;
1689 if(FileExists(filePath))
1691 if(!strcmp(extension, ProjectExtension))
1693 char workspaceFile[MAX_LOCATION];
1694 strcpy(workspaceFile, filePath);
1695 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
1696 workspace = LoadWorkspace(workspaceFile, filePath);
1698 else if(!strcmp(extension, WorkspaceExtension))
1699 workspace = LoadWorkspace(filePath, null);
1702 //project = LoadProject(filePath);
1707 char absolutePath[MAX_LOCATION];
1708 CreateProjectView(workspace, filePath);
1709 document = projectView;
1711 workspace.DropInvalidBreakpoints();
1714 ide.projectView.ShowOutputBuildLog(true);
1716 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
1717 ide.projectView.DisplayCompiler(compiler, false);
1722 char newWorkingDir[MAX_LOCATION];
1723 StripLastDirectory(filePath, newWorkingDir);
1724 ChangeFileDialogsDirectory(newWorkingDir, false);
1727 document.fileName = filePath;
1729 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
1731 // this crashes on starting ide with epj file, solution please?
1732 // app.UpdateDisplay();
1734 workspace.holdTracking = true;
1735 for(ofi : workspace.openedFiles)
1737 if(ofi.state != closed)
1739 Window file = OpenFile(ofi.path, normal, true, null, no, normal);
1742 char fileName[MAX_LOCATION];
1744 GetLastDirectory(ofi.path, fileName);
1745 node = projectView.project.topNode.Find(fileName, true);
1747 node.EnsureVisible();
1751 workspace.holdTracking = false;
1753 workspace.timer.Start();
1755 findInFilesDialog.mode = FindInFilesMode::project;
1756 findInFilesDialog.currentDirectory = ide.project.topNode.path;
1759 char location[MAX_LOCATION];
1760 StripLastDirectory(ide.project.topNode.path, location);
1761 ChangeProjectFileDialogDirectory(location);
1765 if(projectView.debugger)
1766 projectView.debugger.EvaluateWatches();
1773 if(MessageBox { type = yesNo, parent = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
1775 ideProjectFileDialog.text = openProjectFileDialogTitle;
1776 if(ideProjectFileDialog.Modal() == cancel)
1778 filePath = ideProjectFileDialog.filePath;
1779 GetExtension(filePath, extension);
1790 else if(openMethod == add)
1795 char slashFilePath[MAX_LOCATION];
1796 GetSlashPathBuffer(slashFilePath, filePath);
1797 for(p : workspace.projects)
1799 if(!fstrcmp(p.filePath, slashFilePath))
1807 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
1808 contents = $"This project is already present in workspace." }.Modal();
1812 prj = LoadProject(filePath);
1815 workspace.projects.Add(prj);
1817 projectView.AddNode(prj.topNode, null);
1818 workspace.modified = true;
1820 findInFilesDialog.AddProjectItem(prj);
1821 projectView.ProjectUpdateMakefileForAllConfigs(prj, true, true);
1824 char location[MAX_LOCATION];
1825 StripLastDirectory(prj.topNode.path, location);
1826 ChangeProjectFileDialogDirectory(location);
1829 // projectView is associated with the main project and not with the one just added but
1830 return projectView; // just to let the caller know something was opened
1838 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
1839 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
1840 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
1842 if(FileExists(filePath))
1843 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
1844 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
1845 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
1848 MessageBox { type = ok, parent = this, text = filePath, contents = $"File doesn't exist." }.Modal();
1851 else if(!strcmp(extension, "3ds"))
1853 if(FileExists(filePath))
1854 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
1855 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
1856 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
1860 MessageBox { type = ok, parent = this, text = filePath, contents = $"File doesn't exist." }.Modal();
1863 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
1864 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
1865 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
1866 !strcmp(extension, "css") || !strcmp(extension, "php") ||
1867 !strcmp(extension, "js"))
1869 CodeEditor editor { parent = this, state = state, visible = false };
1870 editor.updatingCode = true;
1871 if(editor.LoadFile(filePath))
1874 editor.visible = true;
1878 needFileModified = false;
1882 CodeEditor editor { parent = this, state = state, visible = false };
1883 if(editor.LoadFile(filePath))
1886 editor.visible = true;
1890 needFileModified = false;
1893 if(document && (document._class == class(PictureEdit) ||
1894 document._class == class(ModelView)))
1899 document.fileName = filePath;
1900 if(workspace && !workspace.holdTracking)
1901 workspace.UpdateOpenedFileInfo(filePath, opened);
1905 if(!document && createIfFails != no)
1907 if(createIfFails != yes && !needFileModified &&
1908 MessageBox { type = yesNo, parent = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
1909 createIfFails = yes;
1910 if(createIfFails == yes || createIfFails == whatever)
1912 document = (Window)NewCodeEditor(this, state, true);
1914 document.fileName = filePath;
1920 if(projectView && document._class == class(CodeEditor) && workspace)
1922 int lineNumber, position;
1924 CodeEditor editor = (CodeEditor)document;
1925 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
1926 editor.openedFileInfo.holdTracking = true;
1927 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
1928 position = Max(editor.openedFileInfo.position - 1, 0);
1929 editor.editBox.GoToLineNum(lineNumber);
1930 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
1931 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
1932 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
1933 editor.editBox.scroll = scroll;
1934 editor.openedFileInfo.holdTracking = false;
1937 if(needFileModified)
1938 document.OnFileModified = OnFileModified;
1939 document.NotifySaved = DocumentSaved;
1942 ideSettings.AddRecentProject(document.fileName);
1944 ideSettings.AddRecentFile(document.fileName);
1945 ide.UpdateRecentMenus();
1946 settingsContainer.Save();
1954 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
1955 /*bool Window::GenericDocumentOnClose(bool parentClosing)
1957 if(!parentClosing && ide.workspace)
1958 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
1961 bool ModelView::ModelViewOnClose(bool parentClosing)
1963 if(!parentClosing && ide.workspace)
1964 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
1967 bool PictureEdit::PictureEditOnClose(bool parentClosing)
1969 if(!parentClosing && ide.workspace)
1970 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
1975 void OnUnloadGraphics(Window window)
1977 display.ClearMaterials();
1978 display.ClearTextures();
1979 display.ClearMeshes();
1983 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
1985 caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
1986 num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
1990 bool OnKeyDown(Key key, unichar ch)
1995 projectView.Update(null);
1998 caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2001 num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2007 void GoToError(const char * line)
2010 projectView.GoToError(line);
2013 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
2016 char *colon = strchr(text, ':');
2017 char filePath[MAX_LOCATION];
2018 char completePath[MAX_LOCATION];
2019 int line = 0, col = 0;
2024 char * close = strchr(text, ')');
2028 strncpy(name, &text[4], close - text - 4);
2029 name[close - text - 4] = '\0';
2030 for(p : ide.workspace.projects)
2032 if(!strcmp(p.name, name))
2042 prj = project ? project : (dir ? null : ide.project);
2043 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2045 path = (colon - 1 > path) ? colon - 1 : path;
2046 colon = strstr(colon + 1, ":");
2048 while(isspace(*path)) path++;
2051 strncpy(filePath, path, colon - path);
2052 filePath[colon - path] = '\0';
2053 line = atoi(colon + 1);
2054 colon = strstr(colon + 1, ":");
2056 col = atoi(colon + 1);
2058 else if(path - 1 >= path && *(path - 1) == '\"')
2060 colon = strchr(path, '\"');
2063 strncpy(filePath, path, colon - path);
2064 filePath[colon - path] = '\0';
2069 strcpy(completePath, prj.topNode.path);
2070 else if(dir && dir[0])
2071 strcpy(completePath, dir);
2073 completePath[0] = '\0';
2074 PathCat(completePath, filePath);
2076 if(FileExists(completePath).isFile)
2078 CodeEditor codeEditor = (CodeEditor)OpenFile(completePath, normal, true, "", no, normal);
2079 if(codeEditor && line)
2081 EditBox editBox = codeEditor.editBox;
2082 editBox.GoToLineNum(line - 1);
2083 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2088 void OnRedraw(Surface surface)
2090 Bitmap bitmap = back.bitmap;
2092 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2095 void SheetSelected(SheetType sheetSelected)
2097 if(activeChild == sheet)
2099 if(sheetSelected == methods)
2101 viewPropertiesItem.accelerator = f4;
2102 viewPropertiesItem.parent = viewMenu;
2103 viewMethodsItem.parent = null;
2107 viewMethodsItem.accelerator = f4;
2108 viewMethodsItem.parent = viewMenu;
2109 viewPropertiesItem.parent = null;
2114 viewMethodsItem.parent = viewMenu;
2115 viewPropertiesItem.parent = viewMenu;
2116 if(sheetSelected == methods)
2118 viewMethodsItem.accelerator = f4;
2119 viewPropertiesItem.accelerator = 0;
2123 viewMethodsItem.accelerator = 0;
2124 viewPropertiesItem.accelerator = f4;
2129 void OnActivateClient(Window client, Window previous)
2131 //if(!client || client != previous)
2134 if(!client || client != previous)
2137 dataType = previous._class;
2138 if(previous && !strcmp(dataType.name, "CodeEditor"))
2140 ((CodeEditor)previous).UpdateFormCode();
2142 else if(previous && !strcmp(dataType.name, "Designer"))
2144 ((Designer)previous).codeEditor.UpdateFormCode();
2149 dataType = client._class;
2150 if(client && !strcmp(dataType.name, "CodeEditor"))
2152 CodeEditor codeEditor = (CodeEditor)client;
2153 SetPrivateModule(codeEditor.privateModule);
2154 SetCurrentContext(codeEditor.globalContext);
2155 SetTopContext(codeEditor.globalContext);
2156 SetGlobalContext(codeEditor.globalContext);
2158 SetDefines(&codeEditor.defines);
2159 SetImports(&codeEditor.imports);
2161 SetActiveDesigner(codeEditor.designer);
2163 sheet.codeEditor = codeEditor;
2164 toolBox.codeEditor = codeEditor;
2166 viewDesignerItem.parent = viewMenu;
2167 if(activeChild != codeEditor)
2169 viewCodeItem.parent = viewMenu;
2170 viewDesignerItem.accelerator = 0;
2171 viewCodeItem.accelerator = f8;
2175 viewCodeItem.parent = null;
2176 viewDesignerItem.accelerator = f8;
2179 else if(client && !strcmp(dataType.name, "Designer"))
2181 CodeEditor codeEditor = ((Designer)client).codeEditor;
2184 SetPrivateModule(codeEditor.privateModule);
2185 SetCurrentContext(codeEditor.globalContext);
2186 SetTopContext(codeEditor.globalContext);
2187 SetGlobalContext(codeEditor.globalContext);
2188 SetDefines(&codeEditor.defines);
2189 SetImports(&codeEditor.imports);
2193 SetPrivateModule(null);
2194 SetCurrentContext(null);
2195 SetTopContext(null);
2196 SetGlobalContext(null);
2201 SetActiveDesigner((Designer)client);
2203 sheet.codeEditor = codeEditor;
2204 toolBox.codeEditor = codeEditor;
2206 viewCodeItem.parent = viewMenu;
2207 if(activeChild != client)
2209 viewDesignerItem.parent = viewMenu;
2210 viewDesignerItem.accelerator = f8;
2211 viewCodeItem.accelerator = 0;
2215 viewDesignerItem.parent = null;
2216 viewCodeItem.accelerator = f8;
2222 sheet.codeEditor = null;
2223 toolBox.codeEditor = null;
2224 SetActiveDesigner(null);
2226 viewDesignerItem.parent = null;
2227 viewCodeItem.parent = null;
2230 SheetSelected(sheet.sheetSelected);
2233 projectCompileItem = null;
2238 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
2240 CodeEditor codeEditor = (CodeEditor)client;
2241 EditBox editBox = codeEditor.editBox;
2243 statusBar.AddField(pos);
2245 caps = { width = 40, text = $"CAPS", color = app.GetKeyState(capsState) ? black : Color { 128, 128, 128 } };
2246 statusBar.AddField(caps);
2248 ovr = { width = 30, text = $"OVR", color = editBox.overwrite ? black : Color { 128, 128, 128 } };
2249 statusBar.AddField(ovr);
2251 num = { width = 30, text = $"NUM", color = app.GetKeyState(numState) ? black : Color { 128, 128, 128 } };
2252 statusBar.AddField(num);
2254 //statusBar.text = "Ready";
2256 if(projectView && projectView.project)
2258 ProjectNode node = projectView.GetNodeFromWindow(client, null);
2262 sprintf(name, $"Compile %s", node.name);
2263 projectCompileItem =
2265 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
2267 bool NotifySelect(MenuItem selection, Modifiers mods)
2271 ProjectNode node = projectView.GetNodeFromWindow(activeClient, null);
2273 projectView.Compile(node);
2278 projectMenu.AddDynamic(projectCompileItem, ide, false);
2284 caps = ovr = num = null;
2289 bool OnClose(bool parentClosing)
2291 //return !projectView.buildInProgress;
2292 if(projectView && projectView.buildInProgress)
2294 if(DontTerminateDebugSession($"Close IDE"))
2296 if(findInFilesDialog)
2297 findInFilesDialog.SearchStop();
2300 workspace.timer.Stop();
2303 ideMainFrame.Destroy(0);
2310 for(c = 1; c<app.argc; c++)
2312 char fullPath[MAX_LOCATION];
2313 GetWorkingDir(fullPath, MAX_LOCATION);
2314 PathCat(fullPath, app.argv[c]);
2315 if(FileExists(fullPath))
2316 ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
2323 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
2326 projectView.visible = false;
2327 projectView.Destroy(0);
2330 #ifdef GDB_DEBUG_GUI
2331 gdbDialog.Destroy(0);
2336 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config)
2340 char * oldPaths[128];
2341 String oldList = new char[maxPathLen];
2342 Array<String> newExePaths { };
2343 //Map<String, bool> exePathExists { };
2345 #if defined(__unix__) || defined(__APPLE__)
2346 Array<String> newLibPaths { };
2347 Map<String, bool> libPathExists { };
2352 for(prj : workspace.projects)
2354 DirExpression targetDirExp;
2356 // SKIP FIRST PROJECT...
2357 if(prj == workspace.projects.firstIterator.data) continue;
2359 // NOTE: Right now the additional project config dir will be
2360 // obtained when the debugger is started, so toggling it
2361 // while building will change which library gets used.
2362 // To go with the initial state, e.g. when F5 was pressed,
2363 // we nould need to keep a list of all project's active
2364 // config upon startup.
2365 targetDirExp = prj.GetTargetDir(compiler, prj.config);
2367 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
2371 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2372 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
2376 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2377 if(cfg.targetType == sharedLibrary && cfg.debug)
2381 if(targetDirExp.dir)
2383 char buffer[MAX_LOCATION];
2384 #if defined(__WIN32__)
2385 Array<String> paths = newExePaths;
2387 Array<String> paths = newLibPaths;
2389 GetSystemPathBuffer(buffer, prj.topNode.path);
2390 PathCat(buffer, targetDirExp.dir);
2393 if(!fstrcmp(p, buffer))
2400 paths.Add(CopyString(buffer));
2402 delete targetDirExp;
2406 for(item : compiler.executableDirs)
2409 for(p : newExePaths)
2411 if(!fstrcmp(p, item))
2418 newExePaths.Add(CopySystemPath(item));
2421 GetEnvironment("PATH", oldList, maxPathLen);
2423 printf("Old value of PATH: %s\n", oldList);
2425 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
2426 for(c = 0; c < count; c++)
2429 for(p : newExePaths)
2431 if(!fstrcmp(p, oldPaths[c]))
2438 newExePaths.Add(CopySystemPath(oldPaths[c]));
2442 for(path : newExePaths)
2443 len += strlen(path) + 1;
2444 newList = new char[len + 1];
2446 for(path : newExePaths)
2448 strcat(newList, path);
2449 strcat(newList, pathListSep);
2451 newList[len - 1] = '\0';
2452 SetEnvironment("PATH", newList);
2454 printf("New value of PATH: %s\n", newList);
2461 #if defined(__unix__) || defined(__APPLE__)
2463 for(item : compiler.libraryDirs)
2465 if(!libPathExists[item]) // fstrcmp should be used
2467 newLibPaths.Add(item);
2468 libPathExists[item] = true;
2472 #if defined(__APPLE__)
2473 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
2475 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
2478 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
2480 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
2481 for(c = 0; c < count; c++)
2483 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
2485 newLibPaths.Add(oldPaths[c]);
2486 libPathExists[oldPaths[c]] = true;
2491 for(path : newLibPaths)
2492 len += strlen(path) + 1;
2493 newList = new char[len + 1];
2495 for(path : newLibPaths)
2497 strcat(newList, path);
2498 strcat(newList, pathListSep);
2500 newList[len - 1] = '\0';
2501 #if defined(__APPLE__)
2502 SetEnvironment("DYLD_LIBRARY_PATH", newList);
2504 SetEnvironment("LD_LIBRARY_PATH", newList);
2507 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
2512 delete libPathExists;
2515 if(compiler.distccEnabled && compiler.distccHosts)
2516 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
2521 void DestroyTemporaryProjectDir()
2523 if(tmpPrjDir && tmpPrjDir[0])
2525 if(FileExists(tmpPrjDir).isDirectory)
2526 DestroyDir(tmpPrjDir);
2527 property::tmpPrjDir = null;
2533 // Graphics Driver Menu
2537 app.currentSkin.selectionColor = selectionColor;
2538 app.currentSkin.selectionText = selectionText;
2542 driverItems = new MenuItem[app.numDrivers];
2543 for(c = 0; c < app.numDrivers; c++)
2545 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
2546 driverItems[c].id = c;
2547 driverItems[c].isRadio = true;
2550 driverItems = new MenuItem[2];
2551 #if defined(__unix__)
2552 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
2553 driverItems[0].id = 0;
2554 driverItems[0].isRadio = true;
2556 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
2557 driverItems[0].id = 0;
2558 driverItems[0].isRadio = true;
2560 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
2561 driverItems[1].id = 1;
2562 driverItems[1].isRadio = true;
2564 /* skinItems = new MenuItem[app.numSkins];
2565 for(c = 0; c < app.numSkins; c++)
2567 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
2568 skinItems[c].id = c;
2569 skinItems[c].isRadio = true;
2572 ideFileDialog.master = this;
2573 ideProjectFileDialog.master = this;
2575 //SetDriverAndSkin();
2579 void UpdateRecentMenus()
2582 Menu fileMenu = menu.FindMenu($"File");
2583 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
2584 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
2585 char itemName[MAX_LOCATION + 4];
2588 recentFiles.Clear();
2591 for(recent : ideSettings.recentFiles)
2593 sprintf(itemName, "%d %s", 1 + c, recent);
2594 MakeSystemPath(itemName);
2595 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
2599 recentProjects.Clear();
2601 for(recent : ideSettings.recentProjects)
2603 sprintf(itemName, "%d %s", 1 + c, recent);
2604 MakeSystemPath(itemName);
2605 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
2618 void DestroyDir(char * path)
2620 RecursiveDeleteFolderFSI fsi { };
2625 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
2627 bool preserveRootFolder;
2629 void OutFolder(char * folderPath, bool isRoot)
2631 if(!(preserveRootFolder && isRoot))
2632 RemoveDir(folderPath);
2635 bool OnFile(char * filePath)
2637 DeleteFile(filePath);
2642 class IDEApp : GuiApplication
2644 //driver = "Win32Console";
2645 // driver = "OpenGL";
2650 SetLoggingMode(stdOut, null);
2651 //SetLoggingMode(debug, null);
2653 settingsContainer.Load();
2654 #if defined(__unix__) || defined(__APPLE__)
2655 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
2657 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
2659 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
2663 desktop.text = titleECEREIDE;
2666 for(c = 1; c<app.argc; c++)
2668 char fullPath[MAX_LOCATION];
2669 GetWorkingDir(fullPath, MAX_LOCATION);
2670 PathCat(fullPath, app.argv[c]);
2671 ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
2678 IDEMainFrame ideMainFrame { };
2680 define app = ((IDEApp)__thisModule);
2682 define titleECEREIDE = $"ECERE IDE (Debug)";
2684 define titleECEREIDE = $"ECERE IDE";