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 OnClose(bool parentClosing)
473 ide.RepositionWindows(false);
474 return parentClosing;
478 CallStackView callStackView
480 parent = this, font = { panelFont.faceName, panelFont.size };
482 void OnSelectFrame(int frameIndex)
484 ide.debugger.GoToStackFrameLine(frameIndex, true);
486 ide.debugger.SelectFrame(frameIndex);
489 void OnToggleBreakpoint()
491 Debugger debugger = ide.debugger;
492 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
494 int line = debugger.activeFrame.line;
495 char name[MAX_LOCATION];
497 // TOFIX: Improve on this, don't use only filename, make a function
498 GetLastDirectory(debugger.activeFrame.absoluteFile, name);
499 if(ide && ide.workspace)
501 for(p : ide.workspace.projects)
503 if(p.topNode.Find(name, false))
511 for(p : ide.workspace.projects)
513 if(IsPathInsideOf(debugger.activeFrame.absoluteFile, p.topNode.path))
521 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line, prj);
524 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
525 if(codeEditor) { codeEditor.Update(null); Activate(); }
530 bool OnKeyDown(Key key, unichar ch)
534 case escape: ide.ShowCodeEditor(); break;
539 bool OnClose(bool parentClosing)
543 ide.RepositionWindows(false);
544 return parentClosing;
547 void OnRedraw(Surface surface)
549 Debugger debugger = ide.debugger;
550 Frame activeFrame = debugger.activeFrame;
554 int lineCursor, lineTopFrame, activeThread, hitThread;
555 int lineH, scrollY, boxH;
557 Breakpoint bp = null;
560 scrollY = editBox.scroll.y;
561 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
562 activeThread = debugger.activeThread;
563 hitThread = debugger.hitThread;
564 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
566 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
567 if(activeFrame.absoluteFile)
569 for(i : ide.workspace.breakpoints; i.type == user)
571 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
572 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
573 activeFrame.line == i.line)
581 DrawLineMarginIcon(surface,
582 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
583 lineCursor /*1*/, lineH, scrollY, boxH);
585 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
586 DrawLineMarginIcon(surface,
587 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
588 1, lineH, scrollY, boxH);
590 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
591 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
592 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
594 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
595 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
597 if(editBox.horzScroll && editBox.horzScroll.visible)
599 surface.SetBackground(control);
600 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
605 WatchesView watchesView { parent = this };
606 ThreadsView threadsView
608 parent = this, font = { panelFont.faceName, panelFont.size };
610 bool OnKeyDown(Key key, unichar ch)
614 case escape: ide.ShowCodeEditor(); break;
619 bool OnClose(bool parentClosing)
623 ide.RepositionWindows(false);
624 return parentClosing;
627 void OnSelectThread(int threadId)
630 ide.debugger.SelectThread(threadId);
633 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
636 Debugger debugger = ide.debugger;
637 *activeThread = debugger.activeThread;
638 *hitThread = debugger.hitThread;
639 *signalThread = debugger.signalThread;
644 BreakpointsView breakpointsView { parent = this };
646 ToolBox toolBox { parent = this };
647 Sheet sheet { parent = this };
650 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
652 Menu fileMenu { menu, $"File", f, hasMargin = true };
655 fileMenu, $"New", n, ctrlN;
656 bitmap = { ":actions/docNew.png" };
657 bool NotifySelect(MenuItem selection, Modifiers mods)
659 Window document = (Window)NewCodeEditor(this, normal, false);
660 document.NotifySaved = DocumentSaved;
664 MenuItem fileOpenItem
666 fileMenu, $"Open...", o, ctrlO;
667 bitmap = { ":actions/docOpen.png" };
668 bool NotifySelect(MenuItem selection, Modifiers mods)
670 if(!projectView && ideSettings.ideFileDialogLocation)
671 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
674 if(ideFileDialog.Modal() == ok)
676 bool gotWhatWeWant = false;
678 int numSelections = ideFileDialog.numSelections;
679 char ** multiFilePaths = ideFileDialog.multiFilePaths;
681 for(c = 0; c < numSelections; c++)
683 if(OpenFile(multiFilePaths[c], normal, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
684 gotWhatWeWant = true;
687 MessageBox { type = yesNo, master = this, text = $"Error opening file",
688 contents = $"Open a different file?" }.Modal() == no)
690 if(!projectView && gotWhatWeWant)
691 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
692 ide.RepositionWindows(false);
702 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
703 MenuDivider { fileMenu };
704 MenuItem fileSaveItem
706 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
708 // For the toolbar button; clients can still override that for the menu item
709 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
711 Window w = activeClient;
713 w.MenuFileSave(null, 0);
717 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
718 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
719 MenuDivider { fileMenu };
722 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
723 bool NotifySelect(MenuItem selection, Modifiers mods)
725 findInFilesDialog.replaceMode = false;
726 findInFilesDialog.Show();
730 MenuItem replaceInFiles
732 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
733 bool NotifySelect(MenuItem selection, Modifiers mods)
735 findInFilesDialog.replaceMode = true;
736 findInFilesDialog.Show();
740 MenuDivider { fileMenu };
741 MenuItem globalSettingsItem
743 fileMenu, $"Global Settings...", g;
744 bool NotifySelect(MenuItem selection, Modifiers mods)
746 globalSettingsDialog.master = this;
747 if(ide.workspace && ide.workspace.compiler)
748 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.compiler;
749 else if(ideSettings.defaultCompiler)
750 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
751 globalSettingsDialog.Modal();
755 MenuDivider { fileMenu };
756 Menu recentFiles { fileMenu, $"Recent Files", r };
757 Menu recentProjects { fileMenu, $"Recent Projects", p };
758 MenuDivider { fileMenu };
761 fileMenu, $"Exit", x, altF4;
763 bool NotifySelect(MenuItem selection, Modifiers mods)
765 ideMainFrame.Destroy(0);
770 bool FileRecentFile(MenuItem selection, Modifiers mods)
773 for(file : ideSettings.recentFiles)
775 if(id == selection.id)
778 char extension[MAX_EXTENSION] = "";
779 GetExtension(file, extension);
780 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
783 char * command = PrintString("ide ", isProjectFile ? "-t " : "", file);
789 OpenFile(file, normal, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
790 ide.RepositionWindows(false);
799 bool FileRecentProject(MenuItem selection, Modifiers mods)
802 for(file : ideSettings.recentProjects)
804 if(id == selection.id)
808 char * command = PrintString("ide ", file);
813 OpenFile(file, normal, true, null, no, normal, mods.ctrl && mods.shift);
821 MenuPlacement editMenu { menu, $"Edit", e };
823 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
824 MenuItem projectNewItem
826 projectMenu, $"New...", n, Key { n, true, true };
827 bitmap = { ":actions/projNew.png" };
828 bool NotifySelect(MenuItem selection, Modifiers mods)
830 if(!DontTerminateDebugSession($"New Project"))
833 NewProjectDialog newProjectDialog { master = this };
834 result = newProjectDialog.Modal();
839 newProjectDialog.CreateNewProject();
842 ideSettings.AddRecentProject(projectView.fileName);
843 ide.UpdateRecentMenus();
844 settingsContainer.Save();
852 MenuItem projectOpenItem
854 projectMenu, $"Open...", o, Key { o, true, true };
855 bitmap = { ":actions/projOpen.png" };
856 bool NotifySelect(MenuItem selection, Modifiers mods)
858 if(ideSettings.ideProjectFileDialogLocation)
859 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
861 ideProjectFileDialog.text = openProjectFileDialogTitle;
862 if(ideProjectFileDialog.Modal() == ok)
864 OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
865 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
870 MenuItem projectQuickItem
872 projectMenu, $"Quick...", q, f7, disabled = true;
873 bool NotifySelect(MenuItem selection, Modifiers mods)
876 QuickProjectDialog { this }.Modal();
880 MenuItem projectAddItem
882 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
883 bitmap = { ":actions/projAdd.png" };
885 bool NotifySelect(MenuItem selection, Modifiers mods)
887 if(ideSettings.ideProjectFileDialogLocation)
888 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
890 ideProjectFileDialog.text = addProjectFileDialogTitle;
893 if(ideProjectFileDialog.Modal() == ok)
895 if(OpenFile(ideProjectFileDialog.filePath, normal, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
897 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
898 contents = $"Add a different project?" }.Modal() == no)
909 MenuItem projectCloseItem
911 projectMenu, $"Close", c, disabled = true;
912 bool NotifySelect(MenuItem selection, Modifiers mods)
916 if(!ide.DontTerminateDebugSession($"Project Close"))
922 MenuDivider { projectMenu };
923 MenuItem projectSettingsItem
925 projectMenu, $"Settings...", s, altF7, disabled = true;
926 bool NotifySelect(MenuItem selection, Modifiers mods)
928 projectView.MenuSettings(projectView.active ? selection : null, mods);
932 MenuDivider { projectMenu };
933 MenuItem projectBrowseFolderItem
935 projectMenu, $"Browse Project Folder", p, disabled = true;
936 bool NotifySelect(MenuItem selection, Modifiers mods)
939 projectView.MenuBrowseFolder(null, mods);
943 MenuDivider { projectMenu };
944 MenuItem projectRunItem
946 projectMenu, $"Run", r, ctrlF5, disabled = true;
947 bitmap = { ":actions/run.png" };
948 bool NotifySelect(MenuItem selection, Modifiers mods)
951 projectView.Run(null, mods);
955 MenuItem projectBuildItem
957 projectMenu, $"Build", b, f7, disabled = true;
958 bitmap = { ":actions/build.png" };
959 bool NotifySelect(MenuItem selection, Modifiers mods)
963 if(projectView.buildInProgress == none)
964 projectView.ProjectBuild(projectView.active ? selection : null, mods);
966 projectView.stopBuild = true;
971 MenuItem projectLinkItem
973 projectMenu, $"Relink", l, disabled = true;
974 bitmap = { ":actions/relink.png" };
975 bool NotifySelect(MenuItem selection, Modifiers mods)
978 projectView.ProjectLink(projectView.active ? selection : null, mods);
982 MenuItem projectRebuildItem
984 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
985 bitmap = { ":actions/rebuild.png" };
986 bool NotifySelect(MenuItem selection, Modifiers mods)
989 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
993 MenuItem projectCleanTargetItem
995 projectMenu, $"Clean Target", g, disabled = true;
996 bitmap = { ":actions/clean.png" };
997 bool NotifySelect(MenuItem selection, Modifiers mods)
1002 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
1007 MenuItem projectCleanItem
1009 projectMenu, $"Clean", e, disabled = true;
1010 bitmap = { ":actions/clean.png" };
1011 bool NotifySelect(MenuItem selection, Modifiers mods)
1016 projectView.ProjectClean(projectView.active ? selection : null, mods);
1021 MenuItem projectRealCleanItem
1023 projectMenu, $"Real Clean", disabled = true;
1024 bitmap = { ":actions/clean.png" };
1025 bool NotifySelect(MenuItem selection, Modifiers mods)
1030 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1035 MenuItem projectRegenerateItem
1037 projectMenu, $"Regenerate Makefile", m, disabled = true;
1038 bitmap = { ":actions/regMakefile.png" };
1039 bool NotifySelect(MenuItem selection, Modifiers mods)
1042 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1046 MenuItem projectCompileItem;
1047 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1048 MenuItem debugStartResumeItem
1050 debugMenu, $"Start", s, f5, disabled = true;
1051 bitmap = { ":actions/debug.png" };
1052 NotifySelect = MenuDebugStart;
1054 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1058 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1059 if(!projectView.DebugStart())
1060 debugStartResumeItem.disabled = false; // same exception
1064 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1067 projectView.DebugResume();
1070 MenuItem debugRestartItem
1072 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1073 bitmap = { ":actions/restart.png" };
1074 bool NotifySelect(MenuItem selection, Modifiers mods)
1077 projectView.DebugRestart();
1081 MenuItem debugBreakItem
1083 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1084 bitmap = { ":actions/pause.png" };
1085 bool NotifySelect(MenuItem selection, Modifiers mods)
1087 if(projectView && projectView.buildInProgress != none)
1090 projectView.DebugBreak();
1094 MenuItem debugStopItem
1096 debugMenu, $"Stop", p, shiftF5, disabled = true;
1097 bitmap = { ":actions/stopDebug.png" };
1098 bool NotifySelect(MenuItem selection, Modifiers mods)
1101 projectView.DebugStop();
1105 MenuDivider { debugMenu };
1106 MenuItem debugStepIntoItem
1108 debugMenu, $"Step Into", i, f11, disabled = true;
1109 bitmap = { ":actions/stepInto.png" };
1110 bool NotifySelect(MenuItem selection, Modifiers mods)
1113 projectView.DebugStepInto();
1117 MenuItem debugStepOverItem
1119 debugMenu, $"Step Over", v, f10, disabled = true;
1120 bitmap = { ":actions/stepOver.png" };
1121 bool NotifySelect(MenuItem selection, Modifiers mods)
1124 projectView.DebugStepOver(false);
1128 MenuItem debugStepOutItem
1130 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1131 bitmap = { ":actions/stepOut.png" };
1132 bool NotifySelect(MenuItem selection, Modifiers mods)
1135 projectView.DebugStepOut(false);
1139 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1140 MenuItem debugSkipStepOverItem
1142 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1143 bool NotifySelect(MenuItem selection, Modifiers mods)
1146 projectView.DebugStepOver(true);
1150 MenuItem debugSkipStepOutItem
1152 debugMenu, $"Step Out Skipping Breakpoints", t, Key { f11, ctrl = true, shift = true }, disabled = true;
1153 bitmap = { ":actions/skipBreaks.png" };
1154 bool NotifySelect(MenuItem selection, Modifiers mods)
1157 projectView.DebugStepOut(true);
1161 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1162 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", s };
1163 //MenuDivider { debugMenu };
1164 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1165 MenuPlacement imageMenu { menu, $"Image", i };
1166 Menu viewMenu { menu, $"View", v };
1167 MenuItem viewProjectItem
1169 viewMenu, $"Project View", j, alt0, disabled = true;
1170 bool NotifySelect(MenuItem selection, Modifiers mods)
1174 projectView.visible = true;
1175 projectView.Activate();
1180 MenuPlacement { viewMenu, $"View Designer" };
1181 MenuPlacement { viewMenu, $"View Code" };
1182 MenuPlacement { viewMenu, $"View Properties" };
1183 MenuPlacement { viewMenu, $"View Methods" };
1184 MenuItem viewDesignerItem
1186 viewMenu, $"View Designer", d, f8;
1187 bool NotifySelect(MenuItem selection, Modifiers mods)
1189 Window client = activeClient;
1190 Class dataType = client._class;
1191 if(!strcmp(dataType.name, "Designer"))
1193 client.visible = true;
1197 ((CodeEditor)client).ViewDesigner();
1201 MenuItem viewCodeItem
1203 viewMenu, $"View Code", c, f8;
1204 bool NotifySelect(MenuItem selection, Modifiers mods)
1206 Window client = activeClient;
1207 Class dataType = client._class;
1208 if(!strcmp(dataType.name, "Designer"))
1209 client = ((Designer)client).codeEditor;
1212 // Do this after so the caret isn't moved yet...
1213 client.visible = true;
1217 MenuItem viewPropertiesItem
1219 viewMenu, $"View Properties", p, f4;
1220 bool NotifySelect(MenuItem selection, Modifiers mods)
1222 sheet.visible = true;
1223 sheet.sheetSelected = properties;
1228 MenuItem viewMethodsItem
1230 viewMenu, $"View Methods", m, f4;
1231 bool NotifySelect(MenuItem selection, Modifiers mods)
1233 sheet.visible = true;
1234 sheet.sheetSelected = methods;
1239 MenuItem viewToolBoxItem
1241 viewMenu, $"View Toolbox", x, f12;
1242 bool NotifySelect(MenuItem selection, Modifiers mods)
1244 toolBox.visible = true;
1249 MenuItem viewOutputItem
1251 viewMenu, $"Output", o, alt2;
1252 bool NotifySelect(MenuItem selection, Modifiers mods)
1258 MenuItem viewWatchesItem
1260 viewMenu, $"Watches", w, alt3;
1261 bool NotifySelect(MenuItem selection, Modifiers mods)
1267 MenuItem viewThreadsItem
1269 viewMenu, $"Threads", t, alt4;
1270 bool NotifySelect(MenuItem selection, Modifiers mods)
1276 MenuItem viewBreakpointsItem
1278 viewMenu, $"Breakpoints", b, alt5;
1279 bool NotifySelect(MenuItem selection, Modifiers mods)
1281 breakpointsView.Show();
1285 MenuItem viewCallStackItem
1287 viewMenu, $"Call Stack", s, alt7;
1288 bool NotifySelect(MenuItem selection, Modifiers mods)
1290 callStackView.Show();
1294 MenuItem viewAllDebugViews
1296 viewMenu, $"All Debug Views", a, alt9;
1297 bool NotifySelect(MenuItem selection, Modifiers mods)
1302 callStackView.Show();
1303 breakpointsView.Show();
1307 #ifdef GDB_DEBUG_GUI
1308 MenuDivider { viewMenu };
1309 MenuItem viewGDBItem
1311 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1312 bool NotifySelect(MenuItem selection, Modifiers mods)
1319 MenuDivider { viewMenu };
1320 MenuItem viewColorPicker
1322 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1323 bool NotifySelect(MenuItem selection, Modifiers mods)
1325 ColorPicker colorPicker { master = this };
1326 colorPicker.Modal();
1330 MenuDivider { viewMenu };
1334 viewMenu, "Full Screen", f, checkable = true;
1336 bool NotifySelect(MenuItem selection, Modifiers mods)
1338 app.fullScreen ^= true;
1340 anchor = { 0, 0, 0, 0 };
1345 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1346 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1347 Menu windowMenu { menu, $"Window", w };
1348 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1349 MenuDivider { windowMenu };
1350 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1351 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1352 MenuDivider { windowMenu };
1353 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1354 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1355 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1356 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1357 MenuDivider { windowMenu };
1358 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1359 Menu helpMenu { menu, $"Help", h };
1362 helpMenu, $"API Reference", r, f1;
1363 bool NotifySelect(MenuItem selection, Modifiers mods)
1365 char * p = new char[MAX_LOCATION];
1367 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1368 PathCat(p, "documentor");
1369 #if defined(__WIN32__)
1370 ChangeExtension(p, "exe", p);
1372 if(FileExists(p).isFile)
1375 Execute("documentor");
1380 MenuDivider { helpMenu };
1383 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1384 bool NotifySelect(MenuItem selection, Modifiers mods)
1386 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1390 MenuDivider { helpMenu };
1393 helpMenu, $"Documentation Folder", d;
1394 bool NotifySelect(MenuItem selection, Modifiers mods)
1396 FindAndShellOpenInstalledFolder("doc");
1402 helpMenu, $"Samples Folder", s;
1403 bool NotifySelect(MenuItem selection, Modifiers mods)
1405 FindAndShellOpenInstalledFolder("samples");
1411 helpMenu, $"Extras Folder", x;
1412 bool NotifySelect(MenuItem selection, Modifiers mods)
1414 FindAndShellOpenInstalledFolder("extras");
1418 MenuDivider { helpMenu };
1421 helpMenu, $"Community Forums", f;
1422 bool NotifySelect(MenuItem selection, Modifiers mods)
1424 ShellOpen("http://ecere.com/forums");
1428 MenuDivider { helpMenu };
1431 helpMenu, $"About...", a;
1432 bool NotifySelect(MenuItem selection, Modifiers mods)
1434 AboutIDE { master = this }.Modal();
1439 property ToolBox toolBox
1441 get { return toolBox; }
1444 property Sheet sheet
1446 get { return sheet; }
1449 property Project project
1451 get { return projectView ? projectView.project : null; }
1454 property Workspace workspace
1456 get { return projectView ? projectView.workspace : null; }
1459 FindInFilesDialog findInFilesDialog
1462 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1468 #ifdef GDB_DEBUG_GUI
1471 master = this, parent = this;
1472 anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1474 void OnCommand(char * string)
1477 ide.debugger.SendGDBCommand(string);
1482 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1484 //app.driver = app.drivers[selection.id];
1485 #if defined(__unix__) || defined(__APPLE__)
1486 app.driver = selection.id ? "OpenGL" : "X";
1488 app.driver = selection.id ? "OpenGL" : "GDI";
1490 delete ideSettings.displayDriver;
1491 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1493 settingsContainer.Save();
1494 //SetDriverAndSkin();
1498 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1500 app.skin = app.skins[selection.id];
1505 void SetDriverAndSkin()
1508 for(c = 0; c < app.numSkins; c++)
1509 if(!strcmp(app.skins[c], app.skin))
1511 skinItems[c].checked = true;
1514 for(c = 0; c < app.numDrivers; c++)
1515 if(!strcmp(app.drivers[c], app.driver))
1517 driverItems[c].checked = true;
1522 ProjectView CreateProjectView(Workspace workspace, char * fileName)
1524 Project project = workspace.projects.firstIterator.data;
1525 projectView = ProjectView
1528 fileName = fileName;
1530 void NotifyDestroyed(Window window, DialogResult result)
1533 text = titleECEREIDE;
1538 projectView.Create();
1539 RepositionWindows(false);
1541 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1542 projectView.workspace = workspace;
1543 projectView.project = project;
1544 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1548 ide.breakpointsView.LoadFromWorkspace();
1549 ide.watchesView.LoadFromWorkspace();
1551 findInFilesDialog.projectNodeField.userData = projectView;
1554 char fileName[MAX_LOCATION];
1555 strcpy(fileName, project.topNode.path);
1556 PathCat(fileName, project.topNode.name);
1563 projectView.visible = false;
1564 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1566 if(findInFilesDialog)
1568 char workingDir[MAX_LOCATION];
1569 GetWorkingDir(workingDir, MAX_LOCATION);
1570 findInFilesDialog.SearchStop();
1571 findInFilesDialog.currentDirectory = workingDir;
1573 ideMainFrame.text = titleECEREIDE;
1580 void RepositionWindows(bool expand)
1585 bool inDebugMode = debugger.isActive;
1586 bool callStackVisible = expand ? false : callStackView.visible;
1587 bool threadsVisible = expand ? false : threadsView.visible;
1588 bool watchesVisible = expand ? false : watchesView.visible;
1589 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1590 bool toolBoxVisible = toolBox.visible;
1591 bool outputVisible = expand ? false : outputView.visible;
1592 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1593 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1595 for(child = firstChild; child; child = child.next)
1597 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1598 child._class == class(Sheet) || child._class == class(ProjectView))
1600 Anchor anchor = child.anchor;
1601 anchor.top = topDistance;
1602 anchor.bottom = bottomDistance;
1603 if(child._class == class(CodeEditor) || child._class == class(Designer))
1606 anchor.right = toolBoxVisible ? 150 : 0;
1608 child.anchor = anchor;
1612 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1613 child._class == class(BreakpointsView))
1614 child.visible = false;
1617 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1622 bool ShowCodeEditor()
1625 activeClient.Activate();
1626 else if(projectView)
1628 projectView.visible = true;
1629 projectView.Activate();
1633 sheet.visible = true;
1639 void DocumentSaved(Window document, char * fileName)
1641 ideSettings.AddRecentFile(fileName);
1642 ide.UpdateRecentMenus();
1643 ide.AdjustFileMenus();
1644 settingsContainer.Save();
1647 bool Window::OnFileModified(FileChange fileChange, char * param)
1650 sprintf(temp, $"The document %s was modified by another application.\n"
1651 "Would you like to reload it and lose your changes?", this.fileName);
1652 if(MessageBox { type = yesNo, master = this/*.parent*/,
1653 text = $"Document has been modified", contents = temp }.Modal() == yes)
1655 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1656 char * fileName = CopyString(this.fileName);
1657 WindowState state = this.state;
1658 Anchor anchor = this.anchor;
1659 Size size = this.size;
1661 this.modifiedDocument = false;
1663 this = ide.OpenFile(fileName, normal, true, null, no, normal, noParsing);
1666 this.anchor = anchor;
1668 this.SetState(state, true, 0);
1676 void UpdateMakefiles()
1680 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1681 for(prj : workspace.projects)
1682 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1687 void UpdateCompilerConfigs(bool mute)
1689 UpdateToolBarActiveCompilers();
1692 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1693 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1696 projectView.ShowOutputBuildLog(true);
1697 projectView.DisplayCompiler(compiler, false);
1699 for(prj : workspace.projects)
1700 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1705 void UpdateToolBarActiveCompilers()
1707 toolBar.activeCompiler.Clear();
1708 for(compiler : ideSettings.compilerConfigs)
1710 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1711 if(workspace && workspace.compiler && !strcmp(compiler.name, workspace.compiler))
1712 toolBar.activeCompiler.currentRow = row;
1714 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1715 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1718 void UpdateToolBarActiveConfigs(bool selectionOnly)
1720 bool commonSelected = false;
1721 DataRow row = toolBar.activeConfig.currentRow;
1723 row = toolBar.activeConfig.FindRow(1);
1726 toolBar.activeConfig.Clear();
1727 row = toolBar.activeConfig.AddString($"(Mixed)");
1732 char * configName = null;
1735 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1736 for(prj : workspace.projects)
1738 for(cfg : prj.configurations)
1741 configs[cfg.name] = 1;
1746 toolBar.activeConfig.AddString(&name);
1750 if(projectView && projectView.project)
1752 for(prj : workspace.projects)
1754 if(prj.config && prj.config.name)
1756 configName = prj.config.name;
1762 commonSelected = true;
1763 for(prj : workspace.projects)
1765 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1767 commonSelected = false;
1775 commonSelected = false;
1776 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1778 if(!strcmp(row.string, configName))
1780 toolBar.activeConfig.currentRow = row;
1781 commonSelected = true;
1788 toolBar.activeConfig.Sort(null, 0);
1790 toolBar.activeConfig.currentRow = row;
1795 bool unavailable = !project;
1797 projectAddItem.disabled = unavailable;
1798 toolBar.buttonAddProject.disabled = unavailable;
1800 projectSettingsItem.disabled = unavailable;
1802 projectBrowseFolderItem.disabled = unavailable;
1804 viewProjectItem.disabled = unavailable;
1806 toolBar.activeConfig.disabled = unavailable;
1807 toolBar.activeCompiler.disabled = unavailable;
1808 toolBar.activeBitDepth.disabled = unavailable;
1815 property bool hasOpenedCodeEditors
1820 for(w = firstChild; w; w = w.next)
1821 if(w._class == class(CodeEditor) &&
1822 w.isDocument && !w.closing && w.visible && w.created &&
1823 w.fileName && w.fileName[0])
1829 void AdjustFileMenus()
1831 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
1833 projectQuickItem.disabled = unavailable;
1836 void AdjustBuildMenus()
1838 bool unavailable = project && projectView.buildInProgress;
1840 projectNewItem.disabled = unavailable;
1841 toolBar.buttonNewProject.disabled = unavailable;
1842 projectOpenItem.disabled = unavailable;
1843 toolBar.buttonOpenProject.disabled = unavailable;
1845 unavailable = !project || projectView.buildInProgress;
1847 projectCloseItem.disabled = unavailable;
1848 // toolBar.buttonCloseProject.disabled = unavailable;
1850 projectRunItem.disabled = unavailable || project.GetTargetType(project.config) != executable;
1851 toolBar.buttonRun.disabled = unavailable || project.GetTargetType(project.config) != executable;
1853 projectBuildItem.disabled = false;
1854 projectBuildItem.text = unavailable ? $"Stop Build" : $"Build";
1855 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
1857 projectLinkItem.disabled = unavailable;
1858 toolBar.buttonReLink.disabled = unavailable;
1859 projectRebuildItem.disabled = unavailable;
1860 toolBar.buttonRebuild.disabled = unavailable;
1861 projectCleanItem.disabled = unavailable;
1862 toolBar.buttonClean.disabled = unavailable;
1863 projectCleanTargetItem.disabled = unavailable;
1864 projectRealCleanItem.disabled = unavailable;
1865 // toolBar.buttonRealClean.disabled = unavailable;
1866 projectRegenerateItem.disabled = unavailable;
1867 toolBar.buttonRegenerateMakefile.disabled = unavailable;
1868 projectCompileItem.disabled = unavailable;
1870 AdjustPopupBuildMenus();
1873 void AdjustPopupBuildMenus()
1875 bool unavailable = !project || projectView.buildInProgress;
1877 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
1880 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
1883 menu.disabled = false;
1884 menu.text = unavailable ? $"Stop Build" : $"Build";
1885 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
1888 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0); if(menu) menu.disabled = unavailable;
1889 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0); if(menu) menu.disabled = unavailable;
1890 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0); if(menu) menu.disabled = unavailable;
1891 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0); if(menu) menu.disabled = unavailable;
1892 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0); if(menu) menu.disabled = unavailable;
1893 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
1894 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0); if(menu) menu.disabled = unavailable;
1895 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0); if(menu) menu.disabled = unavailable;
1896 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0); if(menu) menu.disabled = unavailable;
1897 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0); if(menu) menu.disabled = unavailable;
1898 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0); if(menu) menu.disabled = unavailable;
1899 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
1900 projectView.popupMenu.Update(null);
1904 property bool areDebugMenusUnavailable { get {
1906 project.GetTargetType(project.config) != executable ||
1907 projectView.buildInProgress == buildingMainProject;
1910 property bool isBreakpointTogglingUnavailable { get {
1914 property bool isDebuggerExecuting { get {
1918 return ide.debugger.state == running;
1921 void AdjustDebugMenus()
1923 bool unavailable = areDebugMenusUnavailable;
1924 bool active = debugger.isActive;
1925 bool bpNoToggle = isBreakpointTogglingUnavailable;
1926 bool executing = isDebuggerExecuting;
1927 //bool holding = debugger.state == stopped;
1929 debugStartResumeItem.disabled = unavailable || executing;
1930 debugStartResumeItem.text = active ? $"Resume" : $"Start";
1931 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
1934 toolBar.buttonDebugStartResume.disabled = unavailable || executing;
1935 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
1938 debugBreakItem.disabled = unavailable || !executing;
1939 debugStopItem.disabled = unavailable || !active;
1940 debugRestartItem.disabled = unavailable || !active;
1943 toolBar.buttonDebugPause.disabled = unavailable || !executing;
1944 toolBar.buttonDebugStop.disabled = unavailable || !active;
1945 toolBar.buttonDebugRestart.disabled = unavailable || !active;
1948 debugStepIntoItem.disabled = unavailable || executing;
1949 debugStepOverItem.disabled = unavailable || executing;
1950 debugStepOutItem.disabled = unavailable || executing || !active;
1951 debugSkipStepOverItem.disabled = unavailable || executing;
1952 debugSkipStepOutItem.disabled = unavailable || executing || !active;
1955 toolBar.buttonDebugStepInto.disabled = unavailable || executing;
1956 toolBar.buttonDebugStepOver.disabled = unavailable || executing;
1957 toolBar.buttonDebugStepOut.disabled = unavailable || executing || !active;
1958 toolBar.buttonDebugSkipStepOver.disabled = unavailable || executing;
1959 // toolBar.buttonDebugSkipStepOutItem.disabled = unavailable || executing;
1961 if((Designer)GetActiveDesigner())
1963 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
1965 codeEditor.AdjustDebugMenus(unavailable, bpNoToggle, executing);
1969 void ChangeFileDialogsDirectory(char * directory, bool saveSettings)
1971 char tempString[MAX_LOCATION];
1972 strcpy(tempString, directory);
1973 if(saveSettings && !projectView)
1975 ideSettings.ideFileDialogLocation = directory;
1976 settingsContainer.Save();
1979 ideFileDialog.currentDirectory = tempString;
1980 codeEditorFileDialog.currentDirectory = tempString;
1981 codeEditorFormFileDialog.currentDirectory = tempString;
1984 void ChangeProjectFileDialogDirectory(char * directory)
1986 ideSettings.ideProjectFileDialogLocation = directory;
1987 settingsContainer.Save();
1990 Window FindWindow(char * filePath)
1992 Window document = null;
1994 // TOCHECK: Do we need to change slashes here?
1995 for(document = firstChild; document; document = document.next)
1997 char * fileName = document.fileName;
1998 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2000 document.visible = true;
2001 document.Activate();
2008 bool DontTerminateDebugSession(char * title)
2010 if(debugger.isActive)
2012 if(MessageBox { type = yesNo, master = ide,
2013 contents = $"Do you want to terminate the debugging session in progress?",
2014 text = title }.Modal() == no)
2017 MessageBox msg { type = yesNo, master = ide,
2018 contents = "Do you want to terminate the debugging session in progress?",
2020 if(msg.Modal() == no)
2032 Window OpenFile(char * origFilePath, WindowState state, bool visible, char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2034 char extension[MAX_EXTENSION] = "";
2035 Window document = null;
2036 bool isProject = false;
2037 bool needFileModified = true;
2038 char winFilePath[MAX_LOCATION];
2039 char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2043 GetExtension(filePath, extension);
2047 strcpy(extension, type);
2049 if(strcmp(extension, ProjectExtension))
2051 for(document = firstChild; document; document = document.next)
2053 char * fileName = document.fileName;
2054 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2056 document.visible = true;
2058 document.Activate();
2064 if(createIfFails == whatever)
2066 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2068 needFileModified = false;
2069 if(openMethod == normal)
2071 if(DontTerminateDebugSession($"Open Project"))
2081 Workspace workspace = null;
2083 if(FileExists(filePath))
2085 if(!strcmp(extension, ProjectExtension))
2087 char workspaceFile[MAX_LOCATION];
2088 strcpy(workspaceFile, filePath);
2089 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2090 workspace = LoadWorkspace(workspaceFile, filePath);
2092 else if(!strcmp(extension, WorkspaceExtension))
2093 workspace = LoadWorkspace(filePath, null);
2096 //project = LoadProject(filePath, null);
2101 char absolutePath[MAX_LOCATION];
2102 CreateProjectView(workspace, filePath);
2103 document = projectView;
2105 workspace.DropInvalidBreakpoints();
2108 ide.projectView.ShowOutputBuildLog(true);
2110 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2111 ide.projectView.DisplayCompiler(compiler, false);
2114 UpdateCompilerConfigs(false);
2117 char newWorkingDir[MAX_LOCATION];
2118 StripLastDirectory(filePath, newWorkingDir);
2119 ChangeFileDialogsDirectory(newWorkingDir, false);
2122 document.fileName = filePath;
2124 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2126 // this crashes on starting ide with epj file, solution please?
2127 // app.UpdateDisplay();
2129 workspace.holdTracking = true;
2130 for(ofi : workspace.openedFiles)
2132 if(ofi.state != closed)
2134 Window file = OpenFile(ofi.path, normal, true, null, no, normal, noParsing);
2137 char fileName[MAX_LOCATION];
2139 GetLastDirectory(ofi.path, fileName);
2140 node = projectView.project.topNode.Find(fileName, true);
2142 node.EnsureVisible();
2146 ide.RepositionWindows(false);
2147 workspace.holdTracking = false;
2149 workspace.timer.Start();
2151 findInFilesDialog.mode = FindInFilesMode::project;
2152 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2155 char location[MAX_LOCATION];
2156 StripLastDirectory(ide.project.topNode.path, location);
2157 ChangeProjectFileDialogDirectory(location);
2161 if(projectView.debugger)
2162 projectView.debugger.EvaluateWatches();
2169 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2171 ideProjectFileDialog.text = openProjectFileDialogTitle;
2172 if(ideProjectFileDialog.Modal() == cancel)
2174 filePath = ideProjectFileDialog.filePath;
2175 GetExtension(filePath, extension);
2186 else if(openMethod == add)
2191 char slashFilePath[MAX_LOCATION];
2192 GetSlashPathBuffer(slashFilePath, filePath);
2193 for(p : workspace.projects)
2195 if(!fstrcmp(p.filePath, slashFilePath))
2203 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2204 contents = $"This project is already present in workspace." }.Modal();
2208 prj = LoadProject(filePath, null);
2211 char * activeConfigName = null;
2212 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2213 prj.StartMonitoring();
2214 workspace.projects.Add(prj);
2215 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2216 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2217 activeConfigName = toolBar.activeConfig.currentRow.string;
2218 if(activeConfigName)
2220 for(cfg : prj.configurations)
2222 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2230 projectView.AddNode(prj.topNode, null);
2231 workspace.modified = true;
2233 findInFilesDialog.AddProjectItem(prj);
2234 projectView.ShowOutputBuildLog(true);
2235 projectView.DisplayCompiler(compiler, false);
2236 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2240 char location[MAX_LOCATION];
2241 StripLastDirectory(prj.topNode.path, location);
2242 ChangeProjectFileDialogDirectory(location);
2245 // projectView is associated with the main project and not with the one just added but
2246 return projectView; // just to let the caller know something was opened
2254 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2255 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2256 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2258 if(FileExists(filePath))
2259 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2260 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2261 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2264 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2267 else if(!strcmp(extension, "3ds"))
2269 if(FileExists(filePath))
2270 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2271 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2272 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2276 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2279 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2280 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2281 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2282 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2283 !strcmp(extension, "js"))
2285 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2286 editor.updatingCode = true;
2287 if(editor.LoadFile(filePath))
2290 editor.visible = true;
2294 needFileModified = false;
2298 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2299 if(editor.LoadFile(filePath))
2302 editor.visible = true;
2306 needFileModified = false;
2309 if(document && (document._class == class(PictureEdit) ||
2310 document._class == class(ModelView)))
2315 document.fileName = filePath;
2316 if(workspace && !workspace.holdTracking)
2317 workspace.UpdateOpenedFileInfo(filePath, opened);
2321 if(!document && createIfFails != no)
2323 if(createIfFails != yes && !needFileModified &&
2324 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2325 createIfFails = yes;
2326 if(createIfFails == yes || createIfFails == whatever)
2328 document = (Window)NewCodeEditor(this, state, true);
2330 document.fileName = filePath;
2336 if(projectView && document._class == class(CodeEditor) && workspace)
2338 int lineNumber, position;
2340 CodeEditor editor = (CodeEditor)document;
2341 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2342 editor.openedFileInfo.holdTracking = true;
2343 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2344 position = Max(editor.openedFileInfo.position - 1, 0);
2345 editor.editBox.GoToLineNum(lineNumber);
2346 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2347 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2348 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2349 editor.editBox.scroll = scroll;
2350 editor.openedFileInfo.holdTracking = false;
2353 if(needFileModified)
2354 document.OnFileModified = OnFileModified;
2355 document.NotifySaved = DocumentSaved;
2358 ideSettings.AddRecentProject(document.fileName);
2360 ideSettings.AddRecentFile(document.fileName);
2361 ide.UpdateRecentMenus();
2362 ide.AdjustFileMenus();
2363 settingsContainer.Save();
2371 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2372 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2374 if(!parentClosing && ide.workspace)
2375 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2378 bool ModelView::ModelViewOnClose(bool parentClosing)
2380 if(!parentClosing && ide.workspace)
2381 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2384 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2386 if(!parentClosing && ide.workspace)
2387 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2392 void OnUnloadGraphics(Window window)
2394 display.ClearMaterials();
2395 display.ClearTextures();
2396 display.ClearMeshes();
2400 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2402 caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2403 num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2407 bool OnKeyDown(Key key, unichar ch)
2412 projectView.Update(null);
2415 caps.color = app.GetKeyState(capsState) ? black : Color { 128,128,128 };
2418 num.color = app.GetKeyState(numState) ? black : Color { 128,128,128 };
2424 void GoToError(const char * line, bool noParsing)
2427 projectView.GoToError(line, noParsing);
2430 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
2434 char *colon = strchr(text, ':');
2435 char filePath[MAX_LOCATION] = "";
2436 char completePath[MAX_LOCATION];
2437 int line = 0, col = 0;
2438 int len = strlen(text);
2440 FileAttribs fileAttribs;
2442 // support for valgrind output
2443 if((s = strstr(text, "==")) && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2454 /*for(s=colon; *s; s++)
2463 //line = atoi(colon+1);
2465 // support for "Found n match(es) in "file/path";
2466 else if(path[len-1] == '\"' && strstr(path, $"Found %d match%s in \"%s\"%s\n\n"."Found") && strstr(path, $"match") && strstr(path, $"in") && (s = strstr(path, "\"")) && s != path+len-1)
2472 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2474 path = (colon - 1 > path) ? colon - 1 : path;
2475 colon = strstr(colon + 1, ":");
2477 if(*path == '*' && (s = strchr(path+1, '*')))
2479 while(isspace(*path)) path++;
2483 char * close = strchr(path, ')');
2487 strncpy(name, path+1, close - path - 1);
2488 name[close - path - 1] = '\0';
2489 for(p : ide.workspace.projects)
2491 if(!strcmp(p.name, name))
2501 prj = project ? project : (dir ? null : ide.project);
2504 strncpy(filePath, path, colon - path);
2505 filePath[colon - path] = '\0';
2506 line = atoi(colon + 1);
2507 colon = strstr(colon + 1, ":");
2509 col = atoi(colon + 1);
2511 else if(path - 1 >= text && *(path - 1) == '\"')
2513 colon = strchr(path, '\"');
2516 strncpy(filePath, path, colon - path);
2517 filePath[colon - path] = '\0';
2520 else if(path && !colon)
2522 strcpy(filePath, path);
2528 strcpy(completePath, prj.topNode.path);
2529 else if(dir && dir[0])
2530 strcpy(completePath, dir);
2532 completePath[0] = '\0';
2533 PathCat(completePath, filePath);
2535 if((fileAttribs = FileExists(completePath)))
2536 CodeLocationGoTo(completePath, fileAttribs, line, col);
2537 else if(ide.workspace)
2540 for(p : ide.workspace.projects)
2542 strcpy(completePath, p.topNode.path);
2543 PathCat(completePath, filePath);
2544 if((fileAttribs = FileExists(completePath)).isFile)
2546 CodeLocationGoTo(completePath, fileAttribs, line, col);
2553 for(p : ide.workspace.projects)
2555 ProjectNode node = p.topNode.Find(filePath, false);
2558 node.GetFullFilePath(completePath);
2559 if((fileAttribs = FileExists(completePath)).isFile)
2561 CodeLocationGoTo(completePath, fileAttribs, line, col);
2571 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2573 if(fileAttribs.isFile)
2575 char ext[MAX_EXTENSION];
2576 GetExtension(path, ext);
2577 if(!strcmp(ext, "mp3") || !strcmp(ext, "flac") || !strcmp(ext, "ogg") || !strcmp(ext, "avi") || !strcmp(ext, "mkv"))
2579 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2581 char dirPath[MAX_LOCATION];
2582 StripLastDirectory(path, dirPath);
2587 CodeEditor codeEditor = (CodeEditor)OpenFile(path, normal, true, ext, no, normal, false);
2588 if(codeEditor && line)
2590 EditBox editBox = codeEditor.editBox;
2591 editBox.GoToLineNum(line - 1);
2592 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2596 else if(fileAttribs.isDirectory)
2600 void OnRedraw(Surface surface)
2602 Bitmap bitmap = back.bitmap;
2604 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2607 void SheetSelected(SheetType sheetSelected)
2609 if(activeChild == sheet)
2611 if(sheetSelected == methods)
2613 viewPropertiesItem.accelerator = f4;
2614 viewPropertiesItem.parent = viewMenu;
2615 viewMethodsItem.parent = null;
2619 viewMethodsItem.accelerator = f4;
2620 viewMethodsItem.parent = viewMenu;
2621 viewPropertiesItem.parent = null;
2626 viewMethodsItem.parent = viewMenu;
2627 viewPropertiesItem.parent = viewMenu;
2628 if(sheetSelected == methods)
2630 viewMethodsItem.accelerator = f4;
2631 viewPropertiesItem.accelerator = 0;
2635 viewMethodsItem.accelerator = 0;
2636 viewPropertiesItem.accelerator = f4;
2641 void OnActivateClient(Window client, Window previous)
2643 //if(!client || client != previous)
2646 if(!client || client != previous)
2649 dataType = previous._class;
2650 if(previous && !strcmp(dataType.name, "CodeEditor"))
2652 ((CodeEditor)previous).UpdateFormCode();
2654 else if(previous && !strcmp(dataType.name, "Designer"))
2656 ((Designer)previous).codeEditor.UpdateFormCode();
2661 dataType = client._class;
2662 if(client && !strcmp(dataType.name, "CodeEditor"))
2664 CodeEditor codeEditor = (CodeEditor)client;
2665 SetPrivateModule(codeEditor.privateModule);
2666 SetCurrentContext(codeEditor.globalContext);
2667 SetTopContext(codeEditor.globalContext);
2668 SetGlobalContext(codeEditor.globalContext);
2670 SetDefines(&codeEditor.defines);
2671 SetImports(&codeEditor.imports);
2673 SetActiveDesigner(codeEditor.designer);
2675 sheet.codeEditor = codeEditor;
2676 toolBox.codeEditor = codeEditor;
2678 viewDesignerItem.parent = viewMenu;
2679 if(activeChild != codeEditor)
2681 viewCodeItem.parent = viewMenu;
2682 viewDesignerItem.accelerator = 0;
2683 viewCodeItem.accelerator = f8;
2687 viewCodeItem.parent = null;
2688 viewDesignerItem.accelerator = f8;
2691 else if(client && !strcmp(dataType.name, "Designer"))
2693 CodeEditor codeEditor = ((Designer)client).codeEditor;
2696 SetPrivateModule(codeEditor.privateModule);
2697 SetCurrentContext(codeEditor.globalContext);
2698 SetTopContext(codeEditor.globalContext);
2699 SetGlobalContext(codeEditor.globalContext);
2700 SetDefines(&codeEditor.defines);
2701 SetImports(&codeEditor.imports);
2705 SetPrivateModule(null);
2706 SetCurrentContext(null);
2707 SetTopContext(null);
2708 SetGlobalContext(null);
2713 SetActiveDesigner((Designer)client);
2715 sheet.codeEditor = codeEditor;
2716 toolBox.codeEditor = codeEditor;
2718 viewCodeItem.parent = viewMenu;
2719 if(activeChild != client)
2721 viewDesignerItem.parent = viewMenu;
2722 viewDesignerItem.accelerator = f8;
2723 viewCodeItem.accelerator = 0;
2727 viewDesignerItem.parent = null;
2728 viewCodeItem.accelerator = f8;
2734 sheet.codeEditor = null;
2735 toolBox.codeEditor = null;
2736 SetActiveDesigner(null);
2738 viewDesignerItem.parent = null;
2739 viewCodeItem.parent = null;
2742 SheetSelected(sheet.sheetSelected);
2745 projectCompileItem = null;
2750 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
2752 CodeEditor codeEditor = (CodeEditor)client;
2753 EditBox editBox = codeEditor.editBox;
2755 statusBar.AddField(pos);
2757 caps = { width = 40, text = $"CAPS", color = app.GetKeyState(capsState) ? black : Color { 128, 128, 128 } };
2758 statusBar.AddField(caps);
2760 ovr = { width = 30, text = $"OVR", color = (editBox && editBox.overwrite) ? black : Color { 128, 128, 128 } };
2761 statusBar.AddField(ovr);
2763 num = { width = 30, text = $"NUM", color = app.GetKeyState(numState) ? black : Color { 128, 128, 128 } };
2764 statusBar.AddField(num);
2766 //statusBar.text = "Ready";
2768 if(projectView && projectView.project)
2770 bool isCObject = false;
2771 ProjectNode node = projectView.GetNodeFromWindow(client, null, false);
2772 if(!node && (node = projectView.GetNodeFromWindow(client, null, true)))
2776 char nodeName[MAX_FILENAME];
2777 char name[MAX_FILENAME+96];
2779 ChangeExtension(node.name, "c", nodeName);
2780 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
2781 projectCompileItem =
2783 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
2785 bool NotifySelect(MenuItem selection, Modifiers mods)
2789 bool result = false;
2790 bool isCObject = false;
2791 ProjectNode node = null;
2792 for(p : ide.workspace.projects)
2794 node = projectView.GetNodeFromWindow(activeClient, p, false);
2797 if(!node && (node = projectView.GetNodeFromWindow(activeClient, null, true)))
2801 List<ProjectNode> nodes { };
2803 projectView.Compile(node.project, nodes, mods.ctrl && mods.shift, isCObject ? cObject : normal);
2808 ide.outputView.buildBox.Logf($"File %s is excluded from current build configuration.\n", node.name);
2813 projectMenu.AddDynamic(projectCompileItem, ide, false);
2819 caps = ovr = num = null;
2824 bool OnClose(bool parentClosing)
2826 //return !projectView.buildInProgress;
2827 if(projectView && projectView.buildInProgress)
2829 if(DontTerminateDebugSession($"Close IDE"))
2831 if(findInFilesDialog)
2832 findInFilesDialog.SearchStop();
2835 workspace.timer.Stop();
2838 ideMainFrame.Destroy(0);
2845 bool passThrough = false;
2846 bool debugStart = false;
2847 bool debugWorkDir = false;
2848 char * passDebugWorkDir = null;
2849 bool openAsText = false;
2850 DynamicString passArgs { };
2853 for(c = 1; c<app.argc; c++)
2857 char * arg = app.argv[c];
2858 char * buf = new char[strlen(arg)*2+1];
2860 passArgs.concat(" ");
2862 passArgs.concat(buf);
2865 else if(debugWorkDir)
2867 passDebugWorkDir = CopyString(app.argv[c]);
2868 StripQuotes(passDebugWorkDir, passDebugWorkDir);
2869 debugWorkDir = false;
2871 else if(!strcmp(app.argv[c], "-t"))
2873 else if(!strcmp(app.argv[c], "-no-parsing"))
2874 ide.noParsing = true;
2875 else if(!strcmp(app.argv[c], "-debug-start"))
2877 else if(!strcmp(app.argv[c], "-debug-work-dir"))
2878 debugWorkDir = true;
2879 else if(!strcmp(app.argv[c], "-@"))
2883 char fullPath[MAX_LOCATION];
2884 char parentPath[MAX_LOCATION];
2885 char ext[MAX_EXTENSION];
2887 FileAttribs dirAttribs;
2888 GetWorkingDir(fullPath, MAX_LOCATION);
2889 PathCat(fullPath, app.argv[c]);
2890 StripLastDirectory(fullPath, parentPath);
2891 GetExtension(app.argv[c], ext);
2892 isProject = !openAsText && !strcmpi(ext, "epj");
2894 if(isProject && c > (debugStart ? 2 : 1)) continue;
2896 // Create directory for projects (only)
2897 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
2899 if(isProject && !FileExists(fullPath))
2901 char name[MAX_LOCATION];
2902 NewProjectDialog newProjectDialog;
2906 projectView.visible = false;
2907 if(!projectView.Destroy(0))
2911 newProjectDialog = { master = this };
2913 strcpy(name, app.argv[c]);
2914 StripExtension(name);
2915 GetLastDirectory(name, name);
2916 newProjectDialog.projectName.contents = name;
2917 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
2918 newProjectDialog.locationEditBox.path = parentPath;
2919 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
2921 incref newProjectDialog;
2922 newProjectDialog.Modal();
2925 ideSettings.AddRecentProject(projectView.fileName);
2926 ide.UpdateRecentMenus();
2927 settingsContainer.Save();
2929 delete newProjectDialog;
2930 // Open only one project
2934 ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, openAsText ? "txt" : null, yes, normal, false);
2936 else if(strstr(fullPath, "http://") == fullPath)
2937 ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, openAsText ? "txt" : null, yes, normal, false);
2940 if(passThrough && projectView && projectView.project && workspace)
2941 workspace.commandLineArgs = passArgs;
2942 if(passDebugWorkDir && projectView && projectView.project && workspace)
2944 workspace.debugDir = passDebugWorkDir;
2945 delete passDebugWorkDir;
2948 ;//MenuDebugStart(debugStartResumeItem, 0); // <-- how TODO this without getting into the app.Wait lock
2950 UpdateToolBarActiveConfigs(false);
2951 UpdateToolBarActiveCompilers();
2958 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
2961 projectView.visible = false;
2962 projectView.Destroy(0);
2965 #ifdef GDB_DEBUG_GUI
2966 gdbDialog.Destroy(0);
2971 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
2975 char * oldPaths[128];
2976 String oldList = new char[maxPathLen];
2977 Array<String> newExePaths { };
2978 //Map<String, bool> exePathExists { };
2980 #if defined(__unix__) || defined(__APPLE__)
2981 Array<String> newLibPaths { };
2982 Map<String, bool> libPathExists { };
2987 for(prj : workspace.projects)
2989 DirExpression targetDirExp;
2991 // SKIP FIRST PROJECT...
2992 if(prj == workspace.projects.firstIterator.data) continue;
2994 // NOTE: Right now the additional project config dir will be
2995 // obtained when the debugger is started, so toggling it
2996 // while building will change which library gets used.
2997 // To go with the initial state, e.g. when F5 was pressed,
2998 // we nould need to keep a list of all project's active
2999 // config upon startup.
3000 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3002 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3006 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3007 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3011 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3012 if(cfg.targetType == sharedLibrary && cfg.debug)
3016 if(targetDirExp.dir)
3018 char buffer[MAX_LOCATION];
3019 #if defined(__WIN32__)
3020 Array<String> paths = newExePaths;
3022 Array<String> paths = newLibPaths;
3024 GetSystemPathBuffer(buffer, prj.topNode.path);
3025 PathCat(buffer, targetDirExp.dir);
3028 if(!fstrcmp(p, buffer))
3035 paths.Add(CopyString(buffer));
3037 delete targetDirExp;
3041 for(item : compiler.executableDirs)
3044 for(p : newExePaths)
3046 if(!fstrcmp(p, item))
3053 newExePaths.Add(CopySystemPath(item));
3056 GetEnvironment("PATH", oldList, maxPathLen);
3058 printf("Old value of PATH: %s\n", oldList);
3060 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3061 for(c = 0; c < count; c++)
3064 for(p : newExePaths)
3066 if(!fstrcmp(p, oldPaths[c]))
3073 newExePaths.Add(CopySystemPath(oldPaths[c]));
3077 for(path : newExePaths)
3078 len += strlen(path) + 1;
3079 newList = new char[len + 1];
3081 for(path : newExePaths)
3083 strcat(newList, path);
3084 strcat(newList, pathListSep);
3086 newList[len - 1] = '\0';
3087 SetEnvironment("PATH", newList);
3089 printf("New value of PATH: %s\n", newList);
3096 #if defined(__unix__) || defined(__APPLE__)
3098 for(item : compiler.libraryDirs)
3100 if(!libPathExists[item]) // fstrcmp should be used
3102 String s = CopyString(item);
3104 libPathExists[s] = true;
3108 #if defined(__APPLE__)
3109 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3111 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3114 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3116 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3117 for(c = 0; c < count; c++)
3119 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3121 String s = CopyString(oldPaths[c]);
3123 libPathExists[s] = true;
3128 for(path : newLibPaths)
3129 len += strlen(path) + 1;
3130 newList = new char[len + 1];
3132 for(path : newLibPaths)
3134 strcat(newList, path);
3135 strcat(newList, pathListSep);
3137 newList[len - 1] = '\0';
3138 #if defined(__APPLE__)
3139 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3141 SetEnvironment("LD_LIBRARY_PATH", newList);
3144 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3150 delete libPathExists;
3153 if(compiler.distccEnabled && compiler.distccHosts)
3154 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3159 void DestroyTemporaryProjectDir()
3161 if(tmpPrjDir && tmpPrjDir[0])
3163 if(FileExists(tmpPrjDir).isDirectory)
3164 DestroyDir(tmpPrjDir);
3165 property::tmpPrjDir = null;
3171 // Graphics Driver Menu
3175 app.currentSkin.selectionColor = selectionColor;
3176 app.currentSkin.selectionText = selectionText;
3180 driverItems = new MenuItem[app.numDrivers];
3181 for(c = 0; c < app.numDrivers; c++)
3183 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3184 driverItems[c].id = c;
3185 driverItems[c].isRadio = true;
3188 driverItems = new MenuItem[2];
3189 #if defined(__unix__)
3190 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3191 driverItems[0].id = 0;
3192 driverItems[0].isRadio = true;
3194 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3195 driverItems[0].id = 0;
3196 driverItems[0].isRadio = true;
3198 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3199 driverItems[1].id = 1;
3200 driverItems[1].isRadio = true;
3202 /* skinItems = new MenuItem[app.numSkins];
3203 for(c = 0; c < app.numSkins; c++)
3205 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3206 skinItems[c].id = c;
3207 skinItems[c].isRadio = true;
3210 ideFileDialog.master = this;
3211 ideProjectFileDialog.master = this;
3213 //SetDriverAndSkin();
3217 void UpdateRecentMenus()
3220 Menu fileMenu = menu.FindMenu($"File");
3221 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3222 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3223 char * itemPath = new char[MAX_LOCATION];
3224 char * itemName = new char[MAX_LOCATION+4];
3227 recentFiles.Clear();
3230 for(recent : ideSettings.recentFiles)
3232 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3233 MakeSystemPath(itemPath);
3234 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3235 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3239 recentProjects.Clear();
3241 for(recent : ideSettings.recentProjects)
3243 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3244 MakeSystemPath(itemPath);
3245 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3246 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3262 void DestroyDir(char * path)
3264 RecursiveDeleteFolderFSI fsi { };
3269 #if defined(__WIN32__)
3270 define sdkDirName = "Ecere SDK";
3272 define sdkDirName = "ecere";
3275 void FindAndShellOpenInstalledFolder(char * name)
3277 char * p = new char[MAX_LOCATION];
3278 char * v = new char[maxPathLen];
3281 Array<String> paths { };
3283 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3284 StripLastDirectory(p, p);
3286 paths.Add(CopyString(p));
3287 #if defined(__WIN32__)
3288 GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3291 strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3292 PathCat(p, name); paths.Add(CopyString(p));
3294 GetEnvironment("AppData", v, maxPathLen);
3297 strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3298 PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
3300 GetEnvironment("ProgramFiles", v, maxPathLen);
3303 strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3304 PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
3306 GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3309 strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3310 PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
3312 GetEnvironment("SystemDrive", v, maxPathLen);
3315 strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3316 PathCat(p, "Program Files"); PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
3319 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3320 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3321 for(c=0; c<numTokens; c++)
3323 strncpy(p, tokens[c], MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3324 PathCat(p, sdkDirName); PathCat(p, name); paths.Add(CopyString(p));
3329 strncpy(p, path, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3330 if(FileExists(p).isDirectory)
3342 void FindAndShellOpenInstalledFile(char * subdir, char * name)
3344 char * p = new char[MAX_LOCATION];
3345 char * v = new char[maxPathLen];
3348 Array<String> paths { };
3350 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3351 paths.Add(CopyString(p));
3352 StripLastDirectory(p, p);
3354 paths.Add(CopyString(p));
3355 #if defined(__WIN32__)
3356 GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3359 strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3360 PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
3362 GetEnvironment("AppData", v, maxPathLen);
3365 strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3366 PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
3368 GetEnvironment("ProgramFiles", v, maxPathLen);
3371 strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3372 PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
3374 GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3377 strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3378 PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
3380 GetEnvironment("SystemDrive", v, maxPathLen);
3383 strncpy(p, v, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3384 PathCat(p, "Program Files"); PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
3387 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3388 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3389 for(c=0; c<numTokens; c++)
3391 strncpy(p, tokens[c], MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3392 PathCat(p, sdkDirName); PathCat(p, subdir); paths.Add(CopyString(p));
3397 strncpy(p, path, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
3399 if(FileExists(p).isFile)
3411 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3413 bool preserveRootFolder;
3415 void OutFolder(char * folderPath, bool isRoot)
3417 if(!(preserveRootFolder && isRoot))
3418 RemoveDir(folderPath);
3421 bool OnFile(char * filePath)
3423 DeleteFile(filePath);
3428 class IDEApp : GuiApplication
3430 //driver = "Win32Console";
3431 // driver = "OpenGL";
3435 TempFile includeFile { };
3439 char ext[MAX_EXTENSION];
3440 SetLoggingMode(stdOut, null);
3441 //SetLoggingMode(debug, null);
3443 settingsContainer.Load();
3444 if(argc > 1 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3446 app.driver = "OpenGL";
3447 ide.driverItems[1].checked = true;
3451 #if defined(__unix__) || defined(__APPLE__)
3452 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3454 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3456 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3461 desktop.text = titleECEREIDE;
3464 for(c = 1; c<app.argc; c++)
3466 char fullPath[MAX_LOCATION];
3467 GetWorkingDir(fullPath, MAX_LOCATION);
3468 PathCat(fullPath, app.argv[c]);
3469 ide.OpenFile(fullPath, (app.argc == 2) * maximized, true, null, yes, normal, false);
3473 if(!LoadIncludeFile())
3474 PrintLn("error: unable to load :crossplatform.mk file inside ide binary.");
3479 bool LoadIncludeFile()
3481 bool result = false;
3482 File include = FileOpen(":crossplatform.mk", read);
3485 File f = includeFile;
3488 for(; !include.Eof(); )
3491 int count = include.Read(buffer, 1, 4096);
3492 f.Write(buffer, 1, count);
3502 IDEMainFrame ideMainFrame { };
3504 define app = ((IDEApp)__thisModule);
3506 define titleECEREIDE = $"ECERE IDE (Debug)";
3508 define titleECEREIDE = $"ECERE IDE";