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(true);
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 }, disabled = true;
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 }, disabled = true;
306 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
308 if(ide.workspace && ide.projectView && 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 DropBox activeBitDepth
327 this, toolTip = $"Active Bit Depth", size = { 60 }, disabled = true;
328 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
330 if(ide.workspace && ide.projectView && row)
332 bool silent = ide.projectView.buildInProgress == none ? false : true;
333 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
334 ide.workspace.bitDepth = (int)row.tag;
335 ide.projectView.ShowOutputBuildLog(!silent);
337 ide.projectView.DisplayCompiler(compiler, false);
338 for(prj : ide.workspace.projects)
339 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
341 ide.workspace.Save();
347 Window spacer7 { this, size = { 4 } };
352 row = activeBitDepth.AddString("Auto");
354 activeBitDepth.AddString("32 bit").tag = 32;
355 activeBitDepth.AddString("64 bit").tag = 64;
356 activeBitDepth.currentRow = row;
361 class IDEMainFrame : Window
363 background = formColor;
364 borderStyle = sizable;
368 minClientSize = { 600, 300 };
370 icon = { ":icon.png" };
371 text = titleECEREIDE;
375 anchor = { top = 0, right = 0, bottom = 0 };
378 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
385 isActiveClient = true;
387 direction = vertical;
388 background = formColor;
389 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
397 ((IDEWorkSpace)master).toolBar = null;
400 IDEWorkSpace ideWorkSpace { stack, this, toolBar = toolBar };
403 define ide = ideMainFrame.ideWorkSpace;
405 class IDEWorkSpace : Window
407 background = Color { 85, 85, 85 };
410 hasVertScroll = true;
411 hasHorzScroll = true;
413 isActiveClient = true;
414 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
418 MenuItem * driverItems, * skinItems;
419 StatusField pos { width = 150 };
420 StatusField ovr, caps, num;
422 BitmapResource back { ":ecereBack.jpg", window = this };
423 BitmapResource bmpBp { ":codeMarks/breakpoint.png", window = this };
424 BitmapResource bmpBpDisabled { ":codeMarks/breakpointDisabled.png", window = this };
425 BitmapResource bmpBpHalf { ":codeMarks/breakpointHalf.png", window = this };
426 BitmapResource bmpBpHalfDisabled { ":codeMarks/breakpointHalfDisabled.png", window = this };
427 BitmapResource bmpCursor { ":codeMarks/cursor.png", window = this };
428 BitmapResource bmpCursorError { ":codeMarks/cursorError.png", window = this };
429 BitmapResource bmpTopFrame { ":codeMarks/topFrame.png", window = this };
430 BitmapResource bmpTopFrameError { ":codeMarks/topFrameError.png", window = this };
431 BitmapResource bmpTopFrameHalf { ":codeMarks/topFrameHalf.png", window = this };
432 BitmapResource bmpTopFrameHalfError { ":codeMarks/topFrameHalfError.png", window = this };
434 Debugger debugger { };
436 ProjectView projectView;
438 OutputView outputView
442 void OnGotoError(char * line, bool noParsing)
444 ide.GoToError(line, noParsing);
447 void OnCodeLocationParseAndGoTo(char * line)
449 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir);
452 bool OnKeyDown(Key key, unichar ch)
457 if(activeBox != findBox || !ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
458 ide.ShowCodeEditor();
462 OutputView::OnKeyDown(key, ch);
469 bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
472 ide.RepositionWindows(false);
476 bool OnClose(bool parentClosing)
480 ide.RepositionWindows(false);
481 return parentClosing;
485 CallStackView callStackView
487 parent = this, font = { panelFont.faceName, panelFont.size };
489 void OnGotoLine(char * line)
492 stackLvl = atoi(line);
493 ide.debugger.GoToStackFrameLine(stackLvl, true);
496 void OnSelectFrame(int lineNumber)
498 ide.debugger.SelectFrame(lineNumber);
501 void OnToggleBreakpoint()
503 Debugger debugger = ide.debugger;
504 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
506 int line = debugger.activeFrame.line;
507 char name[MAX_LOCATION];
509 // TOFIX: Improve on this, don't use only filename, make a function
510 GetLastDirectory(debugger.activeFrame.absoluteFile, name);
511 if(ide && ide.workspace)
513 for(p : ide.workspace.projects)
515 if(p.topNode.Find(name, false))
523 for(p : ide.workspace.projects)
525 if(IsPathInsideOf(debugger.activeFrame.absoluteFile, p.topNode.path))
533 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line, prj);
536 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
537 if(codeEditor) { codeEditor.Update(null); Activate(); }
542 bool OnKeyDown(Key key, unichar ch)
546 case escape: ide.ShowCodeEditor(); break;
551 bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
554 ide.RepositionWindows(false);
558 bool OnClose(bool parentClosing)
562 ide.RepositionWindows(false);
563 return parentClosing;
566 void OnRedraw(Surface surface)
568 Debugger debugger = ide.debugger;
569 Frame activeFrame = debugger.activeFrame;
573 int lineCursor, lineTopFrame, activeThread, hitThread;
574 int lineH, scrollY, boxH;
576 Breakpoint bp = null;
579 scrollY = editBox.scroll.y;
580 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
581 activeThread = debugger.activeThread;
582 hitThread = debugger.hitThread;
583 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
585 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
586 if(activeFrame.absoluteFile)
588 for(i : ide.workspace.breakpoints; i.type == user)
590 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
591 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
592 activeFrame.line == i.line)
600 DrawLineMarginIcon(surface,
601 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
602 lineCursor /*1*/, lineH, scrollY, boxH);
604 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
605 DrawLineMarginIcon(surface,
606 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
607 1, lineH, scrollY, boxH);
609 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
610 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
611 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
613 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
614 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
616 if(editBox.horzScroll && editBox.horzScroll.visible)
618 surface.SetBackground(control);
619 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
624 WatchesView watchesView { parent = this };
625 ThreadsView threadsView
627 parent = this, font = { panelFont.faceName, panelFont.size };
629 bool OnKeyDown(Key key, unichar ch)
633 case escape: ide.ShowCodeEditor(); break;
638 bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
641 ide.RepositionWindows(false);
645 bool OnClose(bool parentClosing)
649 ide.RepositionWindows(false);
650 return parentClosing;
653 void OnSelectThread(int threadId)
656 ide.debugger.SelectThread(threadId);
659 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
662 Debugger debugger = ide.debugger;
663 *activeThread = debugger.activeThread;
664 *hitThread = debugger.hitThread;
665 *signalThread = debugger.signalThread;
670 BreakpointsView breakpointsView { parent = this };
672 ToolBox toolBox { parent = this };
673 Sheet sheet { parent = this };
676 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
678 Menu fileMenu { menu, $"File", f, hasMargin = true };
681 fileMenu, $"New", n, ctrlN;
682 bitmap = { ":actions/docNew.png" };
683 bool NotifySelect(MenuItem selection, Modifiers mods)
685 Window document = (Window)NewCodeEditor(this, normal, false);
686 document.NotifySaved = DocumentSaved;
690 MenuItem fileOpenItem
692 fileMenu, $"Open...", o, ctrlO;
693 bitmap = { ":actions/docOpen.png" };
694 bool NotifySelect(MenuItem selection, Modifiers mods)
696 if(!projectView && ideSettings.ideFileDialogLocation)
697 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
700 if(ideFileDialog.Modal() == ok)
702 bool gotWhatWeWant = false;
704 int numSelections = ideFileDialog.numSelections;
705 char ** multiFilePaths = ideFileDialog.multiFilePaths;
707 for(c = 0; c < numSelections; c++)
709 if(OpenFile(multiFilePaths[c], normal, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
710 gotWhatWeWant = true;
713 MessageBox { type = yesNo, master = this, text = $"Error opening file",
714 contents = $"Open a different file?" }.Modal() == no)
716 if(!projectView && gotWhatWeWant)
717 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
727 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
728 MenuDivider { fileMenu };
729 MenuItem fileSaveItem
731 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
733 // For the toolbar button; clients can still override that for the menu item
734 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
736 Window w = activeClient;
738 w.MenuFileSave(null, 0);
742 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
743 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
744 MenuDivider { fileMenu };
747 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
748 bool NotifySelect(MenuItem selection, Modifiers mods)
750 findInFilesDialog.replaceMode = false;
751 findInFilesDialog.Show();
755 MenuItem replaceInFiles
757 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
758 bool NotifySelect(MenuItem selection, Modifiers mods)
760 findInFilesDialog.replaceMode = true;
761 findInFilesDialog.Show();
765 MenuDivider { fileMenu };
766 MenuItem globalSettingsItem
768 fileMenu, $"Global Settings...", g;
769 bool NotifySelect(MenuItem selection, Modifiers mods)
771 globalSettingsDialog.master = this;
772 if(ide.workspace && ide.workspace.compiler)
773 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.compiler;
774 else if(ideSettings.defaultCompiler)
775 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
776 globalSettingsDialog.Modal();
780 MenuDivider { fileMenu };
781 Menu recentFiles { fileMenu, $"Recent Files", r };
782 Menu recentProjects { fileMenu, $"Recent Projects", p };
783 MenuDivider { fileMenu };
786 fileMenu, $"Exit", x, altF4, NotifySelect = MenuFileExit;
788 bool NotifySelect(MenuItem selection, Modifiers mods)
790 ideMainFrame.Destroy(0);
795 bool FileRecentFile(MenuItem selection, Modifiers mods)
798 for(file : ideSettings.recentFiles)
800 if(id == selection.id)
803 char extension[MAX_EXTENSION] = "";
804 GetExtension(file, extension);
805 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
808 char * command = PrintString("ide ", isProjectFile ? "-t " : "", file);
813 OpenFile(file, normal, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
821 bool FileRecentProject(MenuItem selection, Modifiers mods)
824 for(file : ideSettings.recentProjects)
826 if(id == selection.id)
830 char * command = PrintString("ide ", file);
835 OpenFile(file, normal, true, null, no, normal, mods.ctrl && mods.shift);
843 MenuPlacement editMenu { menu, $"Edit", e };
845 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
846 MenuItem projectNewItem
848 projectMenu, $"New...", n, Key { n, true, true };
849 bitmap = { ":actions/projNew.png" };
850 bool NotifySelect(MenuItem selection, Modifiers mods)
852 if(!DontTerminateDebugSession($"New Project"))
853 if(MenuWindowCloseAll(null, 0))
855 NewProjectDialog newProjectDialog;
859 projectView.visible = false;
860 if(!projectView.Destroy(0))
864 newProjectDialog = { master = this };
865 newProjectDialog.Modal();
868 ideSettings.AddRecentProject(projectView.fileName);
869 ide.UpdateRecentMenus();
870 settingsContainer.Save();
876 MenuItem projectOpenItem
878 projectMenu, $"Open...", o, Key { o, true, true };
879 bitmap = { ":actions/projOpen.png" };
880 bool NotifySelect(MenuItem selection, Modifiers mods)
882 if(ideSettings.ideProjectFileDialogLocation)
883 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
885 ideProjectFileDialog.text = openProjectFileDialogTitle;
886 if(ideProjectFileDialog.Modal() == ok)
888 OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
889 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
894 MenuItem projectQuickItem
896 projectMenu, $"Quick...", q, f7, disabled = true;
897 bool NotifySelect(MenuItem selection, Modifiers mods)
900 QuickProjectDialog { this }.Modal();
904 MenuItem projectAddItem
906 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
907 bitmap = { ":actions/projAdd.png" };
909 bool NotifySelect(MenuItem selection, Modifiers mods)
911 if(ideSettings.ideProjectFileDialogLocation)
912 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
914 ideProjectFileDialog.text = addProjectFileDialogTitle;
917 if(ideProjectFileDialog.Modal() == ok)
919 if(OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
921 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
922 contents = $"Add a different project?" }.Modal() == no)
933 MenuItem projectCloseItem
935 projectMenu, $"Close", c, disabled = true;
936 bool NotifySelect(MenuItem selection, Modifiers mods)
940 if(!ide.DontTerminateDebugSession($"Project Close"))
942 if(findInFilesDialog)
943 findInFilesDialog.SearchStop();
944 projectView.visible = false;
945 if(projectView.Destroy(0))
946 MenuWindowCloseAll(null, 0);
948 char workingDir[MAX_LOCATION];
949 GetWorkingDir(workingDir, MAX_LOCATION);
950 findInFilesDialog.currentDirectory = workingDir;
951 ideMainFrame.text = titleECEREIDE;
959 MenuDivider { projectMenu };
960 MenuItem projectSettingsItem
962 projectMenu, $"Settings...", s, altF7, disabled = true;
963 bool NotifySelect(MenuItem selection, Modifiers mods)
965 projectView.MenuSettings(projectView.active ? selection : null, mods);
969 MenuDivider { projectMenu };
970 MenuItem projectBrowseFolderItem
972 projectMenu, $"Browse Project Folder", p, disabled = true;
973 bool NotifySelect(MenuItem selection, Modifiers mods)
976 projectView.MenuBrowseFolder(null, mods);
980 MenuDivider { projectMenu };
981 MenuItem projectRunItem
983 projectMenu, $"Run", r, ctrlF5, disabled = true;
984 bitmap = { ":actions/run.png" };
985 bool NotifySelect(MenuItem selection, Modifiers mods)
988 projectView.Run(null, mods);
992 MenuItem projectBuildItem
994 projectMenu, $"Build", b, f7, disabled = true;
995 bitmap = { ":actions/build.png" };
996 bool NotifySelect(MenuItem selection, Modifiers mods)
1000 if(projectView.buildInProgress == none)
1001 projectView.ProjectBuild(projectView.active ? selection : null, mods);
1003 projectView.stopBuild = true;
1008 MenuItem projectLinkItem
1010 projectMenu, $"Relink", l, disabled = true;
1011 bitmap = { ":actions/relink.png" };
1012 bool NotifySelect(MenuItem selection, Modifiers mods)
1015 projectView.ProjectLink(projectView.active ? selection : null, mods);
1019 MenuItem projectRebuildItem
1021 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
1022 bitmap = { ":actions/rebuild.png" };
1023 bool NotifySelect(MenuItem selection, Modifiers mods)
1026 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
1030 MenuItem projectCleanTargetItem
1032 projectMenu, $"Clean Target", g, disabled = true;
1033 bitmap = { ":actions/clean.png" };
1034 bool NotifySelect(MenuItem selection, Modifiers mods)
1039 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
1044 MenuItem projectCleanItem
1046 projectMenu, $"Clean", e, disabled = true;
1047 bitmap = { ":actions/clean.png" };
1048 bool NotifySelect(MenuItem selection, Modifiers mods)
1053 projectView.ProjectClean(projectView.active ? selection : null, mods);
1058 MenuItem projectRealCleanItem
1060 projectMenu, $"Real Clean", disabled = true;
1061 bitmap = { ":actions/clean.png" };
1062 bool NotifySelect(MenuItem selection, Modifiers mods)
1067 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1072 MenuItem projectRegenerateItem
1074 projectMenu, $"Regenerate Makefile", m, disabled = true;
1075 bitmap = { ":actions/regMakefile.png" };
1076 bool NotifySelect(MenuItem selection, Modifiers mods)
1079 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1083 MenuItem projectCompileItem;
1084 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1085 MenuItem debugStartResumeItem
1087 debugMenu, $"Start", s, f5, disabled = true;
1088 bitmap = { ":actions/debug.png" };
1089 NotifySelect = MenuDebugStart;
1091 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1095 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1096 if(!projectView.DebugStart())
1097 debugStartResumeItem.disabled = false; // same exception
1101 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1104 projectView.DebugResume();
1107 MenuItem debugRestartItem
1109 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1110 bitmap = { ":actions/restart.png" };
1111 bool NotifySelect(MenuItem selection, Modifiers mods)
1114 projectView.DebugRestart();
1118 MenuItem debugBreakItem
1120 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1121 bitmap = { ":actions/pause.png" };
1122 bool NotifySelect(MenuItem selection, Modifiers mods)
1124 if(projectView && projectView.buildInProgress != none)
1127 projectView.DebugBreak();
1131 MenuItem debugStopItem
1133 debugMenu, $"Stop", p, shiftF5, disabled = true;
1134 bitmap = { ":actions/stopDebug.png" };
1135 bool NotifySelect(MenuItem selection, Modifiers mods)
1138 projectView.DebugStop();
1142 MenuDivider { debugMenu };
1143 MenuItem debugStepIntoItem
1145 debugMenu, $"Step Into", i, f11, disabled = true;
1146 bitmap = { ":actions/stepInto.png" };
1147 bool NotifySelect(MenuItem selection, Modifiers mods)
1150 projectView.DebugStepInto();
1154 MenuItem debugStepOverItem
1156 debugMenu, $"Step Over", v, f10, disabled = true;
1157 bitmap = { ":actions/stepOver.png" };
1158 bool NotifySelect(MenuItem selection, Modifiers mods)
1161 projectView.DebugStepOver(false);
1165 MenuItem debugStepOutItem
1167 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1168 bitmap = { ":actions/stepOut.png" };
1169 bool NotifySelect(MenuItem selection, Modifiers mods)
1172 projectView.DebugStepOut(false);
1176 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1177 MenuItem debugSkipStepOverItem
1179 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1180 bool NotifySelect(MenuItem selection, Modifiers mods)
1183 projectView.DebugStepOver(true);
1187 MenuItem debugSkipStepOutItem
1189 debugMenu, $"Step Out Skipping Breakpoints", t, Key { f11, ctrl = true, shift = true }, disabled = true;
1190 bitmap = { ":actions/skipBreaks.png" };
1191 bool NotifySelect(MenuItem selection, Modifiers mods)
1194 projectView.DebugStepOut(true);
1198 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1199 //MenuDivider { debugMenu };
1200 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1201 MenuPlacement imageMenu { menu, $"Image", i };
1202 Menu viewMenu { menu, $"View", v };
1203 MenuItem viewProjectItem
1205 viewMenu, $"Project View", j, alt0, disabled = true;
1206 bool NotifySelect(MenuItem selection, Modifiers mods)
1210 projectView.visible = true;
1211 projectView.Activate();
1216 MenuPlacement { viewMenu, $"View Designer" };
1217 MenuPlacement { viewMenu, $"View Code" };
1218 MenuPlacement { viewMenu, $"View Properties" };
1219 MenuPlacement { viewMenu, $"View Methods" };
1220 MenuItem viewDesignerItem
1222 viewMenu, $"View Designer", d, f8;
1223 bool NotifySelect(MenuItem selection, Modifiers mods)
1225 Window client = activeClient;
1226 Class dataType = client._class;
1227 if(!strcmp(dataType.name, "Designer"))
1229 client.visible = true;
1233 ((CodeEditor)client).ViewDesigner();
1237 MenuItem viewCodeItem
1239 viewMenu, $"View Code", c, f8;
1240 bool NotifySelect(MenuItem selection, Modifiers mods)
1242 Window client = activeClient;
1243 Class dataType = client._class;
1244 if(!strcmp(dataType.name, "Designer"))
1245 client = ((Designer)client).codeEditor;
1248 // Do this after so the caret isn't moved yet...
1249 client.visible = true;
1253 MenuItem viewPropertiesItem
1255 viewMenu, $"View Properties", p, f4;
1256 bool NotifySelect(MenuItem selection, Modifiers mods)
1258 sheet.visible = true;
1259 sheet.sheetSelected = properties;
1264 MenuItem viewMethodsItem
1266 viewMenu, $"View Methods", m, f4;
1267 bool NotifySelect(MenuItem selection, Modifiers mods)
1269 sheet.visible = true;
1270 sheet.sheetSelected = methods;
1275 MenuItem viewToolBoxItem
1277 viewMenu, $"View Toolbox", x, f12;
1278 bool NotifySelect(MenuItem selection, Modifiers mods)
1280 toolBox.visible = true;
1285 MenuItem viewOutputItem
1287 viewMenu, $"Output", o, alt2;
1288 bool NotifySelect(MenuItem selection, Modifiers mods)
1294 MenuItem viewWatchesItem
1296 viewMenu, $"Watches", w, alt3;
1297 bool NotifySelect(MenuItem selection, Modifiers mods)
1303 MenuItem viewThreadsItem
1305 viewMenu, $"Threads", t, alt4;
1306 bool NotifySelect(MenuItem selection, Modifiers mods)
1312 MenuItem viewBreakpointsItem
1314 viewMenu, $"Breakpoints", b, alt5;
1315 bool NotifySelect(MenuItem selection, Modifiers mods)
1317 breakpointsView.Show();
1321 MenuItem viewCallStackItem
1323 viewMenu, $"Call Stack", s, alt7;
1324 bool NotifySelect(MenuItem selection, Modifiers mods)
1326 callStackView.Show();
1330 MenuItem viewAllDebugViews
1332 viewMenu, $"All Debug Views", a, alt9;
1333 bool NotifySelect(MenuItem selection, Modifiers mods)
1338 callStackView.Show();
1339 breakpointsView.Show();
1343 #ifdef GDB_DEBUG_GUI
1344 MenuDivider { viewMenu };
1345 MenuItem viewGDBItem
1347 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1348 bool NotifySelect(MenuItem selection, Modifiers mods)
1355 MenuDivider { viewMenu };
1356 MenuItem viewColorPicker
1358 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1359 bool NotifySelect(MenuItem selection, Modifiers mods)
1361 ColorPicker colorPicker { master = this };
1362 colorPicker.Modal();
1366 MenuDivider { viewMenu };
1370 viewMenu, "Full Screen", f, checkable = true;
1372 bool NotifySelect(MenuItem selection, Modifiers mods)
1374 app.fullScreen ^= true;
1376 anchor = { 0, 0, 0, 0 };
1381 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1382 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1383 Menu windowMenu { menu, $"Window", w };
1384 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1385 MenuDivider { windowMenu };
1386 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1387 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1388 MenuDivider { windowMenu };
1389 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1390 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1391 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1392 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1393 MenuDivider { windowMenu };
1394 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1395 Menu helpMenu { menu, $"Help", h };
1398 helpMenu, $"API Reference", r, f1;
1399 bool NotifySelect(MenuItem selection, Modifiers mods)
1401 Execute("documentor");
1405 MenuDivider { helpMenu };
1408 helpMenu, $"About...", a;
1409 bool NotifySelect(MenuItem selection, Modifiers mods)
1411 AboutIDE { master = this }.Modal();
1416 property ToolBox toolBox
1418 get { return toolBox; }
1421 property Sheet sheet
1423 get { return sheet; }
1426 property Project project
1428 get { return projectView ? projectView.project : null; }
1431 property Workspace workspace
1433 get { return projectView ? projectView.workspace : null; }
1436 FindInFilesDialog findInFilesDialog
1439 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1445 #ifdef GDB_DEBUG_GUI
1448 master = this, parent = this;
1449 anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1451 void OnCommand(char * string)
1454 ide.debugger.SendGDBCommand(string);
1459 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1461 //app.driver = app.drivers[selection.id];
1462 #if defined(__unix__) || defined(__APPLE__)
1463 app.driver = selection.id ? "OpenGL" : "X";
1465 app.driver = selection.id ? "OpenGL" : "GDI";
1467 delete ideSettings.displayDriver;
1468 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1470 settingsContainer.Save();
1471 //SetDriverAndSkin();
1475 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1477 app.skin = app.skins[selection.id];
1482 void SetDriverAndSkin()
1485 for(c = 0; c < app.numSkins; c++)
1486 if(!strcmp(app.skins[c], app.skin))
1488 skinItems[c].checked = true;
1491 for(c = 0; c < app.numDrivers; c++)
1492 if(!strcmp(app.drivers[c], app.driver))
1494 driverItems[c].checked = true;
1499 ProjectView CreateProjectView(Workspace workspace, char * fileName)
1501 Project project = workspace.projects.firstIterator.data;
1502 projectView = ProjectView
1505 fileName = fileName;
1507 void NotifyDestroyed(Window window, DialogResult result)
1510 text = titleECEREIDE;
1515 projectView.Create();
1516 RepositionWindows(false);
1518 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1519 projectView.workspace = workspace;
1520 projectView.project = project;
1521 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1525 ide.breakpointsView.LoadFromWorkspace();
1526 ide.watchesView.LoadFromWorkspace();
1528 findInFilesDialog.projectNodeField.userData = projectView;
1531 char fileName[MAX_LOCATION];
1532 strcpy(fileName, project.topNode.path);
1533 PathCat(fileName, project.topNode.name);
1538 void RepositionWindows(bool expand)
1543 bool inDebugMode = debugger.isActive;
1544 bool callStackVisible = expand ? false : callStackView.visible;
1545 bool threadsVisible = expand ? false : threadsView.visible;
1546 bool watchesVisible = expand ? false : watchesView.visible;
1547 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1548 bool toolBoxVisible = toolBox.visible;
1549 bool outputVisible = expand ? false : outputView.visible;
1550 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1551 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1553 for(child = firstChild; child; child = child.next)
1555 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1556 child._class == class(Sheet) || child._class == class(ProjectView))
1558 Anchor anchor = child.anchor;
1559 anchor.top = topDistance;
1560 anchor.bottom = bottomDistance;
1561 if(child._class == class(CodeEditor) || child._class == class(Designer))
1563 anchor.right = toolBoxVisible ? 150 : 0;
1565 child.anchor = anchor;
1569 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1570 child._class == class(BreakpointsView))
1571 child.visible = false;
1574 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1579 bool ShowCodeEditor()
1582 activeClient.Activate();
1583 else if(projectView)
1585 projectView.visible = true;
1586 projectView.Activate();
1590 sheet.visible = true;
1596 void DocumentSaved(Window document, char * fileName)
1598 ideSettings.AddRecentFile(fileName);
1599 ide.UpdateRecentMenus();
1600 ide.AdjustFileMenus();
1601 settingsContainer.Save();
1604 bool Window::OnFileModified(FileChange fileChange, char * param)
1607 sprintf(temp, $"The document %s was modified by another application.\n"
1608 "Would you like to reload it and lose your changes?", this.fileName);
1609 if(MessageBox { type = yesNo, master = this/*.parent*/,
1610 text = $"Document has been modified", contents = temp }.Modal() == yes)
1612 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1613 char * fileName = CopyString(this.fileName);
1614 WindowState state = this.state;
1615 Anchor anchor = this.anchor;
1616 Size size = this.size;
1618 this.modifiedDocument = false;
1620 this = ide.OpenFile(fileName, normal, true, null, no, normal, noParsing);
1623 this.anchor = anchor;
1625 this.SetState(state, true, 0);
1633 void UpdateMakefiles()
1637 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1638 for(prj : workspace.projects)
1639 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1644 void UpdateCompilerConfigs(bool mute)
1646 UpdateToolBarActiveCompilers();
1649 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1650 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1653 projectView.ShowOutputBuildLog(true);
1654 projectView.DisplayCompiler(compiler, false);
1656 for(prj : workspace.projects)
1657 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1662 void UpdateToolBarActiveCompilers()
1664 toolBar.activeCompiler.Clear();
1665 for(compiler : ideSettings.compilerConfigs)
1667 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1668 if(workspace && workspace.compiler && !strcmp(compiler.name, workspace.compiler))
1669 toolBar.activeCompiler.currentRow = row;
1671 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1672 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1675 void UpdateToolBarActiveConfigs(bool selectionOnly)
1677 bool commonSelected = false;
1678 DataRow row = toolBar.activeConfig.currentRow;
1680 row = toolBar.activeConfig.FindRow(1);
1683 toolBar.activeConfig.Clear();
1684 row = toolBar.activeConfig.AddString("(Mixed)");
1689 char * configName = null;
1692 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1693 for(prj : workspace.projects)
1695 for(cfg : prj.configurations)
1698 configs[cfg.name] = 1;
1703 toolBar.activeConfig.AddString(&name);
1707 if(projectView && projectView.project)
1709 for(prj : workspace.projects)
1711 if(prj.config && prj.config.name)
1713 configName = prj.config.name;
1719 commonSelected = true;
1720 for(prj : workspace.projects)
1722 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1724 commonSelected = false;
1732 commonSelected = false;
1733 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1735 if(!strcmp(row.string, configName))
1737 toolBar.activeConfig.currentRow = row;
1738 commonSelected = true;
1745 toolBar.activeConfig.Sort(null, 0);
1747 toolBar.activeConfig.currentRow = row;
1752 bool unavailable = !project;
1754 projectAddItem.disabled = unavailable;
1755 toolBar.buttonAddProject.disabled = unavailable;
1757 projectSettingsItem.disabled = unavailable;
1759 projectBrowseFolderItem.disabled = unavailable;
1761 viewProjectItem.disabled = unavailable;
1763 toolBar.activeConfig.disabled = unavailable;
1764 toolBar.activeCompiler.disabled = unavailable;
1765 toolBar.activeBitDepth.disabled = unavailable;
1772 property bool hasOpenedCodeEditors
1777 for(w = firstChild; w; w = w.next)
1778 if(w._class == class(CodeEditor) &&
1779 w.isDocument && !w.closing && w.visible && w.created &&
1780 w.fileName && w.fileName[0])
1786 void AdjustFileMenus()
1788 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
1790 projectQuickItem.disabled = unavailable;
1793 void AdjustBuildMenus()
1795 bool unavailable = project && projectView.buildInProgress;
1797 projectNewItem.disabled = unavailable;
1798 toolBar.buttonNewProject.disabled = unavailable;
1799 projectOpenItem.disabled = unavailable;
1800 toolBar.buttonOpenProject.disabled = unavailable;
1802 unavailable = !project || projectView.buildInProgress;
1804 projectCloseItem.disabled = unavailable;
1805 // toolBar.buttonCloseProject.disabled = unavailable;
1807 projectRunItem.disabled = unavailable || project.GetTargetType(project.config) != executable;
1808 toolBar.buttonRun.disabled = unavailable || project.GetTargetType(project.config) != executable;
1810 projectBuildItem.disabled = false;
1811 projectBuildItem.text = unavailable ? $"Stop Build" : $"Build";
1812 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
1814 projectLinkItem.disabled = unavailable;
1815 toolBar.buttonReLink.disabled = unavailable;
1816 projectRebuildItem.disabled = unavailable;
1817 toolBar.buttonRebuild.disabled = unavailable;
1818 projectCleanItem.disabled = unavailable;
1819 toolBar.buttonClean.disabled = unavailable;
1820 projectCleanTargetItem.disabled = unavailable;
1821 projectRealCleanItem.disabled = unavailable;
1822 // toolBar.buttonRealClean.disabled = unavailable;
1823 projectRegenerateItem.disabled = unavailable;
1824 toolBar.buttonRegenerateMakefile.disabled = unavailable;
1825 projectCompileItem.disabled = unavailable;
1827 AdjustPopupBuildMenus();
1830 void AdjustPopupBuildMenus()
1832 bool unavailable = !project || projectView.buildInProgress;
1834 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
1837 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
1840 menu.disabled = false;
1841 menu.text = unavailable ? $"Stop Build" : $"Build";
1842 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
1845 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0); if(menu) menu.disabled = unavailable;
1846 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0); if(menu) menu.disabled = unavailable;
1847 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0); if(menu) menu.disabled = unavailable;
1848 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0); if(menu) menu.disabled = unavailable;
1849 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0); if(menu) menu.disabled = unavailable;
1850 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
1851 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0); if(menu) menu.disabled = unavailable;
1852 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0); if(menu) menu.disabled = unavailable;
1853 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0); if(menu) menu.disabled = unavailable;
1854 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0); if(menu) menu.disabled = unavailable;
1855 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0); if(menu) menu.disabled = unavailable;
1856 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
1857 projectView.popupMenu.Update(null);
1861 property bool areDebugMenusUnavailable { get {
1863 project.GetTargetType(project.config) != executable ||
1864 projectView.buildInProgress == buildingMainProject;
1867 property bool isBreakpointTogglingUnavailable { get {
1871 property bool isDebuggerExecuting { get {
1875 return ide.debugger.state == running;
1878 void AdjustDebugMenus()
1880 bool unavailable = areDebugMenusUnavailable;
1881 bool active = debugger.isActive;
1882 bool bpNoToggle = isBreakpointTogglingUnavailable;
1883 bool executing = isDebuggerExecuting;
1884 //bool holding = debugger.state == stopped;
1886 debugStartResumeItem.disabled = unavailable || executing;
1887 debugStartResumeItem.text = active ? $"Resume" : $"Start";
1888 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
1891 toolBar.buttonDebugStartResume.disabled = unavailable || executing;
1892 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
1895 debugBreakItem.disabled = unavailable || !executing;
1896 debugStopItem.disabled = unavailable || !active;
1897 debugRestartItem.disabled = unavailable || !active;
1900 toolBar.buttonDebugPause.disabled = unavailable || !executing;
1901 toolBar.buttonDebugStop.disabled = unavailable || !active;
1902 toolBar.buttonDebugRestart.disabled = unavailable || !active;
1905 debugStepIntoItem.disabled = unavailable || executing;
1906 debugStepOverItem.disabled = unavailable || executing;
1907 debugStepOutItem.disabled = unavailable || executing || !active;
1908 debugSkipStepOverItem.disabled = unavailable || executing;
1909 debugSkipStepOutItem.disabled = unavailable || executing || !active;
1912 toolBar.buttonDebugStepInto.disabled = unavailable || executing;
1913 toolBar.buttonDebugStepOver.disabled = unavailable || executing;
1914 toolBar.buttonDebugStepOut.disabled = unavailable || executing || !active;
1915 toolBar.buttonDebugSkipStepOver.disabled = unavailable || executing;
1916 // toolBar.buttonDebugSkipStepOutItem.disabled = unavailable || executing;
1918 if((Designer)GetActiveDesigner())
1920 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
1922 codeEditor.AdjustDebugMenus(unavailable, bpNoToggle, executing);
1926 void ChangeFileDialogsDirectory(char * directory, bool saveSettings)
1928 char tempString[MAX_LOCATION];
1929 strcpy(tempString, directory);
1930 if(saveSettings && !projectView)
1932 ideSettings.ideFileDialogLocation = directory;
1933 settingsContainer.Save();
1936 ideFileDialog.currentDirectory = tempString;
1937 codeEditorFileDialog.currentDirectory = tempString;
1938 codeEditorFormFileDialog.currentDirectory = tempString;
1941 void ChangeProjectFileDialogDirectory(char * directory)
1943 ideSettings.ideProjectFileDialogLocation = directory;
1944 settingsContainer.Save();
1947 Window FindWindow(char * filePath)
1949 Window document = null;
1951 // TOCHECK: Do we need to change slashes here?
1952 for(document = firstChild; document; document = document.next)
1954 char * fileName = document.fileName;
1955 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
1957 document.visible = true;
1958 document.Activate();
1965 bool DontTerminateDebugSession(char * title)
1967 if(debugger.isActive)
1969 if(MessageBox { type = yesNo, master = ide,
1970 contents = $"Do you want to terminate the debugging session in progress?",
1971 text = title }.Modal() == no)
1974 MessageBox msg { type = yesNo, master = ide,
1975 contents = "Do you want to terminate the debugging session in progress?",
1977 if(msg.Modal() == no)
1989 Window OpenFile(char * origFilePath, WindowState state, bool visible, char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
1991 char extension[MAX_EXTENSION] = "";
1992 Window document = null;
1993 bool isProject = false;
1994 bool needFileModified = true;
1995 char winFilePath[MAX_LOCATION];
1996 char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2000 GetExtension(filePath, extension);
2004 strcpy(extension, type);
2006 if(strcmp(extension, ProjectExtension))
2008 for(document = firstChild; document; document = document.next)
2010 char * fileName = document.fileName;
2011 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2013 document.visible = true;
2015 document.Activate();
2021 if(createIfFails == whatever)
2023 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2025 needFileModified = false;
2026 if(openMethod == normal)
2028 if(DontTerminateDebugSession($"Open Project"))
2031 if(MenuWindowCloseAll(null, 0))
2035 projectView.visible = false;
2036 projectView.Destroy(0);
2037 // Where did this come from? projectView = null;
2044 Workspace workspace = null;
2046 if(FileExists(filePath))
2048 if(!strcmp(extension, ProjectExtension))
2050 char workspaceFile[MAX_LOCATION];
2051 strcpy(workspaceFile, filePath);
2052 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2053 workspace = LoadWorkspace(workspaceFile, filePath);
2055 else if(!strcmp(extension, WorkspaceExtension))
2056 workspace = LoadWorkspace(filePath, null);
2059 //project = LoadProject(filePath, null);
2064 char absolutePath[MAX_LOCATION];
2065 CreateProjectView(workspace, filePath);
2066 document = projectView;
2068 workspace.DropInvalidBreakpoints();
2071 ide.projectView.ShowOutputBuildLog(true);
2073 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2074 ide.projectView.DisplayCompiler(compiler, false);
2077 UpdateCompilerConfigs(false);
2080 char newWorkingDir[MAX_LOCATION];
2081 StripLastDirectory(filePath, newWorkingDir);
2082 ChangeFileDialogsDirectory(newWorkingDir, false);
2085 document.fileName = filePath;
2087 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2089 // this crashes on starting ide with epj file, solution please?
2090 // app.UpdateDisplay();
2092 workspace.holdTracking = true;
2093 for(ofi : workspace.openedFiles)
2095 if(ofi.state != closed)
2097 Window file = OpenFile(ofi.path, normal, true, null, no, normal, noParsing);
2100 char fileName[MAX_LOCATION];
2102 GetLastDirectory(ofi.path, fileName);
2103 node = projectView.project.topNode.Find(fileName, true);
2105 node.EnsureVisible();
2109 workspace.holdTracking = false;
2111 workspace.timer.Start();
2113 findInFilesDialog.mode = FindInFilesMode::project;
2114 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2117 char location[MAX_LOCATION];
2118 StripLastDirectory(ide.project.topNode.path, location);
2119 ChangeProjectFileDialogDirectory(location);
2123 if(projectView.debugger)
2124 projectView.debugger.EvaluateWatches();
2131 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2133 ideProjectFileDialog.text = openProjectFileDialogTitle;
2134 if(ideProjectFileDialog.Modal() == cancel)
2136 filePath = ideProjectFileDialog.filePath;
2137 GetExtension(filePath, extension);
2148 else if(openMethod == add)
2153 char slashFilePath[MAX_LOCATION];
2154 GetSlashPathBuffer(slashFilePath, filePath);
2155 for(p : workspace.projects)
2157 if(!fstrcmp(p.filePath, slashFilePath))
2165 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2166 contents = $"This project is already present in workspace." }.Modal();
2170 prj = LoadProject(filePath, null);
2173 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2174 prj.StartMonitoring();
2175 workspace.projects.Add(prj);
2177 projectView.AddNode(prj.topNode, null);
2178 workspace.modified = true;
2180 findInFilesDialog.AddProjectItem(prj);
2181 projectView.ShowOutputBuildLog(true);
2182 projectView.DisplayCompiler(compiler, false);
2183 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2187 char location[MAX_LOCATION];
2188 StripLastDirectory(prj.topNode.path, location);
2189 ChangeProjectFileDialogDirectory(location);
2192 // projectView is associated with the main project and not with the one just added but
2193 return projectView; // just to let the caller know something was opened
2201 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2202 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2203 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2205 if(FileExists(filePath))
2206 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2207 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2208 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2211 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2214 else if(!strcmp(extension, "3ds"))
2216 if(FileExists(filePath))
2217 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2218 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2219 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2223 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2226 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2227 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2228 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2229 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2230 !strcmp(extension, "js"))
2232 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2233 editor.updatingCode = true;
2234 if(editor.LoadFile(filePath))
2237 editor.visible = true;
2241 needFileModified = false;
2245 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2246 if(editor.LoadFile(filePath))
2249 editor.visible = true;
2253 needFileModified = false;
2256 if(document && (document._class == class(PictureEdit) ||
2257 document._class == class(ModelView)))
2262 document.fileName = filePath;
2263 if(workspace && !workspace.holdTracking)
2264 workspace.UpdateOpenedFileInfo(filePath, opened);
2268 if(!document && createIfFails != no)
2270 if(createIfFails != yes && !needFileModified &&
2271 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2272 createIfFails = yes;
2273 if(createIfFails == yes || createIfFails == whatever)
2275 document = (Window)NewCodeEditor(this, state, true);
2277 document.fileName = filePath;
2283 if(projectView && document._class == class(CodeEditor) && workspace)
2285 int lineNumber, position;
2287 CodeEditor editor = (CodeEditor)document;
2288 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2289 editor.openedFileInfo.holdTracking = true;
2290 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2291 position = Max(editor.openedFileInfo.position - 1, 0);
2292 editor.editBox.GoToLineNum(lineNumber);
2293 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2294 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2295 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2296 editor.editBox.scroll = scroll;
2297 editor.openedFileInfo.holdTracking = false;
2300 if(needFileModified)
2301 document.OnFileModified = OnFileModified;
2302 document.NotifySaved = DocumentSaved;
2305 ideSettings.AddRecentProject(document.fileName);
2307 ideSettings.AddRecentFile(document.fileName);
2308 ide.UpdateRecentMenus();
2309 ide.AdjustFileMenus();
2310 settingsContainer.Save();
2318 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2319 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2321 if(!parentClosing && ide.workspace)
2322 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2325 bool ModelView::ModelViewOnClose(bool parentClosing)
2327 if(!parentClosing && ide.workspace)
2328 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2331 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2333 if(!parentClosing && ide.workspace)
2334 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2339 void OnUnloadGraphics(Window window)
2341 display.ClearMaterials();
2342 display.ClearTextures();
2343 display.ClearMeshes();
2347 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2349 caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2350 num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2354 bool OnKeyDown(Key key, unichar ch)
2359 projectView.Update(null);
2362 caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2365 num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2371 void GoToError(const char * line, bool noParsing)
2374 projectView.GoToError(line, noParsing);
2377 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
2380 char *colon = strchr(text, ':');
2381 char filePath[MAX_LOCATION];
2382 char completePath[MAX_LOCATION];
2383 int line = 0, col = 0;
2385 FileAttribs fileAttribs;
2387 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2389 path = (colon - 1 > path) ? colon - 1 : path;
2390 colon = strstr(colon + 1, ":");
2392 while(isspace(*path)) path++;
2395 char * close = strchr(path, ')');
2399 strncpy(name, path+1, close - path - 1);
2400 name[close - path - 1] = '\0';
2401 for(p : ide.workspace.projects)
2403 if(!strcmp(p.name, name))
2413 prj = project ? project : (dir ? null : ide.project);
2416 strncpy(filePath, path, colon - path);
2417 filePath[colon - path] = '\0';
2418 line = atoi(colon + 1);
2419 colon = strstr(colon + 1, ":");
2421 col = atoi(colon + 1);
2423 else if(path - 1 >= text && *(path - 1) == '\"')
2425 colon = strchr(path, '\"');
2428 strncpy(filePath, path, colon - path);
2429 filePath[colon - path] = '\0';
2432 else if(path && !colon)
2434 strcpy(filePath, path);
2438 strcpy(completePath, prj.topNode.path);
2439 else if(dir && dir[0])
2440 strcpy(completePath, dir);
2442 completePath[0] = '\0';
2443 PathCat(completePath, filePath);
2445 fileAttribs = FileExists(completePath);
2446 if(fileAttribs.isFile)
2448 CodeEditor codeEditor = (CodeEditor)OpenFile(completePath, normal, true, "", no, normal, false);
2449 if(codeEditor && line)
2451 EditBox editBox = codeEditor.editBox;
2452 editBox.GoToLineNum(line - 1);
2453 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2456 else if(fileAttribs.isDirectory)
2457 ShellOpen(completePath);
2460 void OnRedraw(Surface surface)
2462 Bitmap bitmap = back.bitmap;
2464 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2467 void SheetSelected(SheetType sheetSelected)
2469 if(activeChild == sheet)
2471 if(sheetSelected == methods)
2473 viewPropertiesItem.accelerator = f4;
2474 viewPropertiesItem.parent = viewMenu;
2475 viewMethodsItem.parent = null;
2479 viewMethodsItem.accelerator = f4;
2480 viewMethodsItem.parent = viewMenu;
2481 viewPropertiesItem.parent = null;
2486 viewMethodsItem.parent = viewMenu;
2487 viewPropertiesItem.parent = viewMenu;
2488 if(sheetSelected == methods)
2490 viewMethodsItem.accelerator = f4;
2491 viewPropertiesItem.accelerator = 0;
2495 viewMethodsItem.accelerator = 0;
2496 viewPropertiesItem.accelerator = f4;
2501 void OnActivateClient(Window client, Window previous)
2503 //if(!client || client != previous)
2506 if(!client || client != previous)
2509 dataType = previous._class;
2510 if(previous && !strcmp(dataType.name, "CodeEditor"))
2512 ((CodeEditor)previous).UpdateFormCode();
2514 else if(previous && !strcmp(dataType.name, "Designer"))
2516 ((Designer)previous).codeEditor.UpdateFormCode();
2521 dataType = client._class;
2522 if(client && !strcmp(dataType.name, "CodeEditor"))
2524 CodeEditor codeEditor = (CodeEditor)client;
2525 SetPrivateModule(codeEditor.privateModule);
2526 SetCurrentContext(codeEditor.globalContext);
2527 SetTopContext(codeEditor.globalContext);
2528 SetGlobalContext(codeEditor.globalContext);
2530 SetDefines(&codeEditor.defines);
2531 SetImports(&codeEditor.imports);
2533 SetActiveDesigner(codeEditor.designer);
2535 sheet.codeEditor = codeEditor;
2536 toolBox.codeEditor = codeEditor;
2538 viewDesignerItem.parent = viewMenu;
2539 if(activeChild != codeEditor)
2541 viewCodeItem.parent = viewMenu;
2542 viewDesignerItem.accelerator = 0;
2543 viewCodeItem.accelerator = f8;
2547 viewCodeItem.parent = null;
2548 viewDesignerItem.accelerator = f8;
2551 else if(client && !strcmp(dataType.name, "Designer"))
2553 CodeEditor codeEditor = ((Designer)client).codeEditor;
2556 SetPrivateModule(codeEditor.privateModule);
2557 SetCurrentContext(codeEditor.globalContext);
2558 SetTopContext(codeEditor.globalContext);
2559 SetGlobalContext(codeEditor.globalContext);
2560 SetDefines(&codeEditor.defines);
2561 SetImports(&codeEditor.imports);
2565 SetPrivateModule(null);
2566 SetCurrentContext(null);
2567 SetTopContext(null);
2568 SetGlobalContext(null);
2573 SetActiveDesigner((Designer)client);
2575 sheet.codeEditor = codeEditor;
2576 toolBox.codeEditor = codeEditor;
2578 viewCodeItem.parent = viewMenu;
2579 if(activeChild != client)
2581 viewDesignerItem.parent = viewMenu;
2582 viewDesignerItem.accelerator = f8;
2583 viewCodeItem.accelerator = 0;
2587 viewDesignerItem.parent = null;
2588 viewCodeItem.accelerator = f8;
2594 sheet.codeEditor = null;
2595 toolBox.codeEditor = null;
2596 SetActiveDesigner(null);
2598 viewDesignerItem.parent = null;
2599 viewCodeItem.parent = null;
2602 SheetSelected(sheet.sheetSelected);
2605 projectCompileItem = null;
2610 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
2612 CodeEditor codeEditor = (CodeEditor)client;
2613 EditBox editBox = codeEditor.editBox;
2615 statusBar.AddField(pos);
2617 caps = { width = 40, text = $"CAPS", color = app.GetKeyState(capsState) ? black : Color { 128, 128, 128 } };
2618 statusBar.AddField(caps);
2620 ovr = { width = 30, text = $"OVR", color = (editBox && editBox.overwrite) ? black : Color { 128, 128, 128 } };
2621 statusBar.AddField(ovr);
2623 num = { width = 30, text = $"NUM", color = app.GetKeyState(numState) ? black : Color { 128, 128, 128 } };
2624 statusBar.AddField(num);
2626 //statusBar.text = "Ready";
2628 if(projectView && projectView.project)
2630 bool isCObject = false;
2631 ProjectNode node = projectView.GetNodeFromWindow(client, null, false);
2632 if(!node && (node = projectView.GetNodeFromWindow(client, null, true)))
2636 char nodeName[MAX_FILENAME];
2637 char name[MAX_FILENAME+96];
2639 ChangeExtension(node.name, "c", nodeName);
2640 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
2641 projectCompileItem =
2643 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
2645 bool NotifySelect(MenuItem selection, Modifiers mods)
2649 bool result = false;
2650 bool isCObject = false;
2651 ProjectNode node = null;
2652 for(p : ide.workspace.projects)
2654 node = projectView.GetNodeFromWindow(activeClient, p, false);
2657 if(!node && (node = projectView.GetNodeFromWindow(activeClient, null, true)))
2661 List<ProjectNode> nodes { };
2663 projectView.Compile(node.project, nodes, mods.ctrl && mods.shift, isCObject ? cObject : normal);
2668 ide.outputView.buildBox.Logf($"File %s is excluded from current build configuration.\n", node.name);
2673 projectMenu.AddDynamic(projectCompileItem, ide, false);
2679 caps = ovr = num = null;
2684 bool OnClose(bool parentClosing)
2686 //return !projectView.buildInProgress;
2687 if(projectView && projectView.buildInProgress)
2689 if(DontTerminateDebugSession($"Close IDE"))
2691 if(findInFilesDialog)
2692 findInFilesDialog.SearchStop();
2695 workspace.timer.Stop();
2698 ideMainFrame.Destroy(0);
2705 bool passThrough = false;
2706 bool debugStart = false;
2707 bool debugWorkDir = false;
2708 char * passDebugWorkDir = null;
2709 bool openAsText = false;
2710 DynamicString passArgs { };
2711 for(c = 1; c<app.argc; c++)
2713 if(!strcmp(app.argv[c], "-t"))
2715 else if(!strcmp(app.argv[c], "-no-parsing"))
2716 ide.noParsing = true;
2717 else if(!strcmp(app.argv[c], "-debug-start"))
2719 else if(!strcmp(app.argv[c], "-debug-work-dir"))
2720 debugWorkDir = true;
2721 else if(!passThrough && !strcmp(app.argv[c], "-@"))
2723 else if(passThrough)
2725 passArgs.concat(" ");
2726 passArgs.concat(app.argv[c]);
2728 else if(debugWorkDir)
2730 passDebugWorkDir = CopyString(app.argv[c]);
2731 StripQuotes(passDebugWorkDir, passDebugWorkDir);
2732 debugWorkDir = false;
2736 char fullPath[MAX_LOCATION];
2737 char parentPath[MAX_LOCATION];
2738 char ext[MAX_EXTENSION];
2740 FileAttribs dirAttribs;
2741 GetWorkingDir(fullPath, MAX_LOCATION);
2742 PathCat(fullPath, app.argv[c]);
2743 StripLastDirectory(fullPath, parentPath);
2744 GetExtension(app.argv[c], ext);
2745 isProject = !openAsText && !strcmpi(ext, "epj");
2747 if(isProject && c > (debugStart ? 2 : 1)) continue;
2749 // Create directory for projects (only)
2750 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
2752 if(isProject && !FileExists(fullPath))
2754 // The NewProject will handle directory creation
2755 /*if(!dirAttribs.isDirectory)
2757 MakeDir(parentPath);
2758 dirAttribs = FileExists(parentPath);
2760 if(dirAttribs.isDirectory)*/
2762 char name[MAX_LOCATION];
2763 NewProjectDialog newProjectDialog;
2767 projectView.visible = false;
2768 if(!projectView.Destroy(0))
2772 newProjectDialog = { master = this };
2774 strcpy(name, app.argv[c]);
2775 StripExtension(name);
2776 GetLastDirectory(name, name);
2777 newProjectDialog.projectName.contents = name;
2778 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
2779 newProjectDialog.locationEditBox.path = parentPath;
2780 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
2782 newProjectDialog.Modal();
2785 ideSettings.AddRecentProject(projectView.fileName);
2786 ide.UpdateRecentMenus();
2787 settingsContainer.Save();
2790 // Open only one project
2794 ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, openAsText ? "txt" : null, yes, normal, false);
2796 else if(strstr(fullPath, "http://") == fullPath)
2797 ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, openAsText ? "txt" : null, yes, normal, false);
2800 if(passThrough && projectView && projectView.project && workspace)
2802 char * fixSpacing = new char[Max(passArgs.size * 1.5, 32)];
2808 bool inQuote = false;
2809 for(c=0; c<passArgs.size; c++)
2812 if(inQuote && k != '\\' && l == ' ')
2814 fixSpacing[d++] = '\"';
2815 fixSpacing[d++] = ' ';
2818 else if(inQuote && l == '\0')
2820 fixSpacing[d++] = '\"';
2821 fixSpacing[d++] = '\0';
2824 else if(!inQuote && j != '\\' && k == ' ' && l != '-' && l != ' ')
2826 fixSpacing[d++] = '\"';
2827 fixSpacing[d++] = l;
2830 else if(k == '\\' && l == ' ')
2831 fixSpacing[d++] = ' ';
2832 else if(k == '\\' && l == '\\')
2833 fixSpacing[d++] = '\\';
2835 fixSpacing[d++] = l;
2839 fixSpacing[d] = '\0';
2841 workspace.commandLineArgs = fixSpacing;
2843 if(passDebugWorkDir)
2845 workspace.debugDir = passDebugWorkDir;
2846 delete passDebugWorkDir;
2849 ;//MenuDebugStart(debugStartResumeItem, 0); // <-- how TODO this without getting into the app.Wait lock
2851 UpdateToolBarActiveConfigs(false);
2852 UpdateToolBarActiveCompilers();
2859 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
2862 projectView.visible = false;
2863 projectView.Destroy(0);
2866 #ifdef GDB_DEBUG_GUI
2867 gdbDialog.Destroy(0);
2872 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
2876 char * oldPaths[128];
2877 String oldList = new char[maxPathLen];
2878 Array<String> newExePaths { };
2879 //Map<String, bool> exePathExists { };
2881 #if defined(__unix__) || defined(__APPLE__)
2882 Array<String> newLibPaths { };
2883 Map<String, bool> libPathExists { };
2888 for(prj : workspace.projects)
2890 DirExpression targetDirExp;
2892 // SKIP FIRST PROJECT...
2893 if(prj == workspace.projects.firstIterator.data) continue;
2895 // NOTE: Right now the additional project config dir will be
2896 // obtained when the debugger is started, so toggling it
2897 // while building will change which library gets used.
2898 // To go with the initial state, e.g. when F5 was pressed,
2899 // we nould need to keep a list of all project's active
2900 // config upon startup.
2901 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
2903 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
2907 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2908 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
2912 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
2913 if(cfg.targetType == sharedLibrary && cfg.debug)
2917 if(targetDirExp.dir)
2919 char buffer[MAX_LOCATION];
2920 #if defined(__WIN32__)
2921 Array<String> paths = newExePaths;
2923 Array<String> paths = newLibPaths;
2925 GetSystemPathBuffer(buffer, prj.topNode.path);
2926 PathCat(buffer, targetDirExp.dir);
2929 if(!fstrcmp(p, buffer))
2936 paths.Add(CopyString(buffer));
2938 delete targetDirExp;
2942 for(item : compiler.executableDirs)
2945 for(p : newExePaths)
2947 if(!fstrcmp(p, item))
2954 newExePaths.Add(CopySystemPath(item));
2957 GetEnvironment("PATH", oldList, maxPathLen);
2959 printf("Old value of PATH: %s\n", oldList);
2961 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
2962 for(c = 0; c < count; c++)
2965 for(p : newExePaths)
2967 if(!fstrcmp(p, oldPaths[c]))
2974 newExePaths.Add(CopySystemPath(oldPaths[c]));
2978 for(path : newExePaths)
2979 len += strlen(path) + 1;
2980 newList = new char[len + 1];
2982 for(path : newExePaths)
2984 strcat(newList, path);
2985 strcat(newList, pathListSep);
2987 newList[len - 1] = '\0';
2988 SetEnvironment("PATH", newList);
2990 printf("New value of PATH: %s\n", newList);
2997 #if defined(__unix__) || defined(__APPLE__)
2999 for(item : compiler.libraryDirs)
3001 if(!libPathExists[item]) // fstrcmp should be used
3003 newLibPaths.Add(item);
3004 libPathExists[item] = true;
3008 #if defined(__APPLE__)
3009 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3011 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3014 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3016 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3017 for(c = 0; c < count; c++)
3019 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3021 newLibPaths.Add(oldPaths[c]);
3022 libPathExists[oldPaths[c]] = true;
3027 for(path : newLibPaths)
3028 len += strlen(path) + 1;
3029 newList = new char[len + 1];
3031 for(path : newLibPaths)
3033 strcat(newList, path);
3034 strcat(newList, pathListSep);
3036 newList[len - 1] = '\0';
3037 #if defined(__APPLE__)
3038 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3040 SetEnvironment("LD_LIBRARY_PATH", newList);
3043 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3048 delete libPathExists;
3051 if(compiler.distccEnabled && compiler.distccHosts)
3052 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3057 void DestroyTemporaryProjectDir()
3059 if(tmpPrjDir && tmpPrjDir[0])
3061 if(FileExists(tmpPrjDir).isDirectory)
3062 DestroyDir(tmpPrjDir);
3063 property::tmpPrjDir = null;
3069 // Graphics Driver Menu
3073 app.currentSkin.selectionColor = selectionColor;
3074 app.currentSkin.selectionText = selectionText;
3078 driverItems = new MenuItem[app.numDrivers];
3079 for(c = 0; c < app.numDrivers; c++)
3081 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3082 driverItems[c].id = c;
3083 driverItems[c].isRadio = true;
3086 driverItems = new MenuItem[2];
3087 #if defined(__unix__)
3088 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3089 driverItems[0].id = 0;
3090 driverItems[0].isRadio = true;
3092 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3093 driverItems[0].id = 0;
3094 driverItems[0].isRadio = true;
3096 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3097 driverItems[1].id = 1;
3098 driverItems[1].isRadio = true;
3100 /* skinItems = new MenuItem[app.numSkins];
3101 for(c = 0; c < app.numSkins; c++)
3103 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3104 skinItems[c].id = c;
3105 skinItems[c].isRadio = true;
3108 ideFileDialog.master = this;
3109 ideProjectFileDialog.master = this;
3111 //SetDriverAndSkin();
3115 void UpdateRecentMenus()
3118 Menu fileMenu = menu.FindMenu($"File");
3119 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3120 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3121 char * itemPath = new char[MAX_LOCATION];
3122 char * itemName = new char[MAX_LOCATION+4];
3125 recentFiles.Clear();
3128 for(recent : ideSettings.recentFiles)
3130 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3131 MakeSystemPath(itemPath);
3132 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3133 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3137 recentProjects.Clear();
3139 for(recent : ideSettings.recentProjects)
3141 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3142 MakeSystemPath(itemPath);
3143 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3144 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3160 void DestroyDir(char * path)
3162 RecursiveDeleteFolderFSI fsi { };
3167 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3169 bool preserveRootFolder;
3171 void OutFolder(char * folderPath, bool isRoot)
3173 if(!(preserveRootFolder && isRoot))
3174 RemoveDir(folderPath);
3177 bool OnFile(char * filePath)
3179 DeleteFile(filePath);
3184 class IDEApp : GuiApplication
3186 //driver = "Win32Console";
3187 // driver = "OpenGL";
3191 TempFile includeFile { };
3195 SetLoggingMode(stdOut, null);
3196 //SetLoggingMode(debug, null);
3198 settingsContainer.Load();
3199 #if defined(__unix__) || defined(__APPLE__)
3200 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3202 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3204 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3208 desktop.text = titleECEREIDE;
3211 for(c = 1; c<app.argc; c++)
3213 char fullPath[MAX_LOCATION];
3214 GetWorkingDir(fullPath, MAX_LOCATION);
3215 PathCat(fullPath, app.argv[c]);
3216 ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal, false);
3220 if(!LoadIncludeFile())
3221 PrintLn("error: unable to load :crossplatform.mk file inside ide binary.");
3226 bool LoadIncludeFile()
3228 bool result = false;
3229 File include = FileOpen(":crossplatform.mk", read);
3232 File f = includeFile;
3235 for(; !include.Eof(); )
3238 int count = include.Read(buffer, 1, 4096);
3239 f.Write(buffer, 1, count);
3249 IDEMainFrame ideMainFrame { };
3251 define app = ((IDEApp)__thisModule);
3253 define titleECEREIDE = $"ECERE IDE (Debug)";
3255 define titleECEREIDE = $"ECERE IDE";