2 public import static "ecere"
3 public import static "ec"
9 import "GlobalSettingsDialog"
10 import "NewProjectDialog"
11 import "FindInFilesDialog"
18 import "ProjectConfig"
20 import "NodeProperties"
21 import "ProjectSettings"
33 import "BreakpointsView"
34 import "CallStackView"
45 import "FileSystemIterator"
47 #if defined(__WIN32__)
48 define pathListSep = ";";
50 define pathListSep = ":";
53 define maxPathLen = 65 * MAX_LOCATION;
55 class PathBackup : struct
62 oldPath = new char[maxPathLen];
63 oldLDPath = new char[maxPathLen];
65 GetEnvironment("PATH", oldPath, maxPathLen);
66 #if defined(__APPLE__)
67 GetEnvironment("DYLD_LIBRARY_PATH", oldLDPath, maxPathLen);
69 GetEnvironment("LD_LIBRARY_PATH", oldLDPath, maxPathLen);
75 SetEnvironment("PATH", oldPath);
76 #if defined(__APPLE__)
77 SetEnvironment("DYLD_LIBRARY_PATH", oldLDPath);
79 SetEnvironment("LD_LIBRARY_PATH", oldLDPath);
86 enum OpenCreateIfFails { no, yes, something, whatever };
87 enum OpenMethod { normal, add };
89 static Array<FileFilter> fileFilters
91 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
92 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
93 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
94 { $"Text files (*.txt, *.text, *.nfo, *.info)", "txt, text, nfo, info" },
95 { $"Web files (*.html, *.htm, *.xhtml, *.css, *.php, *.js, *.jsi, *.rb, *.xml)", "html, htm, xhtml, css, php, js, jsi, rb, xml" },
96 { $"Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", "jpg, jpeg, bmp, pcx, png, gif" },
97 { $"3D Studio Model Files (*.3ds)", "3ds" },
98 { $"All files", null }
101 static Array<FileType> fileTypes
103 { $"Based on extension", null },
106 { $"3D Studio Model", "3ds" }
109 static Array<FileFilter> projectFilters
111 { $"Project Files (*.epj)", ProjectExtension }
114 static Array<FileType> projectTypes
116 { $"Project File", ProjectExtension }
119 static Array<FileFilter> findInFilesFileFilters
121 { $"eC Files (*.ec, *.eh)", "ec, eh" },
122 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
123 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
124 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
125 { $"Text files (*.txt)", "txt" },
126 { $"All files", null }
129 FileDialog ideFileDialog
131 type = multiOpen, text = $"Open";
132 types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType), filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter);
135 define openProjectFileDialogTitle = $"Open Project";
136 define addProjectFileDialogTitle = $"Open Additional Project";
137 FileDialog ideProjectFileDialog
140 types = projectTypes.array, sizeTypes = projectTypes.count * sizeof(FileType), filters = projectFilters.array, sizeFilters = projectFilters.count * sizeof(FileFilter);
143 GlobalSettingsDialog globalSettingsDialog
145 ideSettings = ideSettings;
146 settingsContainer = settingsContainer;
148 void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange)
150 switch(globalSettingsChange)
155 for(child = ide.firstChild; child; child = child.next)
157 if(child._class == class(CodeEditor))
159 CodeEditor codeEditor = (CodeEditor) child;
160 codeEditor.editBox.freeCaret = ideSettings.useFreeCaret;
161 // codeEditor.editBox.lineNumbers = ideSettings.showLineNumbers;
162 codeEditor.editBox.caretFollowsScrolling = ideSettings.caretFollowsScrolling;
163 codeEditor.OnPostCreate(); // Update editBox margin size
170 case compilerSettings:
172 ide.UpdateCompilerConfigs();
179 void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
184 lineY = (line - 1) * lineH;
185 if(lineY + lineH > scrollY && lineY + lineH < scrollY + boxH)
187 Bitmap bitmap = resource.bitmap;
189 surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
194 #define IDEItem(x) (&((IDEWorkSpace)0).x)
196 class IDEToolbar : ToolBar
200 ToolButton buttonNewFile { this, toolTip = $"New file", menuItemPtr = IDEItem(fileNewItem) };
202 ToolButton buttonOpenFile { this, toolTip = $"Open file", menuItemPtr = IDEItem(fileOpenItem) };
204 // ToolButton buttonCloseFile { this, toolTip = $"Close file", menuItemPtr = IDEItem(fileCloseItem) };
206 ToolButton buttonSaveFile { this, toolTip = $"Save file", menuItemPtr = IDEItem(fileSaveItem) };
208 ToolButton buttonSaveAllFile { this, toolTip = $"Save all", menuItemPtr = IDEItem(fileSaveAllItem) };
210 ToolSeparator separator1 { this };
219 // ToolSeparator separator2 { this };
221 /* Project options */
223 ToolButton buttonNewProject { this, toolTip = $"New project", menuItemPtr = IDEItem(projectNewItem) };
225 ToolButton buttonOpenProject { this, toolTip = $"Open project", menuItemPtr = IDEItem(projectOpenItem) };
226 // Add project to workspace
227 ToolButton buttonAddProject { this, toolTip = $"Add project to workspace", menuItemPtr = IDEItem(projectAddItem), disabled = true; };
229 // ToolButton buttonCloseProject { this, toolTip = $"Close project", menuItemPtr = IDEItem(projectCloseItem), disabled = true; };
231 ToolSeparator separator3 { this };
233 /* Build/Execution options */
235 ToolButton buttonBuild { this, toolTip = $"Build project", menuItemPtr = IDEItem(projectBuildItem), disabled = true; };
237 ToolButton buttonReLink { this, toolTip = $"Relink project", menuItemPtr = IDEItem(projectLinkItem), disabled = true; };
239 ToolButton buttonRebuild { this, toolTip = $"Rebuild project", menuItemPtr = IDEItem(projectRebuildItem), disabled = true; };
241 ToolButton buttonClean { this, toolTip = $"Clean project", menuItemPtr = IDEItem(projectCleanItem), disabled = true; };
243 // ToolButton buttonRealClean { this, toolTip = $"Real clean project", menuItemPtr = IDEItem(projectRealCleanItem), disabled = true; };
244 // Regenerate Makefile
245 ToolButton buttonRegenerateMakefile { this, toolTip = $"Regenerate Makefile", menuItemPtr = IDEItem(projectRegenerateItem), disabled = true; };
246 // Compile actual file
248 ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem), disabled = true; };
250 ToolSeparator separator4 { this };
254 ToolButton buttonDebugStartResume { this, toolTip = $"Start", menuItemPtr = IDEItem(debugStartResumeItem), disabled = true; };
256 ToolButton buttonDebugRestart { this, toolTip = $"Restart", menuItemPtr = IDEItem(debugRestartItem), disabled = true; };
258 ToolButton buttonDebugPause { this, toolTip = $"Break", menuItemPtr = IDEItem(debugBreakItem), disabled = true; };
260 ToolButton buttonDebugStop { this, toolTip = $"Stop", menuItemPtr = IDEItem(debugStopItem), disabled = true; };
262 //ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem) };
264 ToolButton buttonDebugStepInto { this, toolTip = $"Step Into", menuItemPtr = IDEItem(debugStepIntoItem), disabled = true; };
266 ToolButton buttonDebugStepOver { this, toolTip = $"Step Over", menuItemPtr = IDEItem(debugStepOverItem), disabled = true; };
268 ToolButton buttonDebugStepOut { this, toolTip = $"Step Out", menuItemPtr = IDEItem(debugStepOutItem), disabled = true; };
270 ToolButton buttonDebugSkipStepOver { this, toolTip = $"Step Over Skipping Breakpoints", menuItemPtr = IDEItem(debugSkipStepOverItem), disabled = true; };
272 ToolSeparator separator5 { this };
274 Window spacer5 { this, size = { 4 } };
278 this, toolTip = $"Active Configuration(s)", size = { 160 };
279 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
283 for(prj : ide.workspace.projects)
285 for(cfg : prj.configurations)
287 if(cfg.name && !strcmp(cfg.name, row.string))
294 ide.UpdateToolBarActiveConfigs(true);
295 ide.projectView.Update(null);
301 Window spacer6 { this, size = { 4 } };
303 DropBox activeCompiler
305 this, toolTip = $"Active Compiler", size = { 160 };
306 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
308 if(row && strcmp(row.string, ide.workspace.compiler))
310 bool silent = ide.projectView.buildInProgress == none ? false : true;
311 CompilerConfig compiler = ideSettings.GetCompilerConfig(row.string);
312 ide.workspace.compiler = row.string;
313 ide.projectView.ShowOutputBuildLog(!silent);
315 ide.projectView.DisplayCompiler(compiler, false);
316 for(prj : ide.workspace.projects)
317 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
319 ide.workspace.Save();
325 Window spacer7 { this, size = { 4 } };
329 class IDEMainFrame : Window
331 background = formColor;
332 borderStyle = sizable;
336 minClientSize = { 600, 300 };
338 icon = { ":icon.png" };
339 text = titleECEREIDE;
343 anchor = { top = 0, right = 0, bottom = 0 };
346 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
353 isActiveClient = true;
355 direction = vertical;
356 background = formColor;
357 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
365 ((IDEWorkSpace)master).toolBar = null;
368 IDEWorkSpace ideWorkSpace { stack, this, toolBar = toolBar };
371 define ide = ideMainFrame.ideWorkSpace;
373 class IDEWorkSpace : Window
375 background = Color { 85, 85, 85 };
378 hasVertScroll = true;
379 hasHorzScroll = true;
381 isActiveClient = true;
382 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
386 MenuItem * driverItems, * skinItems;
387 StatusField pos { width = 150 };
388 StatusField ovr, caps, num;
390 BitmapResource back { ":ecereBack.jpg", window = this };
391 BitmapResource bmpBp { ":codeMarks/breakpoint.png", window = this };
392 BitmapResource bmpBpDisabled { ":codeMarks/breakpointDisabled.png", window = this };
393 BitmapResource bmpBpHalf { ":codeMarks/breakpointHalf.png", window = this };
394 BitmapResource bmpBpHalfDisabled { ":codeMarks/breakpointHalfDisabled.png", window = this };
395 BitmapResource bmpCursor { ":codeMarks/cursor.png", window = this };
396 BitmapResource bmpCursorError { ":codeMarks/cursorError.png", window = this };
397 BitmapResource bmpTopFrame { ":codeMarks/topFrame.png", window = this };
398 BitmapResource bmpTopFrameError { ":codeMarks/topFrameError.png", window = this };
399 BitmapResource bmpTopFrameHalf { ":codeMarks/topFrameHalf.png", window = this };
400 BitmapResource bmpTopFrameHalfError { ":codeMarks/topFrameHalfError.png", window = this };
402 Debugger debugger { };
404 ProjectView projectView;
406 OutputView outputView
410 void OnGotoError(char * line)
415 void OnCodeLocationParseAndGoTo(char * line)
417 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir);
420 bool OnKeyDown(Key key, unichar ch)
425 if(!ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
426 ide.ShowCodeEditor();
430 OutputView::OnKeyDown(key, ch);
437 bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
440 ide.RepositionWindows(false);
444 bool OnClose(bool parentClosing)
448 ide.RepositionWindows(false);
449 return parentClosing;
453 CallStackView callStackView
455 parent = this, font = { panelFont.faceName, panelFont.size };
457 void OnGotoLine(char * line)
460 stackLvl = atoi(line);
461 ide.debugger.GoToStackFrameLine(stackLvl, true);
464 void OnSelectFrame(int lineNumber)
466 ide.debugger.SelectFrame(lineNumber);
469 void OnToggleBreakpoint()
471 Debugger debugger = ide.debugger;
472 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
474 int line = debugger.activeFrame.line;
475 char name[MAX_LOCATION];
477 // TOFIX: Improve on this, don't use only filename, make a function
478 GetLastDirectory(debugger.activeFrame.absoluteFile, name);
479 if(ide && ide.workspace)
481 for(p : ide.workspace.projects)
483 if(p.topNode.Find(name, false))
491 for(p : ide.workspace.projects)
493 if(IsPathInsideOf(debugger.activeFrame.absoluteFile, p.topNode.path))
501 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line, prj);
504 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
505 if(codeEditor) { codeEditor.Update(null); Activate(); }
510 bool OnKeyDown(Key key, unichar ch)
514 case escape: ide.ShowCodeEditor(); break;
519 bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
522 ide.RepositionWindows(false);
526 bool OnClose(bool parentClosing)
530 ide.RepositionWindows(false);
531 return parentClosing;
534 void OnRedraw(Surface surface)
536 Debugger debugger = ide.debugger;
537 Frame activeFrame = debugger.activeFrame;
541 int lineCursor, lineTopFrame, activeThread, hitThread;
542 int lineH, scrollY, boxH;
544 Breakpoint bp = null;
547 scrollY = editBox.scroll.y;
548 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
549 activeThread = debugger.activeThread;
550 hitThread = debugger.hitThread;
551 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
553 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
554 if(activeFrame.absoluteFile)
556 for(i : ide.workspace.breakpoints; i.type == user)
558 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
559 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
560 activeFrame.line == i.line)
568 DrawLineMarginIcon(surface,
569 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
570 lineCursor /*1*/, lineH, scrollY, boxH);
572 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
573 DrawLineMarginIcon(surface,
574 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
575 1, lineH, scrollY, boxH);
577 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
578 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
579 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
581 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
582 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
584 if(editBox.horzScroll && editBox.horzScroll.visible)
586 surface.SetBackground(control);
587 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
592 WatchesView watchesView { parent = this };
593 ThreadsView threadsView
595 parent = this, font = { panelFont.faceName, panelFont.size };
597 bool OnKeyDown(Key key, unichar ch)
601 case escape: ide.ShowCodeEditor(); break;
606 bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
609 ide.RepositionWindows(false);
613 bool OnClose(bool parentClosing)
617 ide.RepositionWindows(false);
618 return parentClosing;
621 void OnSelectThread(int threadId)
624 ide.debugger.SelectThread(threadId);
627 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
630 Debugger debugger = ide.debugger;
631 *activeThread = debugger.activeThread;
632 *hitThread = debugger.hitThread;
633 *signalThread = debugger.signalThread;
638 BreakpointsView breakpointsView { parent = this };
640 ToolBox toolBox { parent = this };
641 Sheet sheet { parent = this };
644 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
646 Menu fileMenu { menu, $"File", f, hasMargin = true };
649 fileMenu, $"New", n, ctrlN;
650 bitmap = { ":actions/docNew.png" };
651 bool NotifySelect(MenuItem selection, Modifiers mods)
653 Window document = (Window)NewCodeEditor(this, normal, false);
654 document.NotifySaved = DocumentSaved;
658 MenuItem fileOpenItem
660 fileMenu, $"Open...", o, ctrlO;
661 bitmap = { ":actions/docOpen.png" };
662 bool NotifySelect(MenuItem selection, Modifiers mods)
664 if(!projectView && ideSettings.ideFileDialogLocation)
665 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
668 if(ideFileDialog.Modal() == ok)
670 bool gotWhatWeWant = false;
672 int numSelections = ideFileDialog.numSelections;
673 char ** multiFilePaths = ideFileDialog.multiFilePaths;
675 for(c = 0; c < numSelections; c++)
677 if(OpenFile(multiFilePaths[c], normal, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal))
678 gotWhatWeWant = true;
681 MessageBox { type = yesNo, master = this, text = $"Error opening file",
682 contents = $"Open a different file?" }.Modal() == no)
684 if(!projectView && gotWhatWeWant)
685 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
695 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
696 MenuDivider { fileMenu };
697 MenuItem fileSaveItem
699 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
701 // For the toolbar button; clients can still override that for the menu item
702 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
704 Window w = activeClient;
706 w.MenuFileSave(null, 0);
710 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
711 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
712 MenuDivider { fileMenu };
715 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
716 bool NotifySelect(MenuItem selection, Modifiers mods)
718 findInFilesDialog.replaceMode = false;
719 findInFilesDialog.Show();
723 MenuItem replaceInFiles
725 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
726 bool NotifySelect(MenuItem selection, Modifiers mods)
728 findInFilesDialog.replaceMode = true;
729 findInFilesDialog.Show();
733 MenuDivider { fileMenu };
734 MenuItem globalSettingsItem
736 fileMenu, $"Global Settings...", g;
737 bool NotifySelect(MenuItem selection, Modifiers mods)
739 globalSettingsDialog.master = this;
740 if(ide.workspace && ide.workspace.compiler)
741 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.compiler;
742 else if(ideSettings.defaultCompiler)
743 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
744 globalSettingsDialog.Modal();
748 MenuDivider { fileMenu };
749 Menu recentFiles { fileMenu, $"Recent Files", r };
750 Menu recentProjects { fileMenu, $"Recent Projects", p };
751 MenuDivider { fileMenu };
754 fileMenu, $"Exit", x, altF4, NotifySelect = MenuFileExit;
756 bool NotifySelect(MenuItem selection, Modifiers mods)
758 ideMainFrame.Destroy(0);
763 bool FileRecentFile(MenuItem selection, Modifiers mods)
766 for(file : ideSettings.recentFiles)
768 if(id == selection.id)
770 if(mods.ctrl) // Menu::OnLeftButtonUp -> modifiers.ctrl == true, modifiers == 18
771 // Menu::MenuItemSelection -> key.ctrl == false, key.modifiers.ctrl == false, key == 18
772 // removing the (Key) cast from Modifiers when calling MenuItemSelection in OnLeftButtonUp didn't help
774 // it never gets in here!!!
775 char * command = PrintString("ide ", file);
780 OpenFile(file, normal, true, null, no, normal);
788 bool FileRecentProject(MenuItem selection, Modifiers mods)
791 for(file : ideSettings.recentProjects)
793 if(id == selection.id)
795 if(mods.ctrl) // Menu::OnLeftButtonUp -> modifiers.ctrl == true, modifiers == 18
796 // Menu::MenuItemSelection -> key.ctrl == false, key.modifiers.ctrl == false, key == 18
797 // removing the (Key) cast from Modifiers when calling MenuItemSelection in OnLeftButtonUp didn't help
799 // it never gets in here!!!
800 char * command = PrintString("ide ", file);
805 OpenFile(file, normal, true, null, no, normal);
813 MenuPlacement editMenu { menu, $"Edit", e };
815 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
816 MenuItem projectNewItem
818 projectMenu, $"New...", n, Key { n, true, true };
819 bitmap = { ":actions/projNew.png" };
820 bool NotifySelect(MenuItem selection, Modifiers mods)
822 if(!DontTerminateDebugSession($"New Project"))
823 if(MenuWindowCloseAll(null, 0))
825 NewProjectDialog newProjectDialog;
829 projectView.visible = false;
830 if(!projectView.Destroy(0))
834 newProjectDialog = { master = this };
835 newProjectDialog.Modal();
838 ideSettings.AddRecentProject(projectView.fileName);
839 ide.UpdateRecentMenus();
840 settingsContainer.Save();
846 MenuItem projectOpenItem
848 projectMenu, $"Open...", o, Key { o, true, true };
849 bitmap = { ":actions/projOpen.png" };
850 bool NotifySelect(MenuItem selection, Modifiers mods)
852 if(ideSettings.ideProjectFileDialogLocation)
853 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
855 ideProjectFileDialog.text = openProjectFileDialogTitle;
856 if(ideProjectFileDialog.Modal() == ok)
858 OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal);
859 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
864 MenuItem projectQuickItem
866 projectMenu, $"Quick...", q, f7, disabled = true;
867 bool NotifySelect(MenuItem selection, Modifiers mods)
870 QuickProjectDialog { this }.Modal();
874 MenuItem projectAddItem
876 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
877 bitmap = { ":actions/projAdd.png" };
879 bool NotifySelect(MenuItem selection, Modifiers mods)
881 if(ideSettings.ideProjectFileDialogLocation)
882 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
884 ideProjectFileDialog.text = addProjectFileDialogTitle;
887 if(ideProjectFileDialog.Modal() == ok)
889 if(OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add))
891 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
892 contents = $"Add a different project?" }.Modal() == no)
903 MenuItem projectCloseItem
905 projectMenu, $"Close", c, disabled = true;
906 bool NotifySelect(MenuItem selection, Modifiers mods)
910 if(!ide.DontTerminateDebugSession($"Project Close"))
912 if(findInFilesDialog)
913 findInFilesDialog.SearchStop();
914 projectView.visible = false;
915 if(projectView.Destroy(0))
916 MenuWindowCloseAll(null, 0);
918 char workingDir[MAX_LOCATION];
919 GetWorkingDir(workingDir, MAX_LOCATION);
920 findInFilesDialog.currentDirectory = workingDir;
921 ideMainFrame.text = titleECEREIDE;
928 MenuDivider { projectMenu };
929 MenuItem projectSettingsItem
931 projectMenu, $"Settings...", s, altF7, disabled = true;
932 bool NotifySelect(MenuItem selection, Modifiers mods)
934 projectView.MenuSettings(projectView.active ? selection : null, mods);
938 MenuDivider { projectMenu };
939 MenuItem projectBrowseFolderItem
941 projectMenu, $"Browse Project Folder", p, disabled = true;
942 bool NotifySelect(MenuItem selection, Modifiers mods)
945 projectView.MenuBrowseFolder(null, mods);
949 MenuDivider { projectMenu };
950 MenuItem projectRunItem
952 projectMenu, $"Run", r, ctrlF5, disabled = true;
953 bitmap = { ":actions/run.png" };
954 bool NotifySelect(MenuItem selection, Modifiers mods)
957 projectView.Run(null, mods);
961 MenuItem projectBuildItem
963 projectMenu, $"Build", b, f7, disabled = true;
964 bitmap = { ":actions/build.png" };
965 bool NotifySelect(MenuItem selection, Modifiers mods)
969 if(projectView.buildInProgress == none)
970 projectView.ProjectBuild(projectView.active ? selection : null, mods);
972 projectView.stopBuild = true;
977 MenuItem projectLinkItem
979 projectMenu, $"Relink", l, disabled = true;
980 bitmap = { ":actions/relink.png" };
981 bool NotifySelect(MenuItem selection, Modifiers mods)
984 projectView.ProjectLink(projectView.active ? selection : null, mods);
988 MenuItem projectRebuildItem
990 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
991 bitmap = { ":actions/rebuild.png" };
992 bool NotifySelect(MenuItem selection, Modifiers mods)
995 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
999 MenuItem projectCleanItem
1001 projectMenu, $"Clean", e, disabled = true;
1002 bitmap = { ":actions/clean.png" };
1003 bool NotifySelect(MenuItem selection, Modifiers mods)
1008 projectView.ProjectClean(projectView.active ? selection : null, mods);
1013 MenuItem projectRealCleanItem
1015 projectMenu, $"Real Clean", disabled = true;
1016 bitmap = { ":actions/clean.png" };
1017 bool NotifySelect(MenuItem selection, Modifiers mods)
1022 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1027 MenuItem projectRegenerateItem
1029 projectMenu, $"Regenerate Makefile", m, disabled = true;
1030 bitmap = { ":actions/regMakefile.png" };
1031 bool NotifySelect(MenuItem selection, Modifiers mods)
1034 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1038 MenuItem projectCompileItem;
1039 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1040 MenuItem debugStartResumeItem
1042 debugMenu, $"Start", s, f5, disabled = true;
1043 bitmap = { ":actions/debug.png" };
1044 NotifySelect = MenuDebugStart;
1046 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1050 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1051 if(!projectView.DebugStart())
1052 debugStartResumeItem.disabled = false; // same exception
1056 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1059 projectView.DebugResume();
1062 MenuItem debugRestartItem
1064 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1065 bitmap = { ":actions/restart.png" };
1066 bool NotifySelect(MenuItem selection, Modifiers mods)
1069 projectView.DebugRestart();
1073 MenuItem debugBreakItem
1075 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1076 bitmap = { ":actions/pause.png" };
1077 bool NotifySelect(MenuItem selection, Modifiers mods)
1079 if(projectView && projectView.buildInProgress != none)
1082 projectView.DebugBreak();
1086 MenuItem debugStopItem
1088 debugMenu, $"Stop", p, shiftF5, disabled = true;
1089 bitmap = { ":actions/stopDebug.png" };
1090 bool NotifySelect(MenuItem selection, Modifiers mods)
1093 projectView.DebugStop();
1097 MenuDivider { debugMenu };
1098 MenuItem debugStepIntoItem
1100 debugMenu, $"Step Into", i, f11, disabled = true;
1101 bitmap = { ":actions/stepInto.png" };
1102 bool NotifySelect(MenuItem selection, Modifiers mods)
1105 projectView.DebugStepInto();
1109 MenuItem debugStepOverItem
1111 debugMenu, $"Step Over", v, f10, disabled = true;
1112 bitmap = { ":actions/stepOver.png" };
1113 bool NotifySelect(MenuItem selection, Modifiers mods)
1116 projectView.DebugStepOver(false);
1120 MenuItem debugStepOutItem
1122 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1123 bitmap = { ":actions/stepOut.png" };
1124 bool NotifySelect(MenuItem selection, Modifiers mods)
1127 projectView.DebugStepOut(false);
1131 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1132 MenuItem debugSkipStepOverItem
1134 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1135 bool NotifySelect(MenuItem selection, Modifiers mods)
1138 projectView.DebugStepOver(true);
1142 MenuItem debugSkipStepOutItem
1144 debugMenu, $"Step Out Skipping Breakpoints", t, Key { f11, ctrl = true, shift = true }, disabled = true;
1145 bitmap = { ":actions/skipBreaks.png" };
1146 bool NotifySelect(MenuItem selection, Modifiers mods)
1149 projectView.DebugStepOut(true);
1153 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1154 //MenuDivider { debugMenu };
1155 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1156 MenuPlacement imageMenu { menu, $"Image", i };
1157 Menu viewMenu { menu, $"View", v };
1158 MenuItem viewProjectItem
1160 viewMenu, $"Project View", j, alt0, disabled = true;
1161 bool NotifySelect(MenuItem selection, Modifiers mods)
1165 projectView.visible = true;
1166 projectView.Activate();
1171 MenuPlacement { viewMenu, $"View Designer" };
1172 MenuPlacement { viewMenu, $"View Code" };
1173 MenuPlacement { viewMenu, $"View Properties" };
1174 MenuPlacement { viewMenu, $"View Methods" };
1175 MenuItem viewDesignerItem
1177 viewMenu, $"View Designer", d, f8;
1178 bool NotifySelect(MenuItem selection, Modifiers mods)
1180 Window client = activeClient;
1181 Class dataType = client._class;
1182 if(!strcmp(dataType.name, "Designer"))
1184 client.visible = true;
1188 ((CodeEditor)client).ViewDesigner();
1192 MenuItem viewCodeItem
1194 viewMenu, $"View Code", c, f8;
1195 bool NotifySelect(MenuItem selection, Modifiers mods)
1197 Window client = activeClient;
1198 Class dataType = client._class;
1199 if(!strcmp(dataType.name, "Designer"))
1200 client = ((Designer)client).codeEditor;
1203 // Do this after so the caret isn't moved yet...
1204 client.visible = true;
1208 MenuItem viewPropertiesItem
1210 viewMenu, $"View Properties", p, f4;
1211 bool NotifySelect(MenuItem selection, Modifiers mods)
1213 sheet.visible = true;
1214 sheet.sheetSelected = properties;
1219 MenuItem viewMethodsItem
1221 viewMenu, $"View Methods", m, f4;
1222 bool NotifySelect(MenuItem selection, Modifiers mods)
1224 sheet.visible = true;
1225 sheet.sheetSelected = methods;
1230 MenuItem viewToolBoxItem
1232 viewMenu, $"View Toolbox", x, f12;
1233 bool NotifySelect(MenuItem selection, Modifiers mods)
1235 toolBox.visible = true;
1240 MenuItem viewOutputItem
1242 viewMenu, $"Output", o, alt2;
1243 bool NotifySelect(MenuItem selection, Modifiers mods)
1249 MenuItem viewWatchesItem
1251 viewMenu, $"Watches", w, alt3;
1252 bool NotifySelect(MenuItem selection, Modifiers mods)
1258 MenuItem viewThreadsItem
1260 viewMenu, $"Threads", t, alt4;
1261 bool NotifySelect(MenuItem selection, Modifiers mods)
1267 MenuItem viewBreakpointsItem
1269 viewMenu, $"Breakpoints", b, alt5;
1270 bool NotifySelect(MenuItem selection, Modifiers mods)
1272 breakpointsView.Show();
1276 MenuItem viewCallStackItem
1278 viewMenu, $"Call Stack", s, alt7;
1279 bool NotifySelect(MenuItem selection, Modifiers mods)
1281 callStackView.Show();
1285 MenuItem viewAllDebugViews
1287 viewMenu, $"All Debug Views", a, alt9;
1288 bool NotifySelect(MenuItem selection, Modifiers mods)
1293 callStackView.Show();
1294 breakpointsView.Show();
1298 #ifdef GDB_DEBUG_GUI
1299 MenuDivider { viewMenu };
1300 MenuItem viewGDBItem
1302 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1303 bool NotifySelect(MenuItem selection, Modifiers mods)
1310 MenuDivider { viewMenu };
1311 MenuItem viewColorPicker
1313 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1314 bool NotifySelect(MenuItem selection, Modifiers mods)
1316 ColorPicker colorPicker { master = this, parent = this, stayOnTop = true };
1317 colorPicker.Create();
1321 MenuDivider { viewMenu };
1325 viewMenu, "Full Screen", f, checkable = true;
1327 bool NotifySelect(MenuItem selection, Modifiers mods)
1329 app.fullScreen ^= true;
1331 anchor = { 0, 0, 0, 0 };
1336 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1337 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1338 Menu windowMenu { menu, $"Window", w };
1339 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1340 MenuDivider { windowMenu };
1341 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1342 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1343 MenuDivider { windowMenu };
1344 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1345 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1346 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1347 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1348 MenuDivider { windowMenu };
1349 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1350 Menu helpMenu { menu, $"Help", h };
1353 helpMenu, $"API Reference", r, f1;
1354 bool NotifySelect(MenuItem selection, Modifiers mods)
1356 Execute("documentor");
1360 MenuDivider { helpMenu };
1363 helpMenu, $"About...", a;
1364 bool NotifySelect(MenuItem selection, Modifiers mods)
1366 AboutIDE { master = this }.Modal();
1371 property ToolBox toolBox
1373 get { return toolBox; }
1376 property Sheet sheet
1378 get { return sheet; }
1381 property Project project
1383 get { return projectView ? projectView.project : null; }
1386 property Workspace workspace
1388 get { return projectView ? projectView.workspace : null; }
1391 FindInFilesDialog findInFilesDialog
1394 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1398 #ifdef GDB_DEBUG_GUI
1401 master = this, parent = this;
1402 anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1404 void OnCommand(char * string)
1407 ide.debugger.SendGDBCommand(string);
1412 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1414 //app.driver = app.drivers[selection.id];
1415 #if defined(__unix__) || defined(__APPLE__)
1416 app.driver = selection.id ? "OpenGL" : "X";
1418 app.driver = selection.id ? "OpenGL" : "GDI";
1420 delete ideSettings.displayDriver;
1421 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1423 settingsContainer.Save();
1424 //SetDriverAndSkin();
1428 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1430 app.skin = app.skins[selection.id];
1435 void SetDriverAndSkin()
1438 for(c = 0; c < app.numSkins; c++)
1439 if(!strcmp(app.skins[c], app.skin))
1441 skinItems[c].checked = true;
1444 for(c = 0; c < app.numDrivers; c++)
1445 if(!strcmp(app.drivers[c], app.driver))
1447 driverItems[c].checked = true;
1452 ProjectView CreateProjectView(Workspace workspace, char * fileName)
1454 Project project = workspace.projects.firstIterator.data;
1455 projectView = ProjectView
1458 fileName = fileName;
1460 void NotifyDestroyed(Window window, DialogResult result)
1463 text = titleECEREIDE;
1468 projectView.Create();
1469 RepositionWindows(false);
1471 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1472 projectView.workspace = workspace;
1473 projectView.project = project;
1474 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1478 ide.breakpointsView.LoadFromWorkspace();
1479 ide.watchesView.LoadFromWorkspace();
1481 findInFilesDialog.projectNodeField.userData = projectView;
1484 char fileName[MAX_LOCATION];
1485 strcpy(fileName, project.topNode.path);
1486 PathCat(fileName, project.topNode.name);
1491 bool GetDebugMenusDisabled()
1495 Project project = projectView.project;
1497 if(project.GetTargetType(project.config) == executable)
1504 void RepositionWindows(bool expand)
1509 bool inDebugMode = debugger.isActive;
1510 bool callStackVisible = expand ? false : callStackView.visible;
1511 bool threadsVisible = expand ? false : threadsView.visible;
1512 bool watchesVisible = expand ? false : watchesView.visible;
1513 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1514 bool toolBoxVisible = toolBox.visible;
1515 bool outputVisible = expand ? false : outputView.visible;
1516 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1517 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1519 for(child = firstChild; child; child = child.next)
1521 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1522 child._class == class(Sheet) || child._class == class(ProjectView))
1524 Anchor anchor = child.anchor;
1525 anchor.top = topDistance;
1526 anchor.bottom = bottomDistance;
1527 if(child._class == class(CodeEditor) || child._class == class(Designer))
1529 anchor.right = toolBoxVisible ? 150 : 0;
1531 child.anchor = anchor;
1535 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1536 child._class == class(BreakpointsView))
1537 child.visible = false;
1540 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1545 bool ShowCodeEditor()
1548 activeClient.Activate();
1549 else if(projectView)
1551 projectView.visible = true;
1552 projectView.Activate();
1556 sheet.visible = true;
1562 bool ShouldStopBuild()
1564 return projectView.stopBuild;
1567 void DocumentSaved(Window document, char * fileName)
1569 ideSettings.AddRecentFile(fileName);
1570 ide.UpdateRecentMenus();
1571 ide.AdjustFileMenus();
1572 settingsContainer.Save();
1575 bool Window::OnFileModified(FileChange fileChange, char * param)
1578 sprintf(temp, $"The document %s was modified by another application.\n"
1579 "Would you like to reload it and lose your changes?", this.fileName);
1580 if(MessageBox { type = yesNo, master = this/*.parent*/,
1581 text = $"Document has been modified", contents = temp }.Modal() == yes)
1583 char * fileName = CopyString(this.fileName);
1584 WindowState state = this.state;
1585 Anchor anchor = this.anchor;
1586 Size size = this.size;
1588 this.modifiedDocument = false;
1590 this = ide.OpenFile(fileName, normal, true, null, no, normal);
1593 this.anchor = anchor;
1595 this.SetState(state, true, 0);
1603 void UpdateMakefiles()
1607 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1608 for(prj : workspace.projects)
1609 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1614 void UpdateCompilerConfigs()
1616 UpdateToolBarActiveCompilers();
1619 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1620 projectView.ShowOutputBuildLog(true);
1621 projectView.DisplayCompiler(compiler, false);
1622 for(prj : workspace.projects)
1623 projectView.ProjectPrepareCompiler(prj, compiler, false);
1628 void UpdateToolBarActiveCompilers()
1630 toolBar.activeCompiler.Clear();
1631 for(compiler : ideSettings.compilerConfigs)
1633 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1634 if(workspace && workspace.compiler && !strcmp(compiler.name, workspace.compiler))
1635 toolBar.activeCompiler.currentRow = row;
1637 if(!toolBar.activeCompiler.currentRow)
1638 toolBar.activeCompiler.currentRow = toolBar.activeCompiler.firstRow;
1639 toolBar.activeCompiler.disabled = workspace == null;
1642 void UpdateToolBarActiveConfigs(bool selectionOnly)
1644 bool commonSelected = false;
1645 DataRow row = toolBar.activeConfig.currentRow;
1647 row = toolBar.activeConfig.FindRow(1);
1650 toolBar.activeConfig.Clear();
1651 row = toolBar.activeConfig.AddString("(Mixed)");
1656 char * configName = null;
1659 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1660 for(prj : workspace.projects)
1662 for(cfg : prj.configurations)
1665 configs[cfg.name] = 1;
1670 toolBar.activeConfig.AddString(&name);
1674 if(projectView && projectView.project)
1676 for(prj : workspace.projects)
1678 if(prj.config && prj.config.name)
1680 configName = prj.config.name;
1686 commonSelected = true;
1687 for(prj : workspace.projects)
1689 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1691 commonSelected = false;
1699 commonSelected = false;
1700 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1702 if(!strcmp(row.string, configName))
1704 toolBar.activeConfig.currentRow = row;
1705 commonSelected = true;
1712 toolBar.activeConfig.Sort(null, 0);
1714 toolBar.activeConfig.currentRow = row;
1715 toolBar.activeConfig.disabled = workspace == null;
1720 bool unavailable = !project;
1722 projectAddItem.disabled = unavailable;
1723 toolBar.buttonAddProject.disabled = unavailable;
1725 projectSettingsItem.disabled = unavailable;
1727 projectBrowseFolderItem.disabled = unavailable;
1729 viewProjectItem.disabled = unavailable;
1736 property bool hasOpenedCodeEditors
1741 for(w = firstChild; w; w = w.next)
1742 if(w._class == class(CodeEditor) &&
1743 w.isDocument && !w.closing && w.visible && w.created &&
1744 w.fileName && w.fileName[0])
1750 void AdjustFileMenus()
1752 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
1754 projectQuickItem.disabled = unavailable;
1757 void AdjustBuildMenus()
1759 bool unavailable = project && projectView.buildInProgress;
1761 projectNewItem.disabled = unavailable;
1762 toolBar.buttonNewProject.disabled = unavailable;
1763 projectOpenItem.disabled = unavailable;
1764 toolBar.buttonOpenProject.disabled = unavailable;
1766 unavailable = !project || projectView.buildInProgress;
1768 projectCloseItem.disabled = unavailable;
1769 // toolBar.buttonCloseProject.disabled = unavailable;
1771 projectRunItem.disabled = unavailable || project.GetTargetType(project.config) != executable;
1772 toolBar.buttonRun.disabled = unavailable || project.GetTargetType(project.config) != executable;
1774 projectBuildItem.disabled = false;
1775 projectBuildItem.text = unavailable ? $"Stop Build" : $"Build";
1776 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
1778 projectLinkItem.disabled = unavailable;
1779 toolBar.buttonReLink.disabled = unavailable;
1780 projectRebuildItem.disabled = unavailable;
1781 toolBar.buttonRebuild.disabled = unavailable;
1782 projectCleanItem.disabled = unavailable;
1783 toolBar.buttonClean.disabled = unavailable;
1784 projectRealCleanItem.disabled = unavailable;
1785 // toolBar.buttonRealClean.disabled = unavailable;
1786 projectRegenerateItem.disabled = unavailable;
1787 toolBar.buttonRegenerateMakefile.disabled = unavailable;
1788 projectCompileItem.disabled = unavailable;
1790 AdjustPopupBuildMenus();
1793 void AdjustPopupBuildMenus()
1795 bool unavailable = !project || projectView.buildInProgress;
1797 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
1800 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
1803 menu.disabled = false;
1804 menu.text = unavailable ? $"Stop Build" : $"Build";
1805 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
1808 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0); if(menu) menu.disabled = unavailable;
1809 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0); if(menu) menu.disabled = unavailable;
1810 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0); if(menu) menu.disabled = unavailable;
1811 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0); if(menu) menu.disabled = unavailable;
1812 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
1813 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0); if(menu) menu.disabled = unavailable;
1814 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0); if(menu) menu.disabled = unavailable;
1815 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0); if(menu) menu.disabled = unavailable;
1816 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0); if(menu) menu.disabled = unavailable;
1817 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0); if(menu) menu.disabled = unavailable;
1818 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
1819 projectView.popupMenu.Update(null);
1823 void AdjustDebugMenus()
1825 bool unavailable = !project || project.GetTargetType(project.config) != executable ||
1826 projectView.buildInProgress == buildingMainProject;
1827 bool active = ide.debugger.isActive;
1828 bool executing = ide.debugger.state == running;
1829 //bool holding = ide.debugger.state == stopped;
1831 debugStartResumeItem.disabled = unavailable || executing;
1832 debugStartResumeItem.text = active ? $"Resume" : $"Start";
1833 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
1836 toolBar.buttonDebugStartResume.disabled = unavailable || executing;
1837 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
1840 debugBreakItem.disabled = unavailable || !executing;
1841 debugStopItem.disabled = unavailable || !active;
1842 debugRestartItem.disabled = unavailable || !active;
1845 toolBar.buttonDebugPause.disabled = unavailable || !executing;
1846 toolBar.buttonDebugStop.disabled = unavailable || !active;
1847 toolBar.buttonDebugRestart.disabled = unavailable || !active;
1850 debugStepIntoItem.disabled = unavailable || executing;
1851 debugStepOverItem.disabled = unavailable || executing;
1852 debugStepOutItem.disabled = unavailable || executing || !active;
1853 debugSkipStepOverItem.disabled = unavailable || executing;
1854 debugSkipStepOutItem.disabled = unavailable || executing || !active;
1857 toolBar.buttonDebugStepInto.disabled = unavailable || executing;
1858 toolBar.buttonDebugStepOver.disabled = unavailable || executing;
1859 toolBar.buttonDebugStepOut.disabled = unavailable || executing || !active;
1860 toolBar.buttonDebugSkipStepOver.disabled = unavailable || executing;
1861 // toolBar.buttonDebugSkipStepOutItem.disabled = unavailable || executing;
1863 if((Designer)GetActiveDesigner())
1865 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
1868 codeEditor.debugRunToCursor.disabled = unavailable || executing;
1869 codeEditor.debugSkipRunToCursor.disabled = unavailable || executing;
1874 void ChangeFileDialogsDirectory(char * directory, bool saveSettings)
1876 char tempString[MAX_LOCATION];
1877 strcpy(tempString, directory);
1878 if(saveSettings && !projectView)
1880 ideSettings.ideFileDialogLocation = directory;
1881 settingsContainer.Save();
1884 ideFileDialog.currentDirectory = tempString;
1885 codeEditorFileDialog.currentDirectory = tempString;
1886 codeEditorFormFileDialog.currentDirectory = tempString;
1889 void ChangeProjectFileDialogDirectory(char * directory)
1891 ideSettings.ideProjectFileDialogLocation = directory;
1892 settingsContainer.Save();
1895 Window FindWindow(char * filePath)
1897 Window document = null;
1899 // TOCHECK: Do we need to change slashes here?
1900 for(document = firstChild; document; document = document.next)
1902 char * fileName = document.fileName;
1903 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
1905 document.visible = true;
1906 document.Activate();
1913 bool DontTerminateDebugSession(char * title)
1915 if(debugger.isActive)
1917 if(MessageBox { type = yesNo, master = ide,
1918 contents = $"Do you want to terminate the debugging session in progress?",
1919 text = title }.Modal() == no)
1922 MessageBox msg { type = yesNo, master = ide,
1923 contents = "Do you want to terminate the debugging session in progress?",
1925 if(msg.Modal() == no)
1937 Window OpenFile(char * origFilePath, WindowState state, bool visible, char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod)
1939 char extension[MAX_EXTENSION] = "";
1940 Window document = null;
1941 bool isProject = false;
1942 bool needFileModified = true;
1943 char winFilePath[MAX_LOCATION];
1944 char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
1948 GetExtension(filePath, extension);
1952 strcpy(extension, type);
1954 if(strcmp(extension, ProjectExtension))
1956 for(document = firstChild; document; document = document.next)
1958 char * fileName = document.fileName;
1959 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
1961 document.visible = true;
1963 document.Activate();
1969 if(createIfFails == whatever)
1971 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
1973 needFileModified = false;
1974 if(openMethod == normal)
1976 if(DontTerminateDebugSession($"Open Project"))
1979 if(MenuWindowCloseAll(null, 0))
1983 projectView.visible = false;
1984 projectView.Destroy(0);
1985 // Where did this come from? projectView = null;
1992 Workspace workspace = null;
1994 if(FileExists(filePath))
1996 if(!strcmp(extension, ProjectExtension))
1998 char workspaceFile[MAX_LOCATION];
1999 strcpy(workspaceFile, filePath);
2000 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2001 workspace = LoadWorkspace(workspaceFile, filePath);
2003 else if(!strcmp(extension, WorkspaceExtension))
2004 workspace = LoadWorkspace(filePath, null);
2007 //project = LoadProject(filePath, null);
2012 char absolutePath[MAX_LOCATION];
2013 CreateProjectView(workspace, filePath);
2014 document = projectView;
2016 workspace.DropInvalidBreakpoints();
2019 ide.projectView.ShowOutputBuildLog(true);
2021 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2022 ide.projectView.DisplayCompiler(compiler, false);
2025 UpdateCompilerConfigs();
2028 char newWorkingDir[MAX_LOCATION];
2029 StripLastDirectory(filePath, newWorkingDir);
2030 ChangeFileDialogsDirectory(newWorkingDir, false);
2033 document.fileName = filePath;
2035 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2037 // this crashes on starting ide with epj file, solution please?
2038 // app.UpdateDisplay();
2040 workspace.holdTracking = true;
2041 for(ofi : workspace.openedFiles)
2043 if(ofi.state != closed)
2045 Window file = OpenFile(ofi.path, normal, true, null, no, normal);
2048 char fileName[MAX_LOCATION];
2050 GetLastDirectory(ofi.path, fileName);
2051 node = projectView.project.topNode.Find(fileName, true);
2053 node.EnsureVisible();
2057 workspace.holdTracking = false;
2059 workspace.timer.Start();
2061 findInFilesDialog.mode = FindInFilesMode::project;
2062 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2065 char location[MAX_LOCATION];
2066 StripLastDirectory(ide.project.topNode.path, location);
2067 ChangeProjectFileDialogDirectory(location);
2071 if(projectView.debugger)
2072 projectView.debugger.EvaluateWatches();
2079 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2081 ideProjectFileDialog.text = openProjectFileDialogTitle;
2082 if(ideProjectFileDialog.Modal() == cancel)
2084 filePath = ideProjectFileDialog.filePath;
2085 GetExtension(filePath, extension);
2096 else if(openMethod == add)
2101 char slashFilePath[MAX_LOCATION];
2102 GetSlashPathBuffer(slashFilePath, filePath);
2103 for(p : workspace.projects)
2105 if(!fstrcmp(p.filePath, slashFilePath))
2113 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2114 contents = $"This project is already present in workspace." }.Modal();
2118 prj = LoadProject(filePath, null);
2121 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2122 prj.StartMonitoring();
2123 workspace.projects.Add(prj);
2125 projectView.AddNode(prj.topNode, null);
2126 workspace.modified = true;
2128 findInFilesDialog.AddProjectItem(prj);
2129 projectView.ShowOutputBuildLog(true);
2130 projectView.DisplayCompiler(compiler, false);
2131 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2135 char location[MAX_LOCATION];
2136 StripLastDirectory(prj.topNode.path, location);
2137 ChangeProjectFileDialogDirectory(location);
2140 // projectView is associated with the main project and not with the one just added but
2141 return projectView; // just to let the caller know something was opened
2149 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2150 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2151 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2153 if(FileExists(filePath))
2154 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2155 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2156 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2159 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2162 else if(!strcmp(extension, "3ds"))
2164 if(FileExists(filePath))
2165 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2166 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2167 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2171 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2174 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2175 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2176 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2177 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2178 !strcmp(extension, "js"))
2180 CodeEditor editor { parent = this, state = state, visible = false };
2181 editor.updatingCode = true;
2182 if(editor.LoadFile(filePath))
2185 editor.visible = true;
2189 needFileModified = false;
2193 CodeEditor editor { parent = this, state = state, visible = false };
2194 if(editor.LoadFile(filePath))
2197 editor.visible = true;
2201 needFileModified = false;
2204 if(document && (document._class == class(PictureEdit) ||
2205 document._class == class(ModelView)))
2210 document.fileName = filePath;
2211 if(workspace && !workspace.holdTracking)
2212 workspace.UpdateOpenedFileInfo(filePath, opened);
2216 if(!document && createIfFails != no)
2218 if(createIfFails != yes && !needFileModified &&
2219 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2220 createIfFails = yes;
2221 if(createIfFails == yes || createIfFails == whatever)
2223 document = (Window)NewCodeEditor(this, state, true);
2225 document.fileName = filePath;
2231 if(projectView && document._class == class(CodeEditor) && workspace)
2233 int lineNumber, position;
2235 CodeEditor editor = (CodeEditor)document;
2236 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2237 editor.openedFileInfo.holdTracking = true;
2238 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2239 position = Max(editor.openedFileInfo.position - 1, 0);
2240 editor.editBox.GoToLineNum(lineNumber);
2241 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2242 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2243 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2244 editor.editBox.scroll = scroll;
2245 editor.openedFileInfo.holdTracking = false;
2248 if(needFileModified)
2249 document.OnFileModified = OnFileModified;
2250 document.NotifySaved = DocumentSaved;
2253 ideSettings.AddRecentProject(document.fileName);
2255 ideSettings.AddRecentFile(document.fileName);
2256 ide.UpdateRecentMenus();
2257 ide.AdjustFileMenus();
2258 settingsContainer.Save();
2266 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2267 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2269 if(!parentClosing && ide.workspace)
2270 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2273 bool ModelView::ModelViewOnClose(bool parentClosing)
2275 if(!parentClosing && ide.workspace)
2276 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2279 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2281 if(!parentClosing && ide.workspace)
2282 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2287 void OnUnloadGraphics(Window window)
2289 display.ClearMaterials();
2290 display.ClearTextures();
2291 display.ClearMeshes();
2295 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2297 caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2298 num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2302 bool OnKeyDown(Key key, unichar ch)
2307 projectView.Update(null);
2310 caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2313 num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2319 void GoToError(const char * line)
2322 projectView.GoToError(line);
2325 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
2328 char *colon = strchr(text, ':');
2329 char filePath[MAX_LOCATION];
2330 char completePath[MAX_LOCATION];
2331 int line = 0, col = 0;
2333 FileAttribs fileAttribs;
2335 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2337 path = (colon - 1 > path) ? colon - 1 : path;
2338 colon = strstr(colon + 1, ":");
2340 while(isspace(*path)) path++;
2343 char * close = strchr(path, ')');
2347 strncpy(name, path+1, close - path - 1);
2348 name[close - path - 1] = '\0';
2349 for(p : ide.workspace.projects)
2351 if(!strcmp(p.name, name))
2361 prj = project ? project : (dir ? null : ide.project);
2364 strncpy(filePath, path, colon - path);
2365 filePath[colon - path] = '\0';
2366 line = atoi(colon + 1);
2367 colon = strstr(colon + 1, ":");
2369 col = atoi(colon + 1);
2371 else if(path - 1 >= text && *(path - 1) == '\"')
2373 colon = strchr(path, '\"');
2376 strncpy(filePath, path, colon - path);
2377 filePath[colon - path] = '\0';
2380 else if(path && !colon)
2382 strcpy(filePath, path);
2386 strcpy(completePath, prj.topNode.path);
2387 else if(dir && dir[0])
2388 strcpy(completePath, dir);
2390 completePath[0] = '\0';
2391 PathCat(completePath, filePath);
2393 fileAttribs = FileExists(completePath);
2394 if(fileAttribs.isFile)
2396 CodeEditor codeEditor = (CodeEditor)OpenFile(completePath, normal, true, "", no, normal);
2397 if(codeEditor && line)
2399 EditBox editBox = codeEditor.editBox;
2400 editBox.GoToLineNum(line - 1);
2401 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2404 else if(fileAttribs.isDirectory)
2405 ShellOpen(completePath);
2408 void OnRedraw(Surface surface)
2410 Bitmap bitmap = back.bitmap;
2412 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2415 void SheetSelected(SheetType sheetSelected)
2417 if(activeChild == sheet)
2419 if(sheetSelected == methods)
2421 viewPropertiesItem.accelerator = f4;
2422 viewPropertiesItem.parent = viewMenu;
2423 viewMethodsItem.parent = null;
2427 viewMethodsItem.accelerator = f4;
2428 viewMethodsItem.parent = viewMenu;
2429 viewPropertiesItem.parent = null;
2434 viewMethodsItem.parent = viewMenu;
2435 viewPropertiesItem.parent = viewMenu;
2436 if(sheetSelected == methods)
2438 viewMethodsItem.accelerator = f4;
2439 viewPropertiesItem.accelerator = 0;
2443 viewMethodsItem.accelerator = 0;
2444 viewPropertiesItem.accelerator = f4;
2449 void OnActivateClient(Window client, Window previous)
2451 //if(!client || client != previous)
2454 if(!client || client != previous)
2457 dataType = previous._class;
2458 if(previous && !strcmp(dataType.name, "CodeEditor"))
2460 ((CodeEditor)previous).UpdateFormCode();
2462 else if(previous && !strcmp(dataType.name, "Designer"))
2464 ((Designer)previous).codeEditor.UpdateFormCode();
2469 dataType = client._class;
2470 if(client && !strcmp(dataType.name, "CodeEditor"))
2472 CodeEditor codeEditor = (CodeEditor)client;
2473 SetPrivateModule(codeEditor.privateModule);
2474 SetCurrentContext(codeEditor.globalContext);
2475 SetTopContext(codeEditor.globalContext);
2476 SetGlobalContext(codeEditor.globalContext);
2478 SetDefines(&codeEditor.defines);
2479 SetImports(&codeEditor.imports);
2481 SetActiveDesigner(codeEditor.designer);
2483 sheet.codeEditor = codeEditor;
2484 toolBox.codeEditor = codeEditor;
2486 viewDesignerItem.parent = viewMenu;
2487 if(activeChild != codeEditor)
2489 viewCodeItem.parent = viewMenu;
2490 viewDesignerItem.accelerator = 0;
2491 viewCodeItem.accelerator = f8;
2495 viewCodeItem.parent = null;
2496 viewDesignerItem.accelerator = f8;
2499 else if(client && !strcmp(dataType.name, "Designer"))
2501 CodeEditor codeEditor = ((Designer)client).codeEditor;
2504 SetPrivateModule(codeEditor.privateModule);
2505 SetCurrentContext(codeEditor.globalContext);
2506 SetTopContext(codeEditor.globalContext);
2507 SetGlobalContext(codeEditor.globalContext);
2508 SetDefines(&codeEditor.defines);
2509 SetImports(&codeEditor.imports);
2513 SetPrivateModule(null);
2514 SetCurrentContext(null);
2515 SetTopContext(null);
2516 SetGlobalContext(null);
2521 SetActiveDesigner((Designer)client);
2523 sheet.codeEditor = codeEditor;
2524 toolBox.codeEditor = codeEditor;
2526 viewCodeItem.parent = viewMenu;
2527 if(activeChild != client)
2529 viewDesignerItem.parent = viewMenu;
2530 viewDesignerItem.accelerator = f8;
2531 viewCodeItem.accelerator = 0;
2535 viewDesignerItem.parent = null;
2536 viewCodeItem.accelerator = f8;
2542 sheet.codeEditor = null;
2543 toolBox.codeEditor = null;
2544 SetActiveDesigner(null);
2546 viewDesignerItem.parent = null;
2547 viewCodeItem.parent = null;
2550 SheetSelected(sheet.sheetSelected);
2553 projectCompileItem = null;
2558 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
2560 CodeEditor codeEditor = (CodeEditor)client;
2561 EditBox editBox = codeEditor.editBox;
2563 statusBar.AddField(pos);
2565 caps = { width = 40, text = $"CAPS", color = app.GetKeyState(capsState) ? black : Color { 128, 128, 128 } };
2566 statusBar.AddField(caps);
2568 ovr = { width = 30, text = $"OVR", color = editBox.overwrite ? black : Color { 128, 128, 128 } };
2569 statusBar.AddField(ovr);
2571 num = { width = 30, text = $"NUM", color = app.GetKeyState(numState) ? black : Color { 128, 128, 128 } };
2572 statusBar.AddField(num);
2574 //statusBar.text = "Ready";
2576 if(projectView && projectView.project)
2578 bool isCObject = false;
2579 ProjectNode node = projectView.GetNodeFromWindow(client, null, false);
2580 if(!node && (node = projectView.GetNodeFromWindow(client, null, true)))
2584 char nodeName[MAX_FILENAME];
2585 char name[MAX_FILENAME+96];
2587 ChangeExtension(node.name, "c", nodeName);
2588 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
2589 projectCompileItem =
2591 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
2593 bool NotifySelect(MenuItem selection, Modifiers mods)
2597 bool result = false;
2598 bool isCObject = false;
2599 ProjectNode node = null;
2600 for(p : ide.workspace.projects)
2602 node = projectView.GetNodeFromWindow(activeClient, p, false);
2605 if(!node && (node = projectView.GetNodeFromWindow(activeClient, null, true)))
2609 List<ProjectNode> nodes { };
2611 projectView.Compile(node.project, nodes, mods.ctrl && mods.shift, isCObject ? cObject : normal);
2616 ide.outputView.buildBox.Logf($"File %s is excluded from current build configuration.\n", node.name);
2621 projectMenu.AddDynamic(projectCompileItem, ide, false);
2627 caps = ovr = num = null;
2632 bool OnClose(bool parentClosing)
2634 //return !projectView.buildInProgress;
2635 if(projectView && projectView.buildInProgress)
2637 if(DontTerminateDebugSession($"Close IDE"))
2639 if(findInFilesDialog)
2640 findInFilesDialog.SearchStop();
2643 workspace.timer.Stop();
2646 ideMainFrame.Destroy(0);
2653 bool passThrough = false;
2654 bool debugStart = false;
2655 DynamicString passArgs { };
2656 for(c = 1; c<app.argc; c++)
2658 if(!strcmp(app.argv[c], "-debug-start"))
2660 else if(!passThrough && !strcmp(app.argv[c], "-@"))
2662 else if(passThrough)
2664 passArgs.concat(" ");
2665 passArgs.concat(app.argv[c]);
2669 char fullPath[MAX_LOCATION];
2670 char parentPath[MAX_LOCATION];
2671 char ext[MAX_EXTENSION];
2673 FileAttribs dirAttribs;
2674 GetWorkingDir(fullPath, MAX_LOCATION);
2675 PathCat(fullPath, app.argv[c]);
2676 StripLastDirectory(fullPath, parentPath);
2677 GetExtension(app.argv[c], ext);
2678 isProject = !strcmpi(ext, "epj");
2680 if(isProject && c > (debugStart ? 2 : 1)) continue;
2682 // Create directory for projects (only)
2683 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
2685 if(isProject && !FileExists(fullPath))
2687 // The NewProject will handle directory creation
2688 /*if(!dirAttribs.isDirectory)
2690 MakeDir(parentPath);
2691 dirAttribs = FileExists(parentPath);
2693 if(dirAttribs.isDirectory)*/
2695 char name[MAX_LOCATION];
2696 NewProjectDialog newProjectDialog;
2700 projectView.visible = false;
2701 if(!projectView.Destroy(0))
2705 newProjectDialog = { master = this };
2707 strcpy(name, app.argv[c]);
2708 StripExtension(name);
2709 GetLastDirectory(name, name);
2710 newProjectDialog.projectName.contents = name;
2711 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
2712 newProjectDialog.locationEditBox.path = parentPath;
2713 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
2715 newProjectDialog.Modal();
2718 ideSettings.AddRecentProject(projectView.fileName);
2719 ide.UpdateRecentMenus();
2720 settingsContainer.Save();
2723 // Open only one project
2727 ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
2729 else if(strstr(fullPath, "http://") == fullPath)
2730 ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
2733 if(passThrough && projectView && projectView.project && workspace)
2734 workspace.commandLineArgs = passArgs;
2737 ;//MenuDebugStart(debugStartResumeItem, 0); // <-- how TODO this without getting into the app.Wait lock
2739 UpdateToolBarActiveConfigs(false);
2740 UpdateToolBarActiveCompilers();
2746 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
2749 projectView.visible = false;
2750 projectView.Destroy(0);
2753 #ifdef GDB_DEBUG_GUI
2754 gdbDialog.Destroy(0);
2759 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config)
2763 char * oldPaths[128];
2764 String oldList = new char[maxPathLen];
2765 Array<String> newExePaths { };
2766 //Map<String, bool> exePathExists { };
2768 #if defined(__unix__) || defined(__APPLE__)
2769 Array<String> newLibPaths { };
2770 Map<String, bool> libPathExists { };
2775 for(prj : workspace.projects)
2777 DirExpression targetDirExp;
2779 // SKIP FIRST PROJECT...
2780 if(prj == workspace.projects.firstIterator.data) continue;
2782 // NOTE: Right now the additional project config dir will be
2783 // obtained when the debugger is started, so toggling it
2784 // while building will change which library gets used.
2785 // To go with the initial state, e.g. when F5 was pressed,
2786 // we nould need to keep a list of all project's active
2787 // config upon startup.
2788 targetDirExp = prj.GetTargetDir(compiler, prj.config);
2790 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
2794 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2795 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
2799 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2800 if(cfg.targetType == sharedLibrary && cfg.debug)
2804 if(targetDirExp.dir)
2806 char buffer[MAX_LOCATION];
2807 #if defined(__WIN32__)
2808 Array<String> paths = newExePaths;
2810 Array<String> paths = newLibPaths;
2812 GetSystemPathBuffer(buffer, prj.topNode.path);
2813 PathCat(buffer, targetDirExp.dir);
2816 if(!fstrcmp(p, buffer))
2823 paths.Add(CopyString(buffer));
2825 delete targetDirExp;
2829 for(item : compiler.executableDirs)
2832 for(p : newExePaths)
2834 if(!fstrcmp(p, item))
2841 newExePaths.Add(CopySystemPath(item));
2844 GetEnvironment("PATH", oldList, maxPathLen);
2846 printf("Old value of PATH: %s\n", oldList);
2848 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
2849 for(c = 0; c < count; c++)
2852 for(p : newExePaths)
2854 if(!fstrcmp(p, oldPaths[c]))
2861 newExePaths.Add(CopySystemPath(oldPaths[c]));
2865 for(path : newExePaths)
2866 len += strlen(path) + 1;
2867 newList = new char[len + 1];
2869 for(path : newExePaths)
2871 strcat(newList, path);
2872 strcat(newList, pathListSep);
2874 newList[len - 1] = '\0';
2875 SetEnvironment("PATH", newList);
2877 printf("New value of PATH: %s\n", newList);
2884 #if defined(__unix__) || defined(__APPLE__)
2886 for(item : compiler.libraryDirs)
2888 if(!libPathExists[item]) // fstrcmp should be used
2890 newLibPaths.Add(item);
2891 libPathExists[item] = true;
2895 #if defined(__APPLE__)
2896 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
2898 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
2901 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
2903 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
2904 for(c = 0; c < count; c++)
2906 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
2908 newLibPaths.Add(oldPaths[c]);
2909 libPathExists[oldPaths[c]] = true;
2914 for(path : newLibPaths)
2915 len += strlen(path) + 1;
2916 newList = new char[len + 1];
2918 for(path : newLibPaths)
2920 strcat(newList, path);
2921 strcat(newList, pathListSep);
2923 newList[len - 1] = '\0';
2924 #if defined(__APPLE__)
2925 SetEnvironment("DYLD_LIBRARY_PATH", newList);
2927 SetEnvironment("LD_LIBRARY_PATH", newList);
2930 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
2935 delete libPathExists;
2938 if(compiler.distccEnabled && compiler.distccHosts)
2939 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
2944 void DestroyTemporaryProjectDir()
2946 if(tmpPrjDir && tmpPrjDir[0])
2948 if(FileExists(tmpPrjDir).isDirectory)
2949 DestroyDir(tmpPrjDir);
2950 property::tmpPrjDir = null;
2956 // Graphics Driver Menu
2960 app.currentSkin.selectionColor = selectionColor;
2961 app.currentSkin.selectionText = selectionText;
2965 driverItems = new MenuItem[app.numDrivers];
2966 for(c = 0; c < app.numDrivers; c++)
2968 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
2969 driverItems[c].id = c;
2970 driverItems[c].isRadio = true;
2973 driverItems = new MenuItem[2];
2974 #if defined(__unix__)
2975 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
2976 driverItems[0].id = 0;
2977 driverItems[0].isRadio = true;
2979 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
2980 driverItems[0].id = 0;
2981 driverItems[0].isRadio = true;
2983 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
2984 driverItems[1].id = 1;
2985 driverItems[1].isRadio = true;
2987 /* skinItems = new MenuItem[app.numSkins];
2988 for(c = 0; c < app.numSkins; c++)
2990 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
2991 skinItems[c].id = c;
2992 skinItems[c].isRadio = true;
2995 ideFileDialog.master = this;
2996 ideProjectFileDialog.master = this;
2998 //SetDriverAndSkin();
3002 void UpdateRecentMenus()
3005 Menu fileMenu = menu.FindMenu($"File");
3006 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3007 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3008 char itemName[MAX_LOCATION + 4];
3011 recentFiles.Clear();
3014 for(recent : ideSettings.recentFiles)
3016 sprintf(itemName, "%d %s", 1 + c, recent);
3017 MakeSystemPath(itemName);
3018 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3022 recentProjects.Clear();
3024 for(recent : ideSettings.recentProjects)
3026 sprintf(itemName, "%d %s", 1 + c, recent);
3027 MakeSystemPath(itemName);
3028 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3041 void DestroyDir(char * path)
3043 RecursiveDeleteFolderFSI fsi { };
3048 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3050 bool preserveRootFolder;
3052 void OutFolder(char * folderPath, bool isRoot)
3054 if(!(preserveRootFolder && isRoot))
3055 RemoveDir(folderPath);
3058 bool OnFile(char * filePath)
3060 DeleteFile(filePath);
3065 class IDEApp : GuiApplication
3067 //driver = "Win32Console";
3068 // driver = "OpenGL";
3072 TempFile includeFile { };
3076 SetLoggingMode(stdOut, null);
3077 //SetLoggingMode(debug, null);
3079 settingsContainer.Load();
3080 #if defined(__unix__) || defined(__APPLE__)
3081 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3083 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3085 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3089 desktop.text = titleECEREIDE;
3092 for(c = 1; c<app.argc; c++)
3094 char fullPath[MAX_LOCATION];
3095 GetWorkingDir(fullPath, MAX_LOCATION);
3096 PathCat(fullPath, app.argv[c]);
3097 ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal);
3101 if(!LoadIncludeFile())
3102 PrintLn("error: unable to load :crossplatform.mk file inside ide binary.");
3107 bool LoadIncludeFile()
3109 bool result = false;
3110 File include = FileOpen(":crossplatform.mk", read);
3113 File f = includeFile;
3116 for(; !include.Eof(); )
3119 int count = include.Read(buffer, 1, 4096);
3120 f.Write(buffer, 1, count);
3130 IDEMainFrame ideMainFrame { };
3132 define app = ((IDEApp)__thisModule);
3134 define titleECEREIDE = $"ECERE IDE (Debug)";
3136 define titleECEREIDE = $"ECERE IDE";