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 AVLTree<const String> binaryDocExt
49 "wav", "mp3", "flac", "ogg",
51 "avi", "mkv", "mpg", "mpeg",
52 "7z", "zip", "gz", "bz2", "xz", "rar", "z", "tar", "ear",
53 "pdf", "odp", "ods", "odt", "ppt", "doc", "xls", "pptx", "docx", "xlsx"
56 #if defined(__WIN32__)
57 define pathListSep = ";";
59 define pathListSep = ":";
62 IDEConfigHolder ideConfig { };
64 IDESettings ideSettings;
66 IDESettingsContainer settingsContainer
68 dataOwner = &ideSettings;
69 dataClass = class(IDESettings);
71 void onLoadCompilerConfigs() { ide.UpdateCompilerConfigs(true); }
72 void onLoadRecentFiles() { ide.updateRecentFilesMenu(); }
73 void onLoadRecentProjects() { ide.updateRecentProjectsMenu(); }
76 define maxPathLen = 65 * MAX_LOCATION;
78 class PathBackup : struct
85 oldPath = new char[maxPathLen];
86 oldLDPath = new char[maxPathLen];
88 GetEnvironment("PATH", oldPath, maxPathLen);
89 #if defined(__APPLE__)
90 GetEnvironment("DYLD_LIBRARY_PATH", oldLDPath, maxPathLen);
92 GetEnvironment("LD_LIBRARY_PATH", oldLDPath, maxPathLen);
98 SetEnvironment("PATH", oldPath);
99 #if defined(__APPLE__)
100 SetEnvironment("DYLD_LIBRARY_PATH", oldLDPath);
102 SetEnvironment("LD_LIBRARY_PATH", oldLDPath);
109 enum OpenCreateIfFails { no, yes, something, whatever };
110 enum OpenMethod { normal, add };
112 static Array<FileFilter> fileFilters
114 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
115 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
116 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
117 { $"Text files (*.txt, *.text, *.nfo, *.info)", "txt, text, nfo, info" },
118 { $"Web files (*.html, *.htm, *.xhtml, *.css, *.php, *.js, *.jsi, *.rb, *.xml)", "html, htm, xhtml, css, php, js, jsi, rb, xml" },
119 { $"Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", "jpg, jpeg, bmp, pcx, png, gif" },
120 { $"3D Studio Model Files (*.3ds)", "3ds" },
121 { $"All files", null }
124 static Array<FileType> fileTypes
126 { $"Based on extension", null },
129 { $"3D Studio Model", "3ds" }
132 static Array<FileFilter> projectFilters
134 { $"Project Files (*.epj)", ProjectExtension }
137 static Array<FileType> projectTypes
139 { $"Project File", ProjectExtension }
142 static Array<FileFilter> findInFilesFileFilters
144 { $"eC Files (*.ec, *.eh)", "ec, eh" },
145 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
146 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
147 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
148 { $"Text files (*.txt)", "txt" },
149 { $"All files", null }
152 FileDialog ideFileDialog
154 type = multiOpen, text = $"Open";
155 types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType), filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter);
158 define openProjectFileDialogTitle = $"Open Project";
159 define addProjectFileDialogTitle = $"Open Additional Project";
160 FileDialog ideProjectFileDialog
163 types = projectTypes.array, sizeTypes = projectTypes.count * sizeof(FileType), filters = projectFilters.array, sizeFilters = projectFilters.count * sizeof(FileFilter);
166 GlobalSettingsDialog globalSettingsDialog
168 void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange)
170 switch(globalSettingsChange)
175 for(child = ide.firstChild; child; child = child.next)
177 if(child._class == class(CodeEditor))
179 CodeEditor codeEditor = (CodeEditor) child;
180 codeEditor.editBox.freeCaret = ideSettings.useFreeCaret;
181 // codeEditor.editBox.lineNumbers = ideSettings.showLineNumbers;
182 codeEditor.editBox.caretFollowsScrolling = ideSettings.caretFollowsScrolling;
183 codeEditor.OnPostCreate(); // Update editBox margin size
190 case compilerSettings:
192 ide.UpdateCompilerConfigs(true);
199 void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
204 lineY = (line - 1) * lineH;
205 if(lineY + lineH > scrollY && lineY + lineH < scrollY + boxH)
207 Bitmap bitmap = resource.bitmap;
209 surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
214 #define IDEItem(x) (&((IDEWorkSpace)0).x)
216 class IDEToolbar : ToolBar
220 ToolButton buttonNewFile { this, toolTip = $"New file", menuItemPtr = IDEItem(fileNewItem) };
222 ToolButton buttonOpenFile { this, toolTip = $"Open file", menuItemPtr = IDEItem(fileOpenItem) };
224 // ToolButton buttonCloseFile { this, toolTip = $"Close file", menuItemPtr = IDEItem(fileCloseItem) };
226 ToolButton buttonSaveFile { this, toolTip = $"Save file", menuItemPtr = IDEItem(fileSaveItem) };
228 ToolButton buttonSaveAllFile { this, toolTip = $"Save all", menuItemPtr = IDEItem(fileSaveAllItem) };
230 ToolSeparator separator1 { this };
239 // ToolSeparator separator2 { this };
243 ToolButton buttonNewProject { this, toolTip = $"New project", menuItemPtr = IDEItem(projectNewItem) };
245 ToolButton buttonOpenProject { this, toolTip = $"Open project", menuItemPtr = IDEItem(projectOpenItem) };
246 // Add project to workspace
247 ToolButton buttonAddProject { this, toolTip = $"Add project to workspace", menuItemPtr = IDEItem(projectAddItem), disabled = true; };
249 // ToolButton buttonCloseProject { this, toolTip = $"Close project", menuItemPtr = IDEItem(projectCloseItem), disabled = true; };
251 ToolSeparator separator3 { this };
253 // Build/Execution options
255 ToolButton buttonBuild { this, toolTip = $"Build project", menuItemPtr = IDEItem(projectBuildItem), disabled = true; };
257 ToolButton buttonReLink { this, toolTip = $"Relink project", menuItemPtr = IDEItem(projectLinkItem), disabled = true; };
259 ToolButton buttonRebuild { this, toolTip = $"Rebuild project", menuItemPtr = IDEItem(projectRebuildItem), disabled = true; };
261 ToolButton buttonClean { this, toolTip = $"Clean project", menuItemPtr = IDEItem(projectCleanItem), disabled = true; };
263 // ToolButton buttonRealClean { this, toolTip = $"Real clean project", menuItemPtr = IDEItem(projectRealCleanItem), disabled = true; };
264 // Regenerate Makefile
265 ToolButton buttonRegenerateMakefile { this, toolTip = $"Regenerate Makefile", menuItemPtr = IDEItem(projectRegenerateItem), disabled = true; };
266 // Compile actual file
268 ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem), disabled = true; };
269 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
270 ToolButton buttonInstall { this, toolTip = $"Install", menuItemPtr = IDEItem(projectInstallItem), disabled = true; };
273 ToolSeparator separator4 { this };
277 ToolButton buttonDebugStartResume { this, toolTip = $"Start", menuItemPtr = IDEItem(debugStartResumeItem), disabled = true; };
279 ToolButton buttonDebugRestart { this, toolTip = $"Restart", menuItemPtr = IDEItem(debugRestartItem), disabled = true; };
281 ToolButton buttonDebugPause { this, toolTip = $"Break", menuItemPtr = IDEItem(debugBreakItem), disabled = true; };
283 ToolButton buttonDebugStop { this, toolTip = $"Stop", menuItemPtr = IDEItem(debugStopItem), disabled = true; };
285 //ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem) };
287 ToolButton buttonDebugStepInto { this, toolTip = $"Step Into", menuItemPtr = IDEItem(debugStepIntoItem), disabled = true; };
289 ToolButton buttonDebugStepOver { this, toolTip = $"Step Over", menuItemPtr = IDEItem(debugStepOverItem), disabled = true; };
291 ToolButton buttonDebugStepOut { this, toolTip = $"Step Out", menuItemPtr = IDEItem(debugStepOutItem), disabled = true; };
293 ToolButton buttonDebugSkipStepOver { this, toolTip = $"Step Over Skipping Breakpoints", menuItemPtr = IDEItem(debugSkipStepOverItem), disabled = true; };
295 ToolSeparator separator5 { this };
297 Window spacer5 { this, size = { 4 } };
301 this, toolTip = $"Active Configuration(s)", size = { 160 }, disabled = true;
302 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
305 ide.workspace.SelectActiveConfig(row.string);
310 Window spacer6 { this, size = { 4 } };
312 DropBox activeCompiler
314 this, toolTip = $"Active Compiler", size = { 160 }, disabled = true;
315 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
317 if(ide.workspace && ide.projectView && row && strcmp(row.string, ide.workspace.activeCompiler))
319 bool silent = ide.projectView.buildInProgress == none ? false : true;
320 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(row.string);
321 ide.workspace.activeCompiler = row.string;
322 ide.projectView.ShowOutputBuildLog(!silent);
324 ide.projectView.DisplayCompiler(compiler, false);
325 for(prj : ide.workspace.projects)
326 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
328 ide.workspace.Save();
334 DropBox activeBitDepth
336 this, toolTip = $"Active Bit Length", size = { 60 }, disabled = true;
337 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
339 if(ide.workspace && ide.projectView && row)
341 bool silent = ide.projectView.buildInProgress == none ? false : true;
342 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler);
343 ide.workspace.bitDepth = (int)row.tag;
344 ide.projectView.ShowOutputBuildLog(!silent);
346 ide.projectView.DisplayCompiler(compiler, false);
347 for(prj : ide.workspace.projects)
348 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
350 ide.workspace.Save();
356 Window spacer7 { this, size = { 4 } };
361 row = activeBitDepth.AddString("Auto");
363 activeBitDepth.AddString("32 bit").tag = 32;
364 activeBitDepth.AddString("64 bit").tag = 64;
365 activeBitDepth.currentRow = row;
369 class IDEMainFrame : Window
371 background = formColor;
372 borderStyle = sizable;
376 minClientSize = { 600, 300 };
378 icon = { ":icon.png" };
379 text = titleECEREIDE;
383 anchor = { top = 0, right = 0, bottom = 0 };
386 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
393 isActiveClient = true;
395 direction = vertical;
396 background = formColor;
397 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
405 ((IDEWorkSpace)master).toolBar = null;
408 IDEWorkSpace ideWorkSpace { stack, this, toolBar = toolBar };
411 define ide = ideMainFrame.ideWorkSpace;
413 class IDEWorkSpace : Window
415 background = Color { 85, 85, 85 };
418 hasVertScroll = true;
419 hasHorzScroll = true;
421 isActiveClient = true;
422 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
426 MenuItem * driverItems, * skinItems, * languageItems;
427 StatusField pos { width = 150 };
428 StatusField ovr, caps, num;
431 BitmapResource back { ":ecereBack.jpg", window = this };
432 BitmapResource bmpBp { ":codeMarks/breakpoint.png", window = this };
433 BitmapResource bmpBpDisabled { ":codeMarks/breakpointDisabled.png", window = this };
434 BitmapResource bmpBpHalf { ":codeMarks/breakpointHalf.png", window = this };
435 BitmapResource bmpBpHalfDisabled { ":codeMarks/breakpointHalfDisabled.png", window = this };
436 BitmapResource bmpCursor { ":codeMarks/cursor.png", window = this };
437 BitmapResource bmpCursorError { ":codeMarks/cursorError.png", window = this };
438 BitmapResource bmpTopFrame { ":codeMarks/topFrame.png", window = this };
439 BitmapResource bmpTopFrameError { ":codeMarks/topFrameError.png", window = this };
440 BitmapResource bmpTopFrameHalf { ":codeMarks/topFrameHalf.png", window = this };
441 BitmapResource bmpTopFrameHalfError { ":codeMarks/topFrameHalfError.png", window = this };
443 BuildOutputMode rightClickMenuBuildOutputMode;
445 Debugger debugger { };
447 void ApplyFont(const String faceName, float size)
449 panelFont.faceName = faceName;
450 panelFont.size = size;
452 codeFont.faceName = faceName;
453 codeFont.size = size;
457 for(ce = (CodeEditor)firstChild; ce; ce = (CodeEditor)ce.next)
458 if(ce._class == class(CodeEditor))
460 ce.font = { codeFont.faceName, codeFont.size, codeFont.bold, codeFont.italic };
461 ce.editBox.font = ce.font;
466 threadsView.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
467 callStackView.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
468 outputView.buildBox.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
469 outputView.debugBox.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
470 outputView.findBox.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
471 #ifdef GDB_DEBUG_OUTPUT
472 outputView.gdbBox.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
477 gdbDialog.tree.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
478 gdbDialog.output.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
483 ProjectView projectView;
485 OutputView outputView
489 void OnGotoError(const char * line, bool noParsing)
491 CompilerConfig compiler = ide.workspace ? ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler) : null;
492 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
493 ide.GoToError(line, noParsing, objectFileExt);
497 void OnCodeLocationParseAndGoTo(const char * line)
499 CompilerConfig compiler = ide.workspace ? ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler) : null;
500 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
501 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir, objectFileExt);
505 bool OnKeyDown(Key key, unichar ch)
510 if(activeBox != findBox || !ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
511 ide.ShowCodeEditor();
515 OutputView::OnKeyDown(key, ch);
522 bool OnClose(bool parentClosing)
526 ide.RepositionWindows(false);
527 return parentClosing;
531 CallStackView callStackView
533 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
535 void OnSelectFrame(int frameIndex)
537 ide.debugger.GoToStackFrameLine(frameIndex, true, true);
539 ide.debugger.SelectFrame(frameIndex);
542 void OnToggleBreakpoint()
544 Debugger debugger = ide.debugger;
545 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
547 int line = debugger.activeFrame.line;
548 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line);
551 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
552 if(codeEditor) { codeEditor.Update(null); Activate(); }
557 bool OnKeyDown(Key key, unichar ch)
561 case escape: ide.ShowCodeEditor(); break;
566 bool OnClose(bool parentClosing)
570 ide.RepositionWindows(false);
571 return parentClosing;
574 void OnRedraw(Surface surface)
576 Debugger debugger = ide.debugger;
577 Frame activeFrame = debugger.activeFrame;
581 int lineCursor, lineTopFrame;
582 int lineH, scrollY, boxH;
584 Breakpoint bp = null;
587 scrollY = editBox.scroll.y;
588 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
589 //activeThread = debugger.activeThread;
590 //hitThread = debugger.hitThread;
591 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
593 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
594 if(activeFrame.absoluteFile)
596 for(i : ide.workspace.breakpoints; i.type == user)
598 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
599 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
600 activeFrame.line == i.line)
608 DrawLineMarginIcon(surface,
609 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
610 lineCursor /*1*/, lineH, scrollY, boxH);
612 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
613 DrawLineMarginIcon(surface,
614 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
615 1, lineH, scrollY, boxH);
617 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
618 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
619 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
621 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
622 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
624 if(editBox.horzScroll && editBox.horzScroll.visible)
626 surface.SetBackground(control);
627 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
632 WatchesView watchesView { parent = this };
633 ThreadsView threadsView
635 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
637 bool OnKeyDown(Key key, unichar ch)
641 case escape: ide.ShowCodeEditor(); break;
646 bool OnClose(bool parentClosing)
650 ide.RepositionWindows(false);
651 return parentClosing;
654 void OnSelectThread(int threadId)
657 ide.debugger.SelectThread(threadId);
660 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
663 Debugger debugger = ide.debugger;
664 *activeThread = debugger.activeThread;
665 *hitThread = debugger.hitThread;
666 *signalThread = debugger.signalThread;
671 BreakpointsView breakpointsView { parent = this };
673 ToolBox toolBox { parent = this, visible = false };
674 Sheet sheet { parent = this, visible = false };
677 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
679 Menu fileMenu { menu, $"File", f, hasMargin = true };
682 fileMenu, $"New", n, ctrlN;
683 bitmap = { ":actions/docNew.png" };
684 bool NotifySelect(MenuItem selection, Modifiers mods)
686 Window currentDoc = activeClient;
687 bool maximizeDoc = ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
688 Window document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, false);
689 RepositionWindows(false);
690 document.NotifySaved = DocumentSaved;
694 MenuItem fileOpenItem
696 fileMenu, $"Open...", o, ctrlO;
697 bitmap = { ":actions/docOpen.png" };
698 bool NotifySelect(MenuItem selection, Modifiers mods)
700 if(!projectView && ideSettings.ideFileDialogLocation)
701 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
704 if(ideFileDialog.Modal() == ok)
706 bool gotWhatWeWant = false;
708 int numSelections = ideFileDialog.numSelections;
709 const char * const * multiFilePaths = ideFileDialog.multiFilePaths;
711 for(c = 0; c < numSelections; c++)
713 if(OpenFile(multiFilePaths[c], false, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
714 gotWhatWeWant = true;
717 MessageBox { type = yesNo, master = this, text = $"Error opening file",
718 contents = $"Open a different file?" }.Modal() == no)
720 if(!projectView && gotWhatWeWant)
721 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
722 ide.RepositionWindows(false);
732 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
733 MenuDivider { fileMenu };
734 MenuItem fileSaveItem
736 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
738 // For the toolbar button; clients can still override that for the menu item
739 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
741 Window w = activeClient;
743 w.MenuFileSave(null, 0);
747 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
748 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
749 MenuDivider { fileMenu };
752 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
753 bool NotifySelect(MenuItem selection, Modifiers mods)
755 findInFilesDialog.replaceMode = false;
756 findInFilesDialog.Show();
760 MenuItem replaceInFiles
762 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
763 bool NotifySelect(MenuItem selection, Modifiers mods)
765 findInFilesDialog.replaceMode = true;
766 findInFilesDialog.Show();
770 MenuDivider { fileMenu };
771 MenuItem globalSettingsItem
773 fileMenu, $"Global Settings...", g;
774 bool NotifySelect(MenuItem selection, Modifiers mods)
776 // Reload configs here until we setup a configs directory monitor
777 ideConfig.compilers.read(settingsContainer);
779 globalSettingsDialog.master = this;
780 if(ide.workspace && ide.workspace.activeCompiler)
781 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.activeCompiler;
782 else if(ideSettings.defaultCompiler)
783 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
784 globalSettingsDialog.Modal();
788 MenuDivider { fileMenu };
789 Menu recentFilesMenu { fileMenu, $"Recent Files", r };
790 Menu recentProjectsMenu { fileMenu, $"Recent Projects", p };
791 MenuDivider { fileMenu };
794 fileMenu, $"Exit", x, altF4;
796 bool NotifySelect(MenuItem selection, Modifiers mods)
798 ideMainFrame.Destroy(0);
803 bool FileRecentFile(MenuItem selection, Modifiers mods)
806 RecentPaths recentFiles = workspace ? workspace.recentFiles : ideConfig.recentFiles;
807 for(file : recentFiles)
809 if(id == selection.id)
812 char extension[MAX_EXTENSION] = "";
813 GetExtension(file, extension);
814 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
815 if(mods.ctrl && !mods.shift)
817 char * command = PrintString("ecere-ide ", isProjectFile ? "-t " : "", file);
823 OpenFile(file, false, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
824 ide.RepositionWindows(false);
833 bool FileRecentProject(MenuItem selection, Modifiers mods)
836 for(file : ideConfig.recentWorkspaces)
838 if(id == selection.id)
840 if(mods.ctrl && !mods.shift)
842 char * command = PrintString("ecere-ide ", file);
847 OpenFile(file, false, true, (mods.ctrl && mods.shift) ? "txt" : null, no, normal, mods.ctrl && mods.shift);
855 MenuPlacement editMenu { menu, $"Edit", e };
857 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
858 MenuItem projectNewItem
860 projectMenu, $"New...", n, Key { n, true, true };
861 bitmap = { ":actions/projNew.png" };
862 bool NotifySelect(MenuItem selection, Modifiers mods)
864 if(!DontTerminateDebugSession($"New Project"))
867 NewProjectDialog newProjectDialog { master = this };
868 incref newProjectDialog;
869 result = newProjectDialog.Modal();
874 newProjectDialog.CreateNewProject();
877 ideConfig.recentWorkspaces.addRecent(projectView.fileName);
878 ideConfig.recentWorkspaces.write(settingsContainer);
879 ide.updateRecentProjectsMenu();
883 delete newProjectDialog;
888 MenuItem projectOpenItem
890 projectMenu, $"Open...", o, Key { o, true, true };
891 bitmap = { ":actions/projOpen.png" };
892 bool NotifySelect(MenuItem selection, Modifiers mods)
894 if(ideSettings.ideProjectFileDialogLocation)
895 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
897 ideProjectFileDialog.text = openProjectFileDialogTitle;
898 if(ideProjectFileDialog.Modal() == ok)
900 OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
901 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
906 MenuItem projectQuickItem
908 projectMenu, $"Quick...", q, f7, disabled = true;
909 bool NotifySelect(MenuItem selection, Modifiers mods)
912 QuickProjectDialog { this }.Modal();
916 MenuItem projectAddItem
918 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
919 bitmap = { ":actions/projAdd.png" };
921 bool NotifySelect(MenuItem selection, Modifiers mods)
923 if(ideSettings.ideProjectFileDialogLocation)
924 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
926 ideProjectFileDialog.text = addProjectFileDialogTitle;
929 if(ideProjectFileDialog.Modal() == ok)
931 if(OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
933 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
934 contents = $"Add a different project?" }.Modal() == no)
945 MenuItem projectCloseItem
947 projectMenu, $"Close", c, disabled = true;
948 bool NotifySelect(MenuItem selection, Modifiers mods)
952 if(!ide.DontTerminateDebugSession($"Project Close"))
958 MenuDivider { projectMenu };
959 MenuItem projectSettingsItem
961 projectMenu, $"Settings...", s, altF7, disabled = true;
962 bool NotifySelect(MenuItem selection, Modifiers mods)
964 projectView.MenuSettings(projectView.active ? selection : null, mods);
968 MenuDivider { projectMenu };
969 MenuItem projectBrowseFolderItem
971 projectMenu, $"Browse Project Folder", p, disabled = true;
972 bool NotifySelect(MenuItem selection, Modifiers mods)
975 projectView.MenuBrowseFolder(null, mods);
979 MenuDivider { projectMenu };
980 MenuItem projectRunItem
982 projectMenu, $"Run", r, ctrlF5, disabled = true;
983 bitmap = { ":actions/run.png" };
984 bool NotifySelect(MenuItem selection, Modifiers mods)
987 projectView.Run(null, mods);
991 MenuItem projectBuildItem
993 projectMenu, $"Build", b, f7, disabled = true;
994 bitmap = { ":actions/build.png" };
995 bool NotifySelect(MenuItem selection, Modifiers mods)
999 if(projectView.buildInProgress == none)
1000 projectView.ProjectBuild(projectView.active ? selection : null, mods);
1002 projectView.stopBuild = true;
1007 MenuItem projectLinkItem
1009 projectMenu, $"Relink", l, disabled = true;
1010 bitmap = { ":actions/relink.png" };
1011 bool NotifySelect(MenuItem selection, Modifiers mods)
1014 projectView.ProjectLink(projectView.active ? selection : null, mods);
1018 MenuItem projectRebuildItem
1020 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
1021 bitmap = { ":actions/rebuild.png" };
1022 bool NotifySelect(MenuItem selection, Modifiers mods)
1025 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
1029 MenuItem projectCleanTargetItem
1031 projectMenu, $"Clean Target", g, disabled = true;
1032 bitmap = { ":actions/clean.png" };
1033 bool NotifySelect(MenuItem selection, Modifiers mods)
1038 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
1043 MenuItem projectCleanItem
1045 projectMenu, $"Clean", e, disabled = true;
1046 bitmap = { ":actions/clean.png" };
1047 bool NotifySelect(MenuItem selection, Modifiers mods)
1052 projectView.ProjectClean(projectView.active ? selection : null, mods);
1057 MenuItem projectRealCleanItem
1059 projectMenu, $"Real Clean", disabled = true;
1060 bitmap = { ":actions/clean.png" };
1061 bool NotifySelect(MenuItem selection, Modifiers mods)
1066 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1071 MenuItem projectRegenerateItem
1073 projectMenu, $"Regenerate Makefile", m, disabled = true;
1074 bitmap = { ":actions/regMakefile.png" };
1075 bool NotifySelect(MenuItem selection, Modifiers mods)
1078 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1082 MenuItem projectInstallItem
1084 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
1085 projectMenu, $"Install", t, disabled = true;
1087 bitmap = { ":status/software-update-available.png" };
1088 bool NotifySelect(MenuItem selection, Modifiers mods)
1091 projectView.ProjectInstall(projectView.active ? selection : null, mods);
1095 MenuItem projectCompileItem;
1096 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1097 MenuItem debugStartResumeItem
1099 debugMenu, $"Start", s, f5, disabled = true;
1100 bitmap = { ":actions/debug.png" };
1101 NotifySelect = MenuDebugStart;
1103 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1107 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1108 if(!projectView.DebugStart())
1109 debugStartResumeItem.disabled = false; // same exception
1113 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1116 projectView.DebugResume();
1119 MenuItem debugRestartItem
1121 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1122 bitmap = { ":actions/restart.png" };
1123 bool NotifySelect(MenuItem selection, Modifiers mods)
1126 projectView.DebugRestart();
1130 MenuItem debugBreakItem
1132 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1133 bitmap = { ":actions/pause.png" };
1134 bool NotifySelect(MenuItem selection, Modifiers mods)
1136 if(projectView && projectView.buildInProgress != none)
1139 projectView.DebugBreak();
1143 MenuItem debugStopItem
1145 debugMenu, $"Stop", p, shiftF5, disabled = true;
1146 bitmap = { ":actions/stopDebug.png" };
1147 bool NotifySelect(MenuItem selection, Modifiers mods)
1150 projectView.DebugStop();
1154 MenuDivider { debugMenu };
1158 // nonClient = true,
1165 anchor = { right = 0, bottom = 0 },
1167 isActiveClient = false,
1169 clickThrough = true,
1170 size = { 500, 500 };
1172 bool OnLoadGraphics()
1174 ModelView::OnLoadGraphics();
1175 camera.position.z /= 1.3;
1176 camera.orientation = Euler { yaw = 280, pitch = 20 };
1182 bool OnRightButtonDown(int x, int y, Modifiers mods)
1184 if(!displaySystem.flags.flipping) return true;
1185 MenuWindowMove(null, 0);
1189 bool OnRightButtonUp(int x, int y, Modifiers mods)
1191 position = position;
1196 MenuItem debugRubberDuck
1198 debugMenu, $"Rubber Duck", checkable = true, disabled = true;
1199 bool NotifySelect(MenuItem selection, Modifiers mods)
1201 if(selection.checked)
1209 MenuDivider { debugMenu };
1210 MenuItem debugUseValgrindItem
1212 debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
1213 bool NotifySelect(MenuItem selection, Modifiers mods)
1217 ide.workspace.useValgrind = selection.checked;
1218 ide.workspace.Save();
1220 ide.AdjustValgrindMenus();
1224 Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
1225 MenuItem debugValgrindNoLeakCheckItem { debugValgrindLeakCheckItem, $"No" , f, id = ValgrindLeakCheck::no , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1226 MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; };
1227 MenuItem debugValgrindYesLeakCheckItem { debugValgrindLeakCheckItem, $"Yes" , f, id = ValgrindLeakCheck::yes , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1228 MenuItem debugValgrindFullLeakCheckItem { debugValgrindLeakCheckItem, $"Full" , f, id = ValgrindLeakCheck::full , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1229 bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
1233 if(selection.checked)
1235 ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
1237 debugValgrindNoLeakCheckItem.checked = debugValgrindNoLeakCheckItem.id == vgLeakCheck;
1238 debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
1239 debugValgrindYesLeakCheckItem.checked = debugValgrindYesLeakCheckItem.id == vgLeakCheck;
1240 debugValgrindFullLeakCheckItem.checked = debugValgrindFullLeakCheckItem.id == vgLeakCheck;
1242 ide.workspace.vgLeakCheck = vgLeakCheck;
1243 ide.workspace.Save();
1246 selection.checked = true;
1250 Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
1251 MenuItem debugValgrindRSDefaultItem { debugValgrindRedzoneSizeItem, $"Default", f, id = -1, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; };
1252 MenuItem debugValgrindRS0Item { debugValgrindRedzoneSizeItem, "0" , f, id = 0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1253 MenuItem debugValgrindRS16Item { debugValgrindRedzoneSizeItem, "16" , f, id = 16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1254 MenuItem debugValgrindRS32Item { debugValgrindRedzoneSizeItem, "32" , f, id = 32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1255 MenuItem debugValgrindRS64Item { debugValgrindRedzoneSizeItem, "64" , f, id = 64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1256 MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, "128" , f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1257 MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, "256" , f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1258 MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, "512" , f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1259 bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
1263 if(selection.checked)
1265 int vgRedzoneSize = (int)selection.id;
1267 debugValgrindRSDefaultItem.checked = debugValgrindRSDefaultItem.id == vgRedzoneSize;
1268 debugValgrindRS0Item.checked = debugValgrindRS0Item.id == vgRedzoneSize;
1269 debugValgrindRS16Item.checked = debugValgrindRS16Item.id == vgRedzoneSize;
1270 debugValgrindRS32Item.checked = debugValgrindRS32Item.id == vgRedzoneSize;
1271 debugValgrindRS64Item.checked = debugValgrindRS64Item.id == vgRedzoneSize;
1272 debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
1273 debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
1274 debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
1276 ide.workspace.vgRedzoneSize = vgRedzoneSize;
1277 ide.workspace.Save();
1280 selection.checked = true;
1284 MenuItem debugValgrindTrackOriginsItem
1286 debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
1287 bool NotifySelect(MenuItem selection, Modifiers mods)
1291 ide.workspace.vgTrackOrigins = selection.checked;
1292 ide.workspace.Save();
1298 MenuDivider { debugMenu };
1299 MenuItem debugStepIntoItem
1301 debugMenu, $"Step Into", i, f11, disabled = true;
1302 bitmap = { ":actions/stepInto.png" };
1303 bool NotifySelect(MenuItem selection, Modifiers mods)
1305 if(projectView) projectView.DebugStepInto();
1309 MenuItem debugStepOverItem
1311 debugMenu, $"Step Over", v, f10, disabled = true;
1312 bitmap = { ":actions/stepOver.png" };
1313 bool NotifySelect(MenuItem selection, Modifiers mods)
1315 if(projectView) projectView.DebugStepOver(false);
1319 MenuItem debugSkipStepOverItem
1321 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1322 bitmap = { ":actions/stepOverSkipBreak.png" };
1323 bool NotifySelect(MenuItem selection, Modifiers mods)
1325 if(projectView) projectView.DebugStepOver(true);
1329 MenuItem debugStepOutItem
1331 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1332 bitmap = { ":actions/stepOut.png" };
1333 bool NotifySelect(MenuItem selection, Modifiers mods)
1335 if(projectView) projectView.DebugStepOut(false);
1339 MenuItem debugSkipStepOutItem
1341 debugMenu, $"Step Out Skipping Breakpoints", n, Key { f11, ctrl = true, shift = true }, disabled = true;
1342 bitmap = { ":actions/skipBreaks.png" };
1343 bool NotifySelect(MenuItem selection, Modifiers mods)
1345 if(projectView) projectView.DebugStepOut(true);
1350 MenuItem debugStepUntilItem
1352 debugMenu, $"Step Over Until Next Line", x, disabled = true;
1353 bool NotifySelect(MenuItem selection, Modifiers mods)
1355 if(projectView) projectView.DebugStepUntil(false);
1359 MenuItem debugSkipStepUntilItem
1361 debugMenu, $"Step Over Until Next Line Skipping Breakpoints", e, Key { f10, shift = true, alt = true }, disabled = true;
1362 bool NotifySelect(MenuItem selection, Modifiers mods)
1364 if(projectView) projectView.DebugStepUntil(true);
1369 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1370 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1371 MenuPlacement debugRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level", l };
1372 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", g };
1374 MenuPlacement debugBpRunToCursorItem { debugMenu, $"BP Run To Cursor" };
1375 MenuPlacement debugBpSkipRunToCursorItem { debugMenu, $"BP Run To Cursor Skipping Breakpoints" };
1376 MenuPlacement debugBpRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level" };
1377 MenuPlacement debugBpSkipRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level Skipping Breakpoints" };
1379 //MenuDivider { debugMenu };
1380 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1381 MenuPlacement imageMenu { menu, $"Image", i };
1382 Menu viewMenu { menu, $"View", v };
1383 MenuItem viewProjectItem
1385 viewMenu, $"Project View", j, alt0, disabled = true;
1386 bool NotifySelect(MenuItem selection, Modifiers mods)
1390 projectView.visible = true;
1391 projectView.Activate();
1396 MenuPlacement { viewMenu, $"View Designer" };
1397 MenuPlacement { viewMenu, $"View Code" };
1398 MenuPlacement { viewMenu, $"View Properties" };
1399 MenuPlacement { viewMenu, $"View Methods" };
1400 MenuItem viewDesignerItem
1402 viewMenu, $"View Designer", d, f8;
1403 bool NotifySelect(MenuItem selection, Modifiers mods)
1405 Window client = activeClient;
1406 Class dataType = client._class;
1407 if(!strcmp(dataType.name, "Designer"))
1409 client.visible = true;
1413 ((CodeEditor)client).ViewDesigner();
1417 MenuItem viewCodeItem
1419 viewMenu, $"View Code", c, f8;
1420 bool NotifySelect(MenuItem selection, Modifiers mods)
1422 Window client = activeClient;
1423 Class dataType = client._class;
1424 if(!strcmp(dataType.name, "Designer"))
1425 client = ((Designer)client).codeEditor;
1428 // Do this after so the caret isn't moved yet...
1429 client.visible = true;
1433 MenuItem viewPropertiesItem
1435 viewMenu, $"View Properties", p, f4;
1436 bool NotifySelect(MenuItem selection, Modifiers mods)
1438 sheet.visible = true;
1439 sheet.sheetSelected = properties;
1444 MenuItem viewMethodsItem
1446 viewMenu, $"View Methods", m, f4;
1447 bool NotifySelect(MenuItem selection, Modifiers mods)
1449 sheet.visible = true;
1450 sheet.sheetSelected = methods;
1455 MenuItem viewToolBoxItem
1457 viewMenu, $"View Toolbox", x, f12;
1458 bool NotifySelect(MenuItem selection, Modifiers mods)
1460 toolBox.visible = true;
1465 MenuItem viewOutputItem
1467 viewMenu, $"Output", o, alt2;
1468 bool NotifySelect(MenuItem selection, Modifiers mods)
1474 MenuItem viewWatchesItem
1476 viewMenu, $"Watches", w, alt3;
1477 bool NotifySelect(MenuItem selection, Modifiers mods)
1483 MenuItem viewThreadsItem
1485 viewMenu, $"Threads", t, alt4;
1486 bool NotifySelect(MenuItem selection, Modifiers mods)
1492 MenuItem viewBreakpointsItem
1494 viewMenu, $"Breakpoints", b, alt5;
1495 bool NotifySelect(MenuItem selection, Modifiers mods)
1497 breakpointsView.Show();
1501 MenuItem viewCallStackItem
1503 viewMenu, $"Call Stack", s, alt7;
1504 bool NotifySelect(MenuItem selection, Modifiers mods)
1506 callStackView.Show();
1510 MenuItem viewAllDebugViews
1512 viewMenu, $"All Debug Views", a, alt9;
1513 bool NotifySelect(MenuItem selection, Modifiers mods)
1518 callStackView.Show();
1519 breakpointsView.Show();
1523 #ifdef GDB_DEBUG_GUI
1524 MenuDivider { viewMenu };
1525 MenuItem viewGDBItem
1527 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1528 bool NotifySelect(MenuItem selection, Modifiers mods)
1535 MenuDivider { viewMenu };
1536 MenuItem viewColorPicker
1538 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1539 bool NotifySelect(MenuItem selection, Modifiers mods)
1541 ColorPicker colorPicker { master = this };
1542 colorPicker.Modal();
1546 MenuDivider { viewMenu };
1550 viewMenu, "Full Screen", f, checkable = true;
1552 bool NotifySelect(MenuItem selection, Modifiers mods)
1554 app.fullScreen ^= true;
1556 anchor = { 0, 0, 0, 0 };
1561 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1563 MenuDivider { viewMenu };
1565 Menu languageMenu { viewMenu, "Language", l };
1567 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1568 Menu windowMenu { menu, $"Window", w };
1569 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1570 MenuDivider { windowMenu };
1571 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1572 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1573 MenuDivider { windowMenu };
1574 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1575 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1576 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1577 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1578 MenuDivider { windowMenu };
1579 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1580 Menu helpMenu { menu, $"Help", h };
1583 helpMenu, $"API Reference", r, f1;
1584 bool NotifySelect(MenuItem selection, Modifiers mods)
1588 char * p = new char[MAX_LOCATION];
1590 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1591 PathCat(p, "documentor");
1592 #if defined(__WIN32__)
1593 ChangeExtension(p, "exe", p);
1595 if(!FileExists(p).isFile)
1596 strcpy(p, "documentor");
1598 documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
1603 Process_ShowWindows(documentor.GetProcessID());
1604 // documentor.Puts("Activate\n");
1609 MenuDivider { helpMenu };
1612 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1613 bool NotifySelect(MenuItem selection, Modifiers mods)
1615 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1619 MenuDivider { helpMenu };
1622 helpMenu, $"Documentation Folder", d;
1623 bool NotifySelect(MenuItem selection, Modifiers mods)
1625 FindAndShellOpenInstalledFolder("doc");
1631 helpMenu, $"Samples Folder", s;
1632 bool NotifySelect(MenuItem selection, Modifiers mods)
1634 FindAndShellOpenInstalledFolder("samples");
1640 helpMenu, $"Extras Folder", x;
1641 bool NotifySelect(MenuItem selection, Modifiers mods)
1643 FindAndShellOpenInstalledFolder("extras");
1647 MenuDivider { helpMenu };
1650 helpMenu, $"Community Forums", f;
1651 bool NotifySelect(MenuItem selection, Modifiers mods)
1653 ShellOpen("http://ecere.com/forums");
1657 MenuDivider { helpMenu };
1660 helpMenu, $"About...", a;
1661 bool NotifySelect(MenuItem selection, Modifiers mods)
1663 AboutIDE { master = this }.Modal();
1668 property ToolBox toolBox
1670 get { return toolBox; }
1673 property Sheet sheet
1675 get { return sheet; }
1678 property Project project
1680 get { return projectView ? projectView.project : null; }
1683 property Workspace workspace
1685 get { return projectView ? projectView.workspace : null; }
1688 FindInFilesDialog findInFilesDialog
1691 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1698 #ifdef GDB_DEBUG_GUI
1701 master = this, parent = this;
1702 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1704 void OnCommand(const char * string)
1707 ide.debugger.SendGDBCommand(string);
1712 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1714 //app.driver = app.drivers[selection.id];
1715 #if defined(__unix__) || defined(__APPLE__)
1716 app.driver = selection.id ? "OpenGL" : "X";
1718 app.driver = selection.id ? "OpenGL" : "GDI";
1720 delete ideSettings.displayDriver;
1721 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1723 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1725 settingsContainer.Save();
1726 //SetDriverAndSkin();
1730 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1732 app.skin = app.skins[selection.id];
1737 void SetDriverAndSkin()
1740 for(c = 0; c < app.numSkins; c++)
1741 if(!strcmp(app.skins[c], app.skin))
1743 skinItems[c].checked = true;
1746 for(c = 0; c < app.numDrivers; c++)
1747 if(!strcmp(app.drivers[c], app.driver))
1749 driverItems[c].checked = true;
1754 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1756 Project project = workspace.projects.firstIterator.data;
1757 projectView = ProjectView
1760 fileName = fileName;
1762 void NotifyDestroyed(Window window, DialogResult result)
1765 text = titleECEREIDE;
1770 projectView.Create();
1771 RepositionWindows(false);
1773 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1774 projectView.workspace = workspace;
1775 projectView.project = project;
1776 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1779 updateRecentMenus();
1781 ide.breakpointsView.LoadFromWorkspace();
1782 ide.watchesView.LoadFromWorkspace();
1784 findInFilesDialog.projectNodeField.userData = projectView;
1787 char fileName[MAX_LOCATION];
1788 strcpy(fileName, project.topNode.path);
1789 PathCat(fileName, project.topNode.name);
1796 projectView.visible = false;
1797 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1799 if(findInFilesDialog)
1801 char workingDir[MAX_LOCATION];
1802 GetWorkingDir(workingDir, MAX_LOCATION);
1803 findInFilesDialog.SearchStop();
1804 findInFilesDialog.currentDirectory = workingDir;
1806 sheet.visible = false;
1807 toolBox.visible = false;
1808 outputView.visible = false;
1809 ideMainFrame.text = titleECEREIDE;
1811 ide.updateRecentMenus();
1817 void RepositionWindows(bool expand)
1822 bool callStackVisible = expand ? false : callStackView.visible;
1823 bool threadsVisible = expand ? false : threadsView.visible;
1824 bool watchesVisible = expand ? false : watchesView.visible;
1825 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1826 bool toolBoxVisible = toolBox.visible;
1827 bool outputVisible = expand ? false : outputView.visible;
1828 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1829 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1831 for(child = firstChild; child; child = child.next)
1833 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1834 child._class == class(Sheet) || child._class == class(ProjectView))
1836 Anchor anchor = child.anchor;
1837 anchor.top = topDistance;
1838 anchor.bottom = bottomDistance;
1839 if(child._class == class(CodeEditor) || child._class == class(Designer))
1841 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1842 anchor.right = toolBoxVisible ? 150 : 0;
1845 child.anchor = anchor;
1849 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1850 child._class == class(BreakpointsView))
1851 child.visible = false;
1854 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1856 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1860 bool ShowCodeEditor()
1863 activeClient.Activate();
1864 else if(projectView)
1866 projectView.visible = true;
1867 projectView.Activate();
1869 else if(sheet.visible)
1872 outputView.visible = false;
1876 void DocumentSaved(Window document, const char * fileName)
1878 ideConfig.recentFiles.addRecent(fileName);
1879 ideConfig.recentFiles.write(settingsContainer);
1880 ide.updateRecentFilesMenu();
1881 ide.AdjustFileMenus();
1884 bool Window::OnFileModified(FileChange fileChange, const char * param)
1887 sprintf(temp, $"The document %s was modified by another application.\n"
1888 "Would you like to reload it and lose your changes?", this.fileName);
1889 if(MessageBox { creationActivation = flash, type = yesNo, master = this/*.parent*/,
1890 text = $"Document has been modified", contents = temp }.Modal() == yes)
1892 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1893 char * fileName = CopyString(this.fileName);
1894 WindowState state = this.state;
1895 Anchor anchor = this.anchor;
1896 Size size = this.size;
1898 this.modifiedDocument = false;
1900 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1903 this.anchor = anchor;
1905 this.SetState(state, true, 0);
1913 void UpdateMakefiles()
1917 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
1918 for(prj : workspace.projects)
1919 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1924 void UpdateCompilerConfigs(bool mute)
1926 UpdateToolBarActiveCompilers();
1929 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1930 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
1933 projectView.ShowOutputBuildLog(true);
1934 projectView.DisplayCompiler(compiler, false);
1936 for(prj : workspace.projects)
1937 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1942 void UpdateToolBarActiveCompilers()
1944 toolBar.activeCompiler.Clear();
1945 for(compiler : ideConfig.compilers)
1947 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1948 if(workspace && workspace.activeCompiler && !strcmp(compiler.name, workspace.activeCompiler))
1949 toolBar.activeCompiler.currentRow = row;
1951 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1952 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1953 toolBar.activeBitDepth.SelectRow(toolBar.activeBitDepth.FindRow(workspace ? workspace.bitDepth : 0));
1956 void UpdateToolBarActiveConfigs(bool selectionOnly)
1958 bool commonSelected = false;
1959 DataRow row = toolBar.activeConfig.currentRow;
1961 row = toolBar.activeConfig.FindRow(1);
1964 toolBar.activeConfig.Clear();
1965 row = toolBar.activeConfig.AddString($"(Mixed)");
1970 char * configName = null;
1973 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1974 for(prj : workspace.projects)
1976 for(cfg : prj.configurations)
1979 configs[cfg.name] = 1;
1984 toolBar.activeConfig.AddString(&name);
1988 if(projectView && projectView.project)
1990 for(prj : workspace.projects)
1992 if(prj.config && prj.config.name)
1994 configName = prj.config.name;
2000 commonSelected = true;
2001 for(prj : workspace.projects)
2003 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
2005 commonSelected = false;
2013 commonSelected = false;
2014 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
2016 if(!strcmp(row.string, configName))
2018 toolBar.activeConfig.currentRow = row;
2019 commonSelected = true;
2026 toolBar.activeConfig.Sort(null, 0);
2028 toolBar.activeConfig.currentRow = row;
2033 bool unavailable = !project;
2035 projectAddItem.disabled = unavailable;
2036 toolBar.buttonAddProject.disabled = unavailable;
2038 projectSettingsItem.disabled = unavailable;
2040 projectBrowseFolderItem.disabled = unavailable;
2042 viewProjectItem.disabled = unavailable;
2044 toolBar.activeConfig.disabled = unavailable;
2045 toolBar.activeCompiler.disabled = unavailable;
2046 toolBar.activeBitDepth.disabled = unavailable;
2049 debugUseValgrindItem.disabled = unavailable;
2050 AdjustValgrindMenus();
2059 void AdjustValgrindMenus()
2061 bool unavailable = !project || !debugUseValgrindItem.checked;
2062 debugValgrindNoLeakCheckItem.disabled = unavailable;
2063 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2064 debugValgrindYesLeakCheckItem.disabled = unavailable;
2065 debugValgrindFullLeakCheckItem.disabled = unavailable;
2067 debugValgrindTrackOriginsItem.disabled = unavailable;
2069 debugValgrindRSDefaultItem.disabled = unavailable;
2070 debugValgrindRS0Item.disabled = unavailable;
2071 debugValgrindRS16Item.disabled = unavailable;
2072 debugValgrindRS32Item.disabled = unavailable;
2073 debugValgrindRS64Item.disabled = unavailable;
2074 debugValgrindRS128Item.disabled = unavailable;
2075 debugValgrindRS256Item.disabled = unavailable;
2076 debugValgrindRS512Item.disabled = unavailable;
2080 property bool hasOpenedCodeEditors
2085 for(w = firstChild; w; w = w.next)
2086 if(w._class == class(CodeEditor) &&
2087 w.isDocument && !w.closing && w.visible && w.created &&
2088 w.fileName && w.fileName[0])
2094 void AdjustFileMenus()
2096 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2098 projectQuickItem.disabled = unavailable;
2101 void AdjustBuildMenus()
2103 bool unavailable = project && projectView.buildInProgress;
2104 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2105 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2107 projectNewItem.disabled = unavailable;
2108 toolBar.buttonNewProject.disabled = unavailable;
2109 projectOpenItem.disabled = unavailable;
2110 toolBar.buttonOpenProject.disabled = unavailable;
2112 unavailable = !project || projectView.buildInProgress;
2114 projectCloseItem.disabled = unavailable;
2115 // toolBar.buttonCloseProject.disabled = unavailable;
2117 projectRunItem.disabled = naForRun;
2118 toolBar.buttonRun.disabled = naForRun;
2120 projectBuildItem.disabled = false;
2121 projectBuildItem.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2122 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2124 projectLinkItem.disabled = unavailable;
2125 toolBar.buttonReLink.disabled = unavailable;
2126 projectRebuildItem.disabled = unavailable;
2127 toolBar.buttonRebuild.disabled = unavailable;
2128 projectCleanItem.disabled = unavailable;
2129 toolBar.buttonClean.disabled = unavailable;
2130 projectCleanTargetItem.disabled = unavailable;
2131 projectRealCleanItem.disabled = unavailable;
2132 // toolBar.buttonRealClean.disabled = unavailable;
2133 projectRegenerateItem.disabled = unavailable;
2134 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2135 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2136 projectInstallItem.disabled = unavailable;
2137 toolBar.buttonInstall.disabled = unavailable;
2139 projectCompileItem.disabled = unavailable;
2141 AdjustPopupBuildMenus();
2144 void AdjustPopupBuildMenus()
2146 bool unavailable = !project || projectView.buildInProgress;
2148 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2151 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2152 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, mode);
2155 menu.disabled = false;
2156 menu.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2157 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2160 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, mode); if(menu) menu.disabled = unavailable;
2161 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, mode); if(menu) menu.disabled = unavailable;
2162 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, mode); if(menu) menu.disabled = unavailable;
2163 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, mode); if(menu) menu.disabled = unavailable;
2164 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, mode); if(menu) menu.disabled = unavailable;
2165 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, mode); if(menu) menu.disabled = unavailable;
2166 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, mode); if(menu) menu.disabled = unavailable;
2167 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, mode); if(menu) menu.disabled = unavailable;
2168 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, mode); if(menu) menu.disabled = unavailable;
2169 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, mode); if(menu) menu.disabled = unavailable;
2170 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, mode); if(menu) menu.disabled = unavailable;
2171 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, mode); if(menu) menu.disabled = unavailable;
2172 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, mode); if(menu) menu.disabled = unavailable;
2173 projectView.popupMenu.Update(null);
2177 property bool areDebugMenusUnavailable { get {
2179 project.GetTargetType(project.config) != executable ||
2180 projectView.buildInProgress == buildingMainProject;
2183 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2184 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2185 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2187 void AdjustDebugMenus()
2189 bool unavailable = areDebugMenusUnavailable;
2190 bool running = isDebuggerRunning;
2191 bool stopped = isDebuggerStopped;
2192 bool active = debugger.isActive;
2194 bool isNotRunning = unavailable || !running;
2195 bool isNotNotRunning = unavailable || running;
2196 bool isNotStopped = unavailable || !stopped;
2197 bool isNotActive = unavailable || !active;
2199 debugStartResumeItem.disabled = isNotNotRunning;
2200 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2201 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2204 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2205 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2208 debugBreakItem.disabled = isNotRunning;
2209 debugStopItem.disabled = isNotActive;
2210 debugRestartItem.disabled = isNotActive;
2213 toolBar.buttonDebugPause.disabled = isNotRunning;
2214 toolBar.buttonDebugStop.disabled = isNotActive;
2215 toolBar.buttonDebugRestart.disabled = isNotActive;
2218 debugStepIntoItem.disabled = isNotNotRunning;
2219 debugStepOverItem.disabled = isNotNotRunning;
2220 debugSkipStepOverItem.disabled = isNotNotRunning;
2221 debugStepOutItem.disabled = isNotStopped;
2222 debugSkipStepOutItem.disabled = isNotStopped;
2224 debugStepUntilItem.disabled = isNotStopped;
2225 debugSkipStepUntilItem.disabled = isNotStopped;
2229 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2230 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2231 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2232 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2233 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2235 if((Designer)GetActiveDesigner())
2237 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2239 codeEditor.AdjustDebugMenus();
2243 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2245 char tempString[MAX_LOCATION];
2246 strcpy(tempString, directory);
2247 if(saveSettings && !projectView)
2249 ideSettings.ideFileDialogLocation = directory;
2250 settingsContainer.Save();
2253 ideFileDialog.currentDirectory = tempString;
2254 codeEditorFileDialog.currentDirectory = tempString;
2255 codeEditorFormFileDialog.currentDirectory = tempString;
2258 void ChangeProjectFileDialogDirectory(char * directory)
2260 ideSettings.ideProjectFileDialogLocation = directory;
2261 settingsContainer.Save();
2264 Window FindWindow(const char * filePath)
2266 Window document = null;
2268 // TOCHECK: Do we need to change slashes here?
2269 for(document = firstChild; document; document = document.next)
2271 const char * fileName = document.fileName;
2272 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2274 document.visible = true;
2275 document.Activate();
2282 bool DontTerminateDebugSession(const char * title)
2284 if(debugger.isActive)
2286 if(MessageBox { type = yesNo, master = ide,
2287 contents = $"Do you want to terminate the debugging session in progress?",
2288 text = title }.Modal() == no)
2291 MessageBox msg { type = yesNo, master = ide,
2292 contents = "Do you want to terminate the debugging session in progress?",
2294 if(msg.Modal() == no)
2306 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2308 char extension[MAX_EXTENSION] = "";
2309 Window document = null;
2310 bool isProject = false;
2311 bool needFileModified = true;
2312 char winFilePath[MAX_LOCATION];
2313 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2314 Window currentDoc = activeClient;
2315 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2318 GetExtension(filePath, extension);
2322 strcpy(extension, type);
2324 if(strcmp(extension, ProjectExtension))
2326 for(document = firstChild; document; document = document.next)
2328 const char * fileName = document.fileName;
2329 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2331 document.visible = true;
2333 document.Activate();
2339 if(createIfFails == whatever)
2341 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2343 needFileModified = false;
2344 if(openMethod == normal)
2346 if(DontTerminateDebugSession($"Open Project"))
2355 Workspace workspace = null;
2357 if(FileExists(filePath))
2359 if(!strcmp(extension, ProjectExtension))
2361 char workspaceFile[MAX_LOCATION];
2362 strcpy(workspaceFile, filePath);
2363 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2364 workspace = LoadWorkspace(workspaceFile, filePath);
2366 else if(!strcmp(extension, WorkspaceExtension))
2367 workspace = LoadWorkspace(filePath, null);
2374 CreateProjectView(workspace, filePath);
2375 document = projectView;
2377 toolBox.visible = true;
2378 sheet.visible = true;
2379 projectView.MakeActive();
2381 workspace.ParseLoadedBreakpoints();
2382 workspace.DropInvalidBreakpoints(null);
2385 ide.projectView.ShowOutputBuildLog(true);
2387 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler);
2388 ide.projectView.DisplayCompiler(compiler, false);
2391 UpdateCompilerConfigs(false);
2394 char newWorkingDir[MAX_LOCATION];
2395 StripLastDirectory(filePath, newWorkingDir);
2396 ChangeFileDialogsDirectory(newWorkingDir, false);
2399 document.fileName = filePath;
2401 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2403 // this crashes on starting ide with epj file, solution please?
2404 // app.UpdateDisplay();
2406 workspace.OpenPreviouslyOpenedFiles(noParsing);
2407 workspace.holdTracking = true;
2408 ide.RepositionWindows(false);
2409 workspace.holdTracking = false;
2411 workspace.timer.Start();
2413 #if !defined(__WIN32__)
2414 // Valgrind Debug menu updates
2415 debugUseValgrindItem.checked = workspace.useValgrind;
2417 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2418 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2419 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2420 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2422 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2423 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2424 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2425 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2426 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2427 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2428 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2429 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2431 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2434 findInFilesDialog.mode = FindInFilesMode::project;
2435 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2438 char location[MAX_LOCATION];
2439 StripLastDirectory(ide.project.topNode.path, location);
2440 ChangeProjectFileDialogDirectory(location);
2447 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2449 ideProjectFileDialog.text = openProjectFileDialogTitle;
2450 if(ideProjectFileDialog.Modal() == cancel)
2452 filePath = ideProjectFileDialog.filePath;
2453 GetExtension(filePath, extension);
2464 else if(openMethod == add)
2469 char slashFilePath[MAX_LOCATION];
2470 GetSlashPathBuffer(slashFilePath, filePath);
2471 for(p : workspace.projects)
2473 if(!fstrcmp(p.filePath, slashFilePath))
2481 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2482 contents = $"This project is already present in workspace." }.Modal();
2486 prj = LoadProject(filePath, null);
2489 const char * activeConfigName = null;
2490 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
2491 prj.StartMonitoring();
2492 workspace.AddProject(prj, null);
2493 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2494 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2495 activeConfigName = toolBar.activeConfig.currentRow.string;
2496 if(activeConfigName)
2498 for(cfg : prj.configurations)
2500 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2508 projectView.AddNode(prj.topNode, null);
2509 workspace.modified = true;
2511 findInFilesDialog.AddProjectItem(prj);
2512 projectView.ShowOutputBuildLog(true);
2513 projectView.DisplayCompiler(compiler, false);
2514 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2518 char location[MAX_LOCATION];
2519 StripLastDirectory(prj.topNode.path, location);
2520 ChangeProjectFileDialogDirectory(location);
2523 // projectView is associated with the main project and not with the one just added but
2524 return projectView; // just to let the caller know something was opened
2532 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2533 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2534 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2536 if(FileExists(filePath))
2537 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2538 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2539 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2542 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2545 else if(!strcmp(extension, "3ds"))
2547 if(FileExists(filePath))
2548 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2549 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2550 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2554 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2557 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2558 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2559 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2560 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2561 !strcmp(extension, "js"))
2563 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2564 editor.updatingCode = true;
2565 if(editor.LoadFile(filePath))
2568 editor.visible = true;
2572 needFileModified = false;
2576 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2577 if(editor.LoadFile(filePath))
2580 editor.visible = true;
2584 needFileModified = false;
2587 if(document && (document._class == class(PictureEdit) ||
2588 document._class == class(ModelView)))
2593 document.fileName = filePath;
2594 if(workspace && !workspace.holdTracking)
2595 workspace.UpdateOpenedFileInfo(filePath, opened, true);
2599 if(!document && createIfFails != no)
2601 if(createIfFails != yes && !needFileModified &&
2602 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2603 createIfFails = yes;
2604 if(createIfFails == yes || createIfFails == whatever)
2606 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2608 document.fileName = filePath;
2614 if(projectView && document._class == class(CodeEditor) && workspace)
2615 workspace.RestorePreviouslyOpenedFileState((CodeEditor)document);
2617 if(needFileModified)
2618 document.OnFileModified = OnFileModified;
2619 document.NotifySaved = DocumentSaved;
2620 if(maximizeDoc && document.hasMaximize)
2621 document.state = maximized;
2625 ideConfig.recentWorkspaces.addRecent(document.fileName);
2626 ideConfig.recentWorkspaces.write(settingsContainer);
2627 ide.updateRecentProjectsMenu();
2630 workspace.recentFiles.addRecent(document.fileName);
2633 ideConfig.recentFiles.addRecent(document.fileName);
2634 ideConfig.recentFiles.write(settingsContainer);
2636 ide.updateRecentFilesMenu();
2637 ide.AdjustFileMenus();
2644 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2645 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2647 if(!parentClosing && ide.workspace)
2648 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2651 bool ModelView::ModelViewOnClose(bool parentClosing)
2653 if(!parentClosing && ide.workspace)
2654 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2657 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2659 if(!parentClosing && ide.workspace)
2660 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2665 void OnUnloadGraphics(Window window)
2667 display.ClearMaterials();
2668 display.ClearTextures();
2669 display.ClearMeshes();
2673 void UpdateStateLight(StatusField fld, bool on)
2675 fld.color = on ? lime : Color { 128,128,128 };
2676 fld.backColor = on ? dimGray : 0;
2680 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2682 UpdateStateLight(caps, app.GetKeyState(capsState));
2683 UpdateStateLight(num, app.GetKeyState(numState));
2687 bool OnKeyDown(Key key, unichar ch)
2691 case b: projectView.Update(null); break;
2692 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2693 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2698 bool OnKeyUp(Key key, unichar ch)
2702 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2703 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2708 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2711 projectView.GoToError(line, noParsing, objectFileExt);
2714 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2716 FileAttribs result { };
2717 FileAttribs fileAttribs;
2721 strcpy(selectedPath, prj.topNode.path);
2722 else if(dir && dir[0])
2723 strcpy(selectedPath, dir);
2725 selectedPath[0] = '\0';
2726 PathCat(selectedPath, filePath);
2728 if((fileAttribs = FileExists(selectedPath)).isFile)
2729 result = fileAttribs;
2733 for(p : workspace.projects)
2735 strcpy(selectedPath, p.topNode.path);
2736 PathCat(selectedPath, filePath);
2737 if((fileAttribs = FileExists(selectedPath)).isFile)
2740 result = fileAttribs;
2747 ProjectNode n = null;
2748 for(p : workspace.projects)
2750 if((n = p.topNode.Find(filePath, false)))
2752 n.GetFullFilePath(selectedPath, true);
2753 if((fileAttribs = FileExists(selectedPath)).isFile)
2756 result = fileAttribs;
2761 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2762 (fileAttribs = FileExists(selectedPath)).isFile)
2765 result = fileAttribs;
2773 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2776 const char *path = text;
2777 char *colon = strchr(text, ':');
2778 char filePath[MAX_LOCATION] = "";
2779 char completePath[MAX_LOCATION];
2780 int line = 0, col = 0;
2781 int len = strlen(text);
2783 FileAttribs fileAttribs;
2785 // support for valgrind output
2786 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2797 /*for(s=colon; *s; s++)
2806 //line = atoi(colon+1);
2808 // support for "Found n match(es) in "file/path";
2809 else if(len > 0 && 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)
2815 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2817 path = (colon - 1 > path) ? colon - 1 : path;
2818 colon = strstr(colon + 1, ":");
2820 if(*path == '*' && (s = strchr(path+1, '*')))
2822 while(isspace(*path)) path++;
2826 char * close = strchr(path, ')');
2830 strncpy(name, path+1, close - path - 1);
2831 name[close - path - 1] = '\0';
2832 for(p : ide.workspace.projects)
2834 if(!strcmp(p.name, name))
2844 prj = project ? project : (dir ? null : ide.project);
2847 strncpy(filePath, path, colon - path);
2848 filePath[colon - path] = '\0';
2849 line = atoi(colon + 1);
2850 colon = strstr(colon + 1, ":");
2852 col = atoi(colon + 1);
2854 else if(path - 1 >= text && *(path - 1) == '\"')
2856 colon = strchr(path, '\"');
2859 strncpy(filePath, path, colon - path);
2860 filePath[colon - path] = '\0';
2863 else if(path && !colon)
2865 strcpy(filePath, path);
2868 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2869 CodeLocationGoTo(completePath, fileAttribs, line, col);
2872 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2874 if(fileAttribs.isFile)
2876 char ext[MAX_EXTENSION];
2877 GetExtension(path, ext);
2879 if(binaryDocExt.Find(ext))
2881 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2882 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2884 char dirPath[MAX_LOCATION];
2885 StripLastDirectory(path, dirPath);
2890 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2891 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2893 EditBox editBox = codeEditor.editBox;
2894 editBox.GoToLineNum(line - 1);
2895 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2899 else if(fileAttribs.isDirectory)
2903 void OnRedraw(Surface surface)
2905 Bitmap bitmap = back.bitmap;
2907 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2910 void SheetSelected(SheetType sheetSelected)
2912 if(activeChild == sheet)
2914 if(sheetSelected == methods)
2916 viewPropertiesItem.accelerator = f4;
2917 viewPropertiesItem.parent = viewMenu;
2918 viewMethodsItem.parent = null;
2922 viewMethodsItem.accelerator = f4;
2923 viewMethodsItem.parent = viewMenu;
2924 viewPropertiesItem.parent = null;
2929 viewMethodsItem.parent = viewMenu;
2930 viewPropertiesItem.parent = viewMenu;
2931 if(sheetSelected == methods)
2933 viewMethodsItem.accelerator = f4;
2934 viewPropertiesItem.accelerator = 0;
2938 viewMethodsItem.accelerator = 0;
2939 viewPropertiesItem.accelerator = f4;
2944 void OnActivateClient(Window client, Window previous)
2946 //if(!client || client != previous)
2949 if(!client || client != previous)
2952 dataType = previous._class;
2953 if(previous && !strcmp(dataType.name, "CodeEditor"))
2955 ((CodeEditor)previous).UpdateFormCode();
2957 else if(previous && !strcmp(dataType.name, "Designer"))
2959 ((Designer)previous).codeEditor.UpdateFormCode();
2964 dataType = client._class;
2965 if(client && !strcmp(dataType.name, "CodeEditor"))
2967 CodeEditor codeEditor = (CodeEditor)client;
2968 SetPrivateModule(codeEditor.privateModule);
2969 SetCurrentContext(codeEditor.globalContext);
2970 SetTopContext(codeEditor.globalContext);
2971 SetGlobalContext(codeEditor.globalContext);
2973 SetDefines(&codeEditor.defines);
2974 SetImports(&codeEditor.imports);
2976 SetActiveDesigner(codeEditor.designer);
2978 sheet.codeEditor = codeEditor;
2979 toolBox.codeEditor = codeEditor;
2981 viewDesignerItem.parent = viewMenu;
2982 if(activeChild != codeEditor)
2984 viewCodeItem.parent = viewMenu;
2985 viewDesignerItem.accelerator = 0;
2986 viewCodeItem.accelerator = f8;
2990 viewCodeItem.parent = null;
2991 viewDesignerItem.accelerator = f8;
2994 else if(client && !strcmp(dataType.name, "Designer"))
2996 CodeEditor codeEditor = ((Designer)client).codeEditor;
2999 SetPrivateModule(codeEditor.privateModule);
3000 SetCurrentContext(codeEditor.globalContext);
3001 SetTopContext(codeEditor.globalContext);
3002 SetGlobalContext(codeEditor.globalContext);
3003 SetDefines(&codeEditor.defines);
3004 SetImports(&codeEditor.imports);
3008 SetPrivateModule(null);
3009 SetCurrentContext(null);
3010 SetTopContext(null);
3011 SetGlobalContext(null);
3016 SetActiveDesigner((Designer)client);
3018 sheet.codeEditor = codeEditor;
3019 toolBox.codeEditor = codeEditor;
3021 viewCodeItem.parent = viewMenu;
3022 if(activeChild != client)
3024 viewDesignerItem.parent = viewMenu;
3025 viewDesignerItem.accelerator = f8;
3026 viewCodeItem.accelerator = 0;
3030 viewDesignerItem.parent = null;
3031 viewCodeItem.accelerator = f8;
3036 if(!client && !projectView && sheet.visible)
3039 sheet.visible = false;
3040 toolBox.visible = false;
3043 sheet.codeEditor = null;
3044 toolBox.codeEditor = null;
3045 SetActiveDesigner(null);
3047 viewDesignerItem.parent = null;
3048 viewCodeItem.parent = null;
3051 SheetSelected(sheet.sheetSelected);
3054 projectCompileItem = null;
3059 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3061 CodeEditor codeEditor = (CodeEditor)client;
3062 EditBox editBox = codeEditor.editBox;
3064 statusBar.AddField(pos);
3066 caps = { width = 40, text = $"CAPS" };
3067 statusBar.AddField(caps);
3068 UpdateStateLight(caps, app.GetKeyState(capsState));
3070 ovr = { width = 36, text = $"OVR" };
3071 statusBar.AddField(ovr);
3072 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3074 num = { width = 36, text = $"NUM" };
3075 statusBar.AddField(num);
3076 UpdateStateLight(num, app.GetKeyState(numState));
3078 //statusBar.text = "Ready";
3080 if(projectView && projectView.project)
3082 bool isCObject = false;
3083 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3084 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3088 char nodeName[MAX_FILENAME];
3089 char name[MAX_FILENAME+96];
3091 ChangeExtension(node.name, "c", nodeName);
3092 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3093 projectCompileItem =
3095 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3097 bool NotifySelect(MenuItem selection, Modifiers mods)
3101 bool isCObject = false;
3102 bool isExcluded = false;
3103 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3107 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3110 List<ProjectNode> nodes { };
3112 projectView.Compile(node.project, nodes, normal, isCObject ? cObject : normal);
3120 projectMenu.AddDynamic(projectCompileItem, ide, false);
3126 caps = ovr = num = null;
3131 bool OnClose(bool parentClosing)
3133 //return !projectView.buildInProgress;
3134 if(projectView && projectView.buildInProgress)
3136 if(DontTerminateDebugSession($"Close IDE"))
3138 if(findInFilesDialog)
3139 findInFilesDialog.SearchStop();
3142 workspace.timer.Stop();
3145 ideMainFrame.Destroy(0);
3152 bool passThrough = false;
3153 bool debugWorkDir = false;
3154 char * passDebugWorkDir = null;
3155 bool openAsText = false;
3156 DynamicString passArgs { };
3159 for(c = 1; c<app.argc; c++)
3163 const char * arg = app.argv[c];
3164 char * buf = new char[strlen(arg)*2+1];
3166 passArgs.concat(" ");
3168 passArgs.concat(buf);
3171 else if(debugWorkDir)
3173 passDebugWorkDir = CopyString(app.argv[c]);
3174 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3175 debugWorkDir = false;
3177 else if(!strcmp(app.argv[c], "-t"))
3179 else if(!strcmp(app.argv[c], "-no-parsing"))
3180 ide.noParsing = true;
3181 else if(!strcmp(app.argv[c], "-debug-start"))
3182 ide.debugStart = true;
3183 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3184 debugWorkDir = true;
3185 else if(!strcmp(app.argv[c], "-@"))
3189 char fullPath[MAX_LOCATION];
3190 char parentPath[MAX_LOCATION];
3191 char ext[MAX_EXTENSION];
3193 FileAttribs dirAttribs;
3194 GetWorkingDir(fullPath, MAX_LOCATION);
3195 PathCat(fullPath, app.argv[c]);
3196 StripLastDirectory(fullPath, parentPath);
3197 GetExtension(app.argv[c], ext);
3198 isProject = !openAsText && !strcmpi(ext, "epj");
3200 if(isProject && c > 1 + (ide.debugStart ? 1 : 0)) continue;
3202 // Create directory for projects (only)
3203 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3205 if(isProject && !FileExists(fullPath))
3207 char name[MAX_LOCATION];
3208 NewProjectDialog newProjectDialog;
3212 projectView.visible = false;
3213 if(!projectView.Destroy(0))
3217 newProjectDialog = { master = this };
3219 strcpy(name, app.argv[c]);
3220 StripExtension(name);
3221 GetLastDirectory(name, name);
3222 newProjectDialog.projectName.contents = name;
3223 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3224 newProjectDialog.locationEditBox.path = parentPath;
3225 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3227 incref newProjectDialog;
3228 newProjectDialog.Modal();
3231 ideConfig.recentWorkspaces.addRecent(projectView.fileName);
3232 ideConfig.recentWorkspaces.write(settingsContainer);
3233 ide.updateRecentMenus();
3235 delete newProjectDialog;
3236 // Open only one project
3240 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3242 else if(strstr(fullPath, "http://") == fullPath)
3243 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3246 if(passThrough && projectView && projectView.project && workspace)
3247 workspace.commandLineArgs = passArgs;
3248 if(passDebugWorkDir && projectView && projectView.project && workspace)
3250 workspace.debugDir = passDebugWorkDir;
3251 delete passDebugWorkDir;
3254 UpdateToolBarActiveConfigs(false);
3255 UpdateToolBarActiveCompilers();
3262 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3265 projectView.visible = false;
3266 projectView.Destroy(0);
3269 #ifdef GDB_DEBUG_GUI
3270 gdbDialog.Destroy(0);
3275 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3279 char * oldPaths[128];
3280 String oldList = new char[maxPathLen];
3281 Array<String> newExePaths { };
3282 //Map<String, bool> exePathExists { };
3284 #if defined(__unix__) || defined(__APPLE__)
3285 Array<String> newLibPaths { };
3286 Map<String, bool> libPathExists { };
3291 for(prj : workspace.projects)
3293 DirExpression targetDirExp;
3295 // SKIP FIRST PROJECT...
3296 if(prj == workspace.projects.firstIterator.data) continue;
3298 // NOTE: Right now the additional project config dir will be
3299 // obtained when the debugger is started, so toggling it
3300 // while building will change which library gets used.
3301 // To go with the initial state, e.g. when F5 was pressed,
3302 // we nould need to keep a list of all project's active
3303 // config upon startup.
3304 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3306 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3310 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3311 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3315 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3316 if(cfg.targetType == sharedLibrary && cfg.debug)
3320 if(targetDirExp.dir)
3322 char buffer[MAX_LOCATION];
3323 #if defined(__WIN32__)
3324 Array<String> paths = newExePaths;
3326 Array<String> paths = newLibPaths;
3328 GetSystemPathBuffer(buffer, prj.topNode.path);
3329 PathCat(buffer, targetDirExp.dir);
3332 if(!fstrcmp(p, buffer))
3339 paths.Add(CopyString(buffer));
3341 delete targetDirExp;
3345 for(item : compiler.executableDirs)
3347 DirExpression dirExpr { };
3348 dirExpr.Evaluate(item, null, compiler, null, 0);
3351 for(p : newExePaths)
3353 if(!fstrcmp(p, dirExpr.dir))
3360 newExePaths.Add(CopySystemPath(dirExpr.dir));
3364 GetEnvironment("PATH", oldList, maxPathLen);
3366 printf("Old value of PATH: %s\n", oldList);
3368 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3369 for(c = 0; c < count; c++)
3372 for(p : newExePaths)
3374 if(!fstrcmp(p, oldPaths[c]))
3381 newExePaths.Add(CopySystemPath(oldPaths[c]));
3385 for(path : newExePaths)
3386 len += strlen(path) + 1;
3387 newList = new char[len + 1];
3389 for(path : newExePaths)
3391 strcat(newList, path);
3392 strcat(newList, pathListSep);
3394 newList[len - 1] = '\0';
3395 SetEnvironment("PATH", newList);
3397 printf("New value of PATH: %s\n", newList);
3404 #if defined(__unix__) || defined(__APPLE__)
3406 for(item : compiler.libraryDirs)
3408 if(!libPathExists[item]) // fstrcmp should be used
3410 String s = CopyString(item);
3412 libPathExists[s] = true;
3416 #if defined(__APPLE__)
3417 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3419 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3422 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3424 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3425 for(c = 0; c < count; c++)
3427 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3429 String s = CopyString(oldPaths[c]);
3431 libPathExists[s] = true;
3436 for(path : newLibPaths)
3437 len += strlen(path) + 1;
3438 newList = new char[len + 1];
3440 for(path : newLibPaths)
3442 strcat(newList, path);
3443 strcat(newList, pathListSep);
3445 newList[len - 1] = '\0';
3446 #if defined(__APPLE__)
3447 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3449 SetEnvironment("LD_LIBRARY_PATH", newList);
3452 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3458 delete libPathExists;
3461 if(compiler.distccEnabled && compiler.distccHosts)
3462 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3467 void DestroyTemporaryProjectDir()
3469 if(tmpPrjDir && tmpPrjDir[0])
3471 if(FileExists(tmpPrjDir).isDirectory)
3472 DestroyDir(tmpPrjDir);
3473 property::tmpPrjDir = null;
3479 // Graphics Driver Menu
3482 app.currentSkin.selectionColor = selectionColor;
3483 app.currentSkin.selectionText = selectionText;
3487 driverItems = new MenuItem[app.numDrivers];
3488 for(c = 0; c < app.numDrivers; c++)
3490 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3491 driverItems[c].id = c;
3492 driverItems[c].isRadio = true;
3495 driverItems = new MenuItem[2];
3496 #if defined(__unix__)
3497 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3498 driverItems[0].id = 0;
3499 driverItems[0].isRadio = true;
3501 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3502 driverItems[0].id = 0;
3503 driverItems[0].isRadio = true;
3505 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3506 driverItems[1].id = 1;
3507 driverItems[1].isRadio = true;
3509 /* skinItems = new MenuItem[app.numSkins];
3510 for(c = 0; c < app.numSkins; c++)
3512 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3513 skinItems[c].id = c;
3514 skinItems[c].isRadio = true;
3517 ideFileDialog.master = this;
3518 ideProjectFileDialog.master = this;
3520 //SetDriverAndSkin();
3524 void updateRecentMenus()
3526 updateRecentFilesMenu();
3527 updateRecentProjectsMenu();
3530 void updateRecentFilesMenu()
3533 char * itemPath = new char[MAX_LOCATION];
3534 char * itemName = new char[MAX_LOCATION+4];
3535 Workspace ws = workspace;
3536 RecentPaths recentFiles = ws ? ws.recentFiles : ideConfig.recentFiles;
3537 recentFilesMenu.Clear();
3538 for(recent : recentFiles)
3540 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3541 MakeSystemPath(itemPath);
3542 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3543 recentFilesMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3550 void updateRecentProjectsMenu()
3553 char * itemPath = new char[MAX_LOCATION];
3554 char * itemName = new char[MAX_LOCATION+4];
3555 recentProjectsMenu.Clear();
3556 for(recent : ideConfig.recentWorkspaces)
3558 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3559 MakeSystemPath(itemPath);
3560 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3561 recentProjectsMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3572 delete languageItems;
3576 documentor.Puts("Quit\n");
3583 void DestroyDir(char * path)
3585 RecursiveDeleteFolderFSI fsi { };
3590 #if defined(__WIN32__)
3591 define sdkDirName = "Ecere SDK";
3593 define sdkDirName = "ecere";
3596 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3599 char * v = new char[maxPathLen];
3603 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3604 StripLastDirectory(path, path);
3605 PathCat(path, subDir);
3606 if(name) PathCat(path, name);
3607 if(FileExists(path) & attribs) found = true;
3609 #if defined(__WIN32__)
3612 for(s : [ "ECERE_SDK_SRC", "AppData", "ALLUSERSPROFILE", "USERPROFILE", "HOMEPATH", "ProgramData", "ProgramFiles", "ProgramFiles(x86)", "SystemDrive" ])
3614 GetEnvironment(s, v, maxPathLen);
3617 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3618 if(!strcmp(s, "SystemDrive"))
3619 PathCat(path, "Program Files");
3620 if(strcmp(s, "ECERE_SDK_SRC"))
3621 PathCat(path, sdkDirName);
3622 PathCat(path, subDir);
3623 if(name) PathCat(path, name);
3624 if(FileExists(path) & attribs)
3639 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3640 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3643 p = new char[MAX_LOCATION];
3645 strcat(p, "/usr/share");
3649 for(c=0; c<numTokens; c++)
3651 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3652 PathCat(path, sdkDirName);
3653 PathCat(path, subDir);
3655 PathCat(path, name);
3656 if(FileExists(path) & attribs)
3669 void FindAndShellOpenInstalledFolder(const char * name)
3671 char path[MAX_LOCATION];
3672 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3676 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3678 char path[MAX_LOCATION];
3679 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3683 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3685 bool preserveRootFolder;
3687 void OutFolder(const char * folderPath, bool isRoot)
3689 if(!(preserveRootFolder && isRoot))
3690 RemoveDir(folderPath);
3693 bool OnFile(const char * filePath)
3695 DeleteFile(filePath);
3700 class IDEApp : GuiApplication
3702 //driver = "Win32Console";
3703 // driver = "OpenGL";
3707 TempFile includeFile { };
3712 char ext[MAX_EXTENSION];
3713 SetLoggingMode(stdOut, null);
3714 //SetLoggingMode(debug, null);
3716 settingsContainer.Load();
3718 if(ideSettings.language)
3720 const String language = GetLanguageString();
3721 if(ideSettings.language.OnCompare(language))
3723 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3728 ide.ApplyFont(ideSettings.codeEditorFont, ideSettings.codeEditorFontSize);
3730 ideConfig.compilers.read(settingsContainer);
3731 ideConfig.recentFiles.read(settingsContainer);
3732 ideConfig.recentWorkspaces.read(settingsContainer);
3734 // First count files arg to decide whether to maximize
3736 bool passThrough = false, debugWorkDir = false;
3739 for(c = 1; c<app.argc; c++)
3742 else if(debugWorkDir)
3743 debugWorkDir = false;
3744 else if(!strcmp(app.argv[c], "-t"));
3745 else if(!strcmp(app.argv[c], "-no-parsing"));
3746 else if(!strcmp(app.argv[c], "-debug-start"));
3747 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3748 debugWorkDir = true;
3749 else if(!strcmp(app.argv[c], "-@"))
3756 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3758 app.driver = "OpenGL";
3759 ide.driverItems[1].checked = true;
3763 #if defined(__unix__) || defined(__APPLE__)
3764 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3766 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3768 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3772 char model[MAX_LOCATION];
3773 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3775 ide.duck.modelFile = model;
3776 ide.duck.parent = ideMainFrame;
3779 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3780 ide.debugRubberDuck.disabled = false;
3784 desktop.caption = titleECEREIDE;
3787 for(c = 1; c<app.argc; c++)
3789 char fullPath[MAX_LOCATION];
3790 GetWorkingDir(fullPath, MAX_LOCATION);
3791 PathCat(fullPath, app.argv[c]);
3792 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3796 // Default to language specified by environment if no language selected
3797 if(!ideSettings.language)
3799 ideSettings.language = GetLanguageString();
3800 settingsContainer.Save();
3803 // Default to home directory if no directory yet set up
3804 if(!ideSettings.ideProjectFileDialogLocation[0])
3807 char location[MAX_LOCATION];
3808 char * home = getenv("HOME");
3809 char * homeDrive = getenv("HOMEDRIVE");
3810 char * homePath = getenv("HOMEPATH");
3811 char * userProfile = getenv("USERPROFILE");
3812 char * systemDrive = getenv("SystemDrive");
3813 if(home && FileExists(home).isDirectory)
3815 strcpy(location, home);
3818 if(!found && homeDrive && homePath)
3820 strcpy(location, homeDrive);
3821 PathCat(location, homePath);
3822 if(FileExists(location).isDirectory)
3825 if(!found && FileExists(userProfile).isDirectory)
3827 strcpy(location, userProfile);
3830 if(!found && FileExists(systemDrive).isDirectory)
3832 strcpy(location, systemDrive);
3837 ideSettings.ideProjectFileDialogLocation = location;
3838 if(!ideSettings.ideFileDialogLocation[0])
3839 ideSettings.ideFileDialogLocation = location;
3843 if(!LoadIncludeFile())
3844 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3846 // Create language menu
3848 String language = ideSettings.language;
3852 ide.languageItems = new MenuItem[languages.count];
3855 ide.languageItems[i] =
3857 ide.languageMenu, l.name;
3858 bitmap = { l.bitmap };
3862 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3864 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3866 // Re-select previous selected language if aborted
3867 String language = ideSettings.language;
3871 if(((!language || !language[0]) && i == 0) ||
3872 (language && !strcmpi(l.code, language)))
3874 ide.languageItems[i].checked = true;
3886 // Try to find country-specific language first
3892 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3894 ide.languageItems[i].checked = true;
3902 // Try generalizing locale
3903 if(!found && language)
3906 char genericLocale[256];
3908 strncpy(genericLocale, language, sizeof(genericLocale));
3909 genericLocale[sizeof(genericLocale)-1] = 0;
3911 under = strchr(genericLocale, '_');
3914 if(!strcmpi(genericLocale, "zh"))
3915 strcpy(genericLocale, "zh_CN");
3916 if(strcmp(genericLocale, language))
3920 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3922 ide.languageItems[i].checked = true;
3932 ide.languageItems[0].checked = true;
3934 MenuDivider { ide.languageMenu };
3937 ide.languageMenu, "Help Translate";
3939 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3941 ShellOpen("http://translations.launchpad.net/ecere");
3947 ideMainFrame.Create();
3948 if(app.argFilesCount > 1)
3949 ide.MenuWindowTileVert(null, 0);
3953 bool Cycle(bool idle)
3957 if(ide.documentor.Peek())
3960 ide.documentor.GetLine(line, sizeof(line));
3961 if(!strcmpi(line, "Exited"))
3963 ide.documentor.CloseInput();
3964 ide.documentor.CloseOutput();
3965 ide.documentor.Wait();
3966 delete ide.documentor;
3969 if(ide.documentor && ide.documentor.eof)
3971 ide.documentor.CloseInput();
3972 ide.documentor.CloseOutput();
3973 ide.documentor.Wait();
3974 delete ide.documentor;
3980 bool LoadIncludeFile()
3982 bool result = false;
3983 File include = FileOpen(":crossplatform.mk", read);
3986 File f = includeFile;
3989 for(; !include.Eof(); )
3992 int count = include.Read(buffer, 1, 4096);
3993 f.Write(buffer, 1, count);
4003 IDEMainFrame ideMainFrame { };
4005 define app = ((IDEApp)__thisModule);
4007 define titleECEREIDE = $"Ecere IDE (Debug)";
4009 define titleECEREIDE = $"Ecere IDE";