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 ProjectView projectView;
449 OutputView outputView
453 void OnGotoError(const char * line, bool noParsing)
455 CompilerConfig compiler = ide.workspace ? ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler) : null;
456 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
457 ide.GoToError(line, noParsing, objectFileExt);
461 void OnCodeLocationParseAndGoTo(const char * line)
463 CompilerConfig compiler = ide.workspace ? ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler) : null;
464 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
465 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir, objectFileExt);
469 bool OnKeyDown(Key key, unichar ch)
474 if(activeBox != findBox || !ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
475 ide.ShowCodeEditor();
479 OutputView::OnKeyDown(key, ch);
486 bool OnClose(bool parentClosing)
490 ide.RepositionWindows(false);
491 return parentClosing;
495 CallStackView callStackView
497 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
499 void OnSelectFrame(int frameIndex)
501 ide.debugger.GoToStackFrameLine(frameIndex, true, true);
503 ide.debugger.SelectFrame(frameIndex);
506 void OnToggleBreakpoint()
508 Debugger debugger = ide.debugger;
509 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
511 int line = debugger.activeFrame.line;
512 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line);
515 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
516 if(codeEditor) { codeEditor.Update(null); Activate(); }
521 bool OnKeyDown(Key key, unichar ch)
525 case escape: ide.ShowCodeEditor(); break;
530 bool OnClose(bool parentClosing)
534 ide.RepositionWindows(false);
535 return parentClosing;
538 void OnRedraw(Surface surface)
540 Debugger debugger = ide.debugger;
541 Frame activeFrame = debugger.activeFrame;
545 int lineCursor, lineTopFrame;
546 int lineH, scrollY, boxH;
548 Breakpoint bp = null;
551 scrollY = editBox.scroll.y;
552 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
553 //activeThread = debugger.activeThread;
554 //hitThread = debugger.hitThread;
555 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
557 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
558 if(activeFrame.absoluteFile)
560 for(i : ide.workspace.breakpoints; i.type == user)
562 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
563 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
564 activeFrame.line == i.line)
572 DrawLineMarginIcon(surface,
573 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
574 lineCursor /*1*/, lineH, scrollY, boxH);
576 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
577 DrawLineMarginIcon(surface,
578 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
579 1, lineH, scrollY, boxH);
581 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
582 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
583 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
585 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
586 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
588 if(editBox.horzScroll && editBox.horzScroll.visible)
590 surface.SetBackground(control);
591 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
596 WatchesView watchesView { parent = this };
597 ThreadsView threadsView
599 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
601 bool OnKeyDown(Key key, unichar ch)
605 case escape: ide.ShowCodeEditor(); break;
610 bool OnClose(bool parentClosing)
614 ide.RepositionWindows(false);
615 return parentClosing;
618 void OnSelectThread(int threadId)
621 ide.debugger.SelectThread(threadId);
624 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
627 Debugger debugger = ide.debugger;
628 *activeThread = debugger.activeThread;
629 *hitThread = debugger.hitThread;
630 *signalThread = debugger.signalThread;
635 BreakpointsView breakpointsView { parent = this };
637 ToolBox toolBox { parent = this, visible = false };
638 Sheet sheet { parent = this, visible = false };
641 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
643 Menu fileMenu { menu, $"File", f, hasMargin = true };
646 fileMenu, $"New", n, ctrlN;
647 bitmap = { ":actions/docNew.png" };
648 bool NotifySelect(MenuItem selection, Modifiers mods)
650 Window currentDoc = activeClient;
651 bool maximizeDoc = ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
652 Window document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, false);
653 RepositionWindows(false);
654 document.NotifySaved = DocumentSaved;
658 MenuItem fileOpenItem
660 fileMenu, $"Open...", o, ctrlO;
661 bitmap = { ":actions/docOpen.png" };
662 bool NotifySelect(MenuItem selection, Modifiers mods)
664 if(!projectView && ideSettings.ideFileDialogLocation)
665 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
668 if(ideFileDialog.Modal() == ok)
670 bool gotWhatWeWant = false;
672 int numSelections = ideFileDialog.numSelections;
673 const char * const * multiFilePaths = ideFileDialog.multiFilePaths;
675 for(c = 0; c < numSelections; c++)
677 if(OpenFile(multiFilePaths[c], false, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
678 gotWhatWeWant = true;
681 MessageBox { type = yesNo, master = this, text = $"Error opening file",
682 contents = $"Open a different file?" }.Modal() == no)
684 if(!projectView && gotWhatWeWant)
685 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
686 ide.RepositionWindows(false);
696 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
697 MenuDivider { fileMenu };
698 MenuItem fileSaveItem
700 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
702 // For the toolbar button; clients can still override that for the menu item
703 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
705 Window w = activeClient;
707 w.MenuFileSave(null, 0);
711 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
712 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
713 MenuDivider { fileMenu };
716 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
717 bool NotifySelect(MenuItem selection, Modifiers mods)
719 findInFilesDialog.replaceMode = false;
720 findInFilesDialog.Show();
724 MenuItem replaceInFiles
726 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
727 bool NotifySelect(MenuItem selection, Modifiers mods)
729 findInFilesDialog.replaceMode = true;
730 findInFilesDialog.Show();
734 MenuDivider { fileMenu };
735 MenuItem globalSettingsItem
737 fileMenu, $"Global Settings...", g;
738 bool NotifySelect(MenuItem selection, Modifiers mods)
740 // Reload configs here until we setup a configs directory monitor
741 ideConfig.compilers.read(settingsContainer);
743 globalSettingsDialog.master = this;
744 if(ide.workspace && ide.workspace.activeCompiler)
745 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.activeCompiler;
746 else if(ideSettings.defaultCompiler)
747 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
748 globalSettingsDialog.Modal();
752 MenuDivider { fileMenu };
753 Menu recentFilesMenu { fileMenu, $"Recent Files", r };
754 Menu recentProjectsMenu { fileMenu, $"Recent Projects", p };
755 MenuDivider { fileMenu };
758 fileMenu, $"Exit", x, altF4;
760 bool NotifySelect(MenuItem selection, Modifiers mods)
762 ideMainFrame.Destroy(0);
767 bool FileRecentFile(MenuItem selection, Modifiers mods)
770 RecentPaths recentFiles = workspace ? workspace.recentFiles : ideConfig.recentFiles;
771 for(file : recentFiles)
773 if(id == selection.id)
776 char extension[MAX_EXTENSION] = "";
777 GetExtension(file, extension);
778 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
779 if(mods.ctrl && !mods.shift)
781 char * command = PrintString("ecere-ide ", isProjectFile ? "-t " : "", file);
787 OpenFile(file, false, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
788 ide.RepositionWindows(false);
797 bool FileRecentProject(MenuItem selection, Modifiers mods)
800 for(file : ideConfig.recentWorkspaces)
802 if(id == selection.id)
804 if(mods.ctrl && !mods.shift)
806 char * command = PrintString("ecere-ide ", file);
811 OpenFile(file, false, true, (mods.ctrl && mods.shift) ? "txt" : null, no, normal, mods.ctrl && mods.shift);
819 MenuPlacement editMenu { menu, $"Edit", e };
821 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
822 MenuItem projectNewItem
824 projectMenu, $"New...", n, Key { n, true, true };
825 bitmap = { ":actions/projNew.png" };
826 bool NotifySelect(MenuItem selection, Modifiers mods)
828 if(!DontTerminateDebugSession($"New Project"))
831 NewProjectDialog newProjectDialog { master = this };
832 incref newProjectDialog;
833 result = newProjectDialog.Modal();
838 newProjectDialog.CreateNewProject();
841 ideConfig.recentWorkspaces.addRecent(projectView.fileName);
842 ideConfig.recentWorkspaces.write(settingsContainer);
843 ide.updateRecentProjectsMenu();
847 delete newProjectDialog;
852 MenuItem projectOpenItem
854 projectMenu, $"Open...", o, Key { o, true, true };
855 bitmap = { ":actions/projOpen.png" };
856 bool NotifySelect(MenuItem selection, Modifiers mods)
858 if(ideSettings.ideProjectFileDialogLocation)
859 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
861 ideProjectFileDialog.text = openProjectFileDialogTitle;
862 if(ideProjectFileDialog.Modal() == ok)
864 OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
865 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
870 MenuItem projectQuickItem
872 projectMenu, $"Quick...", q, f7, disabled = true;
873 bool NotifySelect(MenuItem selection, Modifiers mods)
876 QuickProjectDialog { this }.Modal();
880 MenuItem projectAddItem
882 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
883 bitmap = { ":actions/projAdd.png" };
885 bool NotifySelect(MenuItem selection, Modifiers mods)
887 if(ideSettings.ideProjectFileDialogLocation)
888 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
890 ideProjectFileDialog.text = addProjectFileDialogTitle;
893 if(ideProjectFileDialog.Modal() == ok)
895 if(OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
897 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
898 contents = $"Add a different project?" }.Modal() == no)
909 MenuItem projectCloseItem
911 projectMenu, $"Close", c, disabled = true;
912 bool NotifySelect(MenuItem selection, Modifiers mods)
916 if(!ide.DontTerminateDebugSession($"Project Close"))
922 MenuDivider { projectMenu };
923 MenuItem projectSettingsItem
925 projectMenu, $"Settings...", s, altF7, disabled = true;
926 bool NotifySelect(MenuItem selection, Modifiers mods)
928 projectView.MenuSettings(projectView.active ? selection : null, mods);
932 MenuDivider { projectMenu };
933 MenuItem projectBrowseFolderItem
935 projectMenu, $"Browse Project Folder", p, disabled = true;
936 bool NotifySelect(MenuItem selection, Modifiers mods)
939 projectView.MenuBrowseFolder(null, mods);
943 MenuDivider { projectMenu };
944 MenuItem projectRunItem
946 projectMenu, $"Run", r, ctrlF5, disabled = true;
947 bitmap = { ":actions/run.png" };
948 bool NotifySelect(MenuItem selection, Modifiers mods)
951 projectView.Run(null, mods);
955 MenuItem projectBuildItem
957 projectMenu, $"Build", b, f7, disabled = true;
958 bitmap = { ":actions/build.png" };
959 bool NotifySelect(MenuItem selection, Modifiers mods)
963 if(projectView.buildInProgress == none)
964 projectView.ProjectBuild(projectView.active ? selection : null, mods);
966 projectView.stopBuild = true;
971 MenuItem projectLinkItem
973 projectMenu, $"Relink", l, disabled = true;
974 bitmap = { ":actions/relink.png" };
975 bool NotifySelect(MenuItem selection, Modifiers mods)
978 projectView.ProjectLink(projectView.active ? selection : null, mods);
982 MenuItem projectRebuildItem
984 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
985 bitmap = { ":actions/rebuild.png" };
986 bool NotifySelect(MenuItem selection, Modifiers mods)
989 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
993 MenuItem projectCleanTargetItem
995 projectMenu, $"Clean Target", g, disabled = true;
996 bitmap = { ":actions/clean.png" };
997 bool NotifySelect(MenuItem selection, Modifiers mods)
1002 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
1007 MenuItem projectCleanItem
1009 projectMenu, $"Clean", e, disabled = true;
1010 bitmap = { ":actions/clean.png" };
1011 bool NotifySelect(MenuItem selection, Modifiers mods)
1016 projectView.ProjectClean(projectView.active ? selection : null, mods);
1021 MenuItem projectRealCleanItem
1023 projectMenu, $"Real Clean", disabled = true;
1024 bitmap = { ":actions/clean.png" };
1025 bool NotifySelect(MenuItem selection, Modifiers mods)
1030 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1035 MenuItem projectRegenerateItem
1037 projectMenu, $"Regenerate Makefile", m, disabled = true;
1038 bitmap = { ":actions/regMakefile.png" };
1039 bool NotifySelect(MenuItem selection, Modifiers mods)
1042 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1046 MenuItem projectInstallItem
1048 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
1049 projectMenu, $"Install", t, disabled = true;
1051 bitmap = { ":status/software-update-available.png" };
1052 bool NotifySelect(MenuItem selection, Modifiers mods)
1055 projectView.ProjectInstall(projectView.active ? selection : null, mods);
1059 MenuItem projectCompileItem;
1060 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1061 MenuItem debugStartResumeItem
1063 debugMenu, $"Start", s, f5, disabled = true;
1064 bitmap = { ":actions/debug.png" };
1065 NotifySelect = MenuDebugStart;
1067 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1071 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1072 if(!projectView.DebugStart())
1073 debugStartResumeItem.disabled = false; // same exception
1077 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1080 projectView.DebugResume();
1083 MenuItem debugRestartItem
1085 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1086 bitmap = { ":actions/restart.png" };
1087 bool NotifySelect(MenuItem selection, Modifiers mods)
1090 projectView.DebugRestart();
1094 MenuItem debugBreakItem
1096 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1097 bitmap = { ":actions/pause.png" };
1098 bool NotifySelect(MenuItem selection, Modifiers mods)
1100 if(projectView && projectView.buildInProgress != none)
1103 projectView.DebugBreak();
1107 MenuItem debugStopItem
1109 debugMenu, $"Stop", p, shiftF5, disabled = true;
1110 bitmap = { ":actions/stopDebug.png" };
1111 bool NotifySelect(MenuItem selection, Modifiers mods)
1114 projectView.DebugStop();
1118 MenuDivider { debugMenu };
1122 // nonClient = true,
1129 anchor = { right = 0, bottom = 0 },
1131 isActiveClient = false,
1133 clickThrough = true,
1134 size = { 500, 500 };
1136 bool OnLoadGraphics()
1138 ModelView::OnLoadGraphics();
1139 camera.position.z /= 1.3;
1140 camera.orientation = Euler { yaw = 280, pitch = 20 };
1146 bool OnRightButtonDown(int x, int y, Modifiers mods)
1148 if(!displaySystem.flags.flipping) return true;
1149 MenuWindowMove(null, 0);
1153 bool OnRightButtonUp(int x, int y, Modifiers mods)
1155 position = position;
1160 MenuItem debugRubberDuck
1162 debugMenu, $"Rubber Duck", checkable = true, disabled = true;
1163 bool NotifySelect(MenuItem selection, Modifiers mods)
1165 if(selection.checked)
1173 MenuDivider { debugMenu };
1174 MenuItem debugUseValgrindItem
1176 debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
1177 bool NotifySelect(MenuItem selection, Modifiers mods)
1181 ide.workspace.useValgrind = selection.checked;
1182 ide.workspace.Save();
1184 ide.AdjustValgrindMenus();
1188 Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
1189 MenuItem debugValgrindNoLeakCheckItem { debugValgrindLeakCheckItem, $"No" , f, id = ValgrindLeakCheck::no , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1190 MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; };
1191 MenuItem debugValgrindYesLeakCheckItem { debugValgrindLeakCheckItem, $"Yes" , f, id = ValgrindLeakCheck::yes , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1192 MenuItem debugValgrindFullLeakCheckItem { debugValgrindLeakCheckItem, $"Full" , f, id = ValgrindLeakCheck::full , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1193 bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
1197 if(selection.checked)
1199 ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
1201 debugValgrindNoLeakCheckItem.checked = debugValgrindNoLeakCheckItem.id == vgLeakCheck;
1202 debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
1203 debugValgrindYesLeakCheckItem.checked = debugValgrindYesLeakCheckItem.id == vgLeakCheck;
1204 debugValgrindFullLeakCheckItem.checked = debugValgrindFullLeakCheckItem.id == vgLeakCheck;
1206 ide.workspace.vgLeakCheck = vgLeakCheck;
1207 ide.workspace.Save();
1210 selection.checked = true;
1214 Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
1215 MenuItem debugValgrindRSDefaultItem { debugValgrindRedzoneSizeItem, $"Default", f, id = -1, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; };
1216 MenuItem debugValgrindRS0Item { debugValgrindRedzoneSizeItem, "0" , f, id = 0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1217 MenuItem debugValgrindRS16Item { debugValgrindRedzoneSizeItem, "16" , f, id = 16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1218 MenuItem debugValgrindRS32Item { debugValgrindRedzoneSizeItem, "32" , f, id = 32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1219 MenuItem debugValgrindRS64Item { debugValgrindRedzoneSizeItem, "64" , f, id = 64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1220 MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, "128" , f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1221 MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, "256" , f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1222 MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, "512" , f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1223 bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
1227 if(selection.checked)
1229 int vgRedzoneSize = (int)selection.id;
1231 debugValgrindRSDefaultItem.checked = debugValgrindRSDefaultItem.id == vgRedzoneSize;
1232 debugValgrindRS0Item.checked = debugValgrindRS0Item.id == vgRedzoneSize;
1233 debugValgrindRS16Item.checked = debugValgrindRS16Item.id == vgRedzoneSize;
1234 debugValgrindRS32Item.checked = debugValgrindRS32Item.id == vgRedzoneSize;
1235 debugValgrindRS64Item.checked = debugValgrindRS64Item.id == vgRedzoneSize;
1236 debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
1237 debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
1238 debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
1240 ide.workspace.vgRedzoneSize = vgRedzoneSize;
1241 ide.workspace.Save();
1244 selection.checked = true;
1248 MenuItem debugValgrindTrackOriginsItem
1250 debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
1251 bool NotifySelect(MenuItem selection, Modifiers mods)
1255 ide.workspace.vgTrackOrigins = selection.checked;
1256 ide.workspace.Save();
1262 MenuDivider { debugMenu };
1263 MenuItem debugStepIntoItem
1265 debugMenu, $"Step Into", i, f11, disabled = true;
1266 bitmap = { ":actions/stepInto.png" };
1267 bool NotifySelect(MenuItem selection, Modifiers mods)
1269 if(projectView) projectView.DebugStepInto();
1273 MenuItem debugStepOverItem
1275 debugMenu, $"Step Over", v, f10, disabled = true;
1276 bitmap = { ":actions/stepOver.png" };
1277 bool NotifySelect(MenuItem selection, Modifiers mods)
1279 if(projectView) projectView.DebugStepOver(false);
1283 MenuItem debugSkipStepOverItem
1285 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1286 bitmap = { ":actions/stepOverSkipBreak.png" };
1287 bool NotifySelect(MenuItem selection, Modifiers mods)
1289 if(projectView) projectView.DebugStepOver(true);
1293 MenuItem debugStepOutItem
1295 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1296 bitmap = { ":actions/stepOut.png" };
1297 bool NotifySelect(MenuItem selection, Modifiers mods)
1299 if(projectView) projectView.DebugStepOut(false);
1303 MenuItem debugSkipStepOutItem
1305 debugMenu, $"Step Out Skipping Breakpoints", n, Key { f11, ctrl = true, shift = true }, disabled = true;
1306 bitmap = { ":actions/skipBreaks.png" };
1307 bool NotifySelect(MenuItem selection, Modifiers mods)
1309 if(projectView) projectView.DebugStepOut(true);
1314 MenuItem debugStepUntilItem
1316 debugMenu, $"Step Over Until Next Line", x, disabled = true;
1317 bool NotifySelect(MenuItem selection, Modifiers mods)
1319 if(projectView) projectView.DebugStepUntil(false);
1323 MenuItem debugSkipStepUntilItem
1325 debugMenu, $"Step Over Until Next Line Skipping Breakpoints", e, Key { f10, shift = true, alt = true }, disabled = true;
1326 bool NotifySelect(MenuItem selection, Modifiers mods)
1328 if(projectView) projectView.DebugStepUntil(true);
1333 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1334 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1335 MenuPlacement debugRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level", l };
1336 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", g };
1338 MenuPlacement debugBpRunToCursorItem { debugMenu, $"BP Run To Cursor" };
1339 MenuPlacement debugBpSkipRunToCursorItem { debugMenu, $"BP Run To Cursor Skipping Breakpoints" };
1340 MenuPlacement debugBpRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level" };
1341 MenuPlacement debugBpSkipRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level Skipping Breakpoints" };
1343 //MenuDivider { debugMenu };
1344 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1345 MenuPlacement imageMenu { menu, $"Image", i };
1346 Menu viewMenu { menu, $"View", v };
1347 MenuItem viewProjectItem
1349 viewMenu, $"Project View", j, alt0, disabled = true;
1350 bool NotifySelect(MenuItem selection, Modifiers mods)
1354 projectView.visible = true;
1355 projectView.Activate();
1360 MenuPlacement { viewMenu, $"View Designer" };
1361 MenuPlacement { viewMenu, $"View Code" };
1362 MenuPlacement { viewMenu, $"View Properties" };
1363 MenuPlacement { viewMenu, $"View Methods" };
1364 MenuItem viewDesignerItem
1366 viewMenu, $"View Designer", d, f8;
1367 bool NotifySelect(MenuItem selection, Modifiers mods)
1369 Window client = activeClient;
1370 Class dataType = client._class;
1371 if(!strcmp(dataType.name, "Designer"))
1373 client.visible = true;
1377 ((CodeEditor)client).ViewDesigner();
1381 MenuItem viewCodeItem
1383 viewMenu, $"View Code", c, f8;
1384 bool NotifySelect(MenuItem selection, Modifiers mods)
1386 Window client = activeClient;
1387 Class dataType = client._class;
1388 if(!strcmp(dataType.name, "Designer"))
1389 client = ((Designer)client).codeEditor;
1392 // Do this after so the caret isn't moved yet...
1393 client.visible = true;
1397 MenuItem viewPropertiesItem
1399 viewMenu, $"View Properties", p, f4;
1400 bool NotifySelect(MenuItem selection, Modifiers mods)
1402 sheet.visible = true;
1403 sheet.sheetSelected = properties;
1408 MenuItem viewMethodsItem
1410 viewMenu, $"View Methods", m, f4;
1411 bool NotifySelect(MenuItem selection, Modifiers mods)
1413 sheet.visible = true;
1414 sheet.sheetSelected = methods;
1419 MenuItem viewToolBoxItem
1421 viewMenu, $"View Toolbox", x, f12;
1422 bool NotifySelect(MenuItem selection, Modifiers mods)
1424 toolBox.visible = true;
1429 MenuItem viewOutputItem
1431 viewMenu, $"Output", o, alt2;
1432 bool NotifySelect(MenuItem selection, Modifiers mods)
1438 MenuItem viewWatchesItem
1440 viewMenu, $"Watches", w, alt3;
1441 bool NotifySelect(MenuItem selection, Modifiers mods)
1447 MenuItem viewThreadsItem
1449 viewMenu, $"Threads", t, alt4;
1450 bool NotifySelect(MenuItem selection, Modifiers mods)
1456 MenuItem viewBreakpointsItem
1458 viewMenu, $"Breakpoints", b, alt5;
1459 bool NotifySelect(MenuItem selection, Modifiers mods)
1461 breakpointsView.Show();
1465 MenuItem viewCallStackItem
1467 viewMenu, $"Call Stack", s, alt7;
1468 bool NotifySelect(MenuItem selection, Modifiers mods)
1470 callStackView.Show();
1474 MenuItem viewAllDebugViews
1476 viewMenu, $"All Debug Views", a, alt9;
1477 bool NotifySelect(MenuItem selection, Modifiers mods)
1482 callStackView.Show();
1483 breakpointsView.Show();
1487 #ifdef GDB_DEBUG_GUI
1488 MenuDivider { viewMenu };
1489 MenuItem viewGDBItem
1491 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1492 bool NotifySelect(MenuItem selection, Modifiers mods)
1499 MenuDivider { viewMenu };
1500 MenuItem viewColorPicker
1502 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1503 bool NotifySelect(MenuItem selection, Modifiers mods)
1505 ColorPicker colorPicker { master = this };
1506 colorPicker.Modal();
1510 MenuDivider { viewMenu };
1514 viewMenu, "Full Screen", f, checkable = true;
1516 bool NotifySelect(MenuItem selection, Modifiers mods)
1518 app.fullScreen ^= true;
1520 anchor = { 0, 0, 0, 0 };
1525 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1527 MenuDivider { viewMenu };
1529 Menu languageMenu { viewMenu, "Language", l };
1531 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1532 Menu windowMenu { menu, $"Window", w };
1533 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1534 MenuDivider { windowMenu };
1535 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1536 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1537 MenuDivider { windowMenu };
1538 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1539 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1540 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1541 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1542 MenuDivider { windowMenu };
1543 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1544 Menu helpMenu { menu, $"Help", h };
1547 helpMenu, $"API Reference", r, f1;
1548 bool NotifySelect(MenuItem selection, Modifiers mods)
1552 char * p = new char[MAX_LOCATION];
1554 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1555 PathCat(p, "documentor");
1556 #if defined(__WIN32__)
1557 ChangeExtension(p, "exe", p);
1559 if(!FileExists(p).isFile)
1560 strcpy(p, "documentor");
1562 documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
1567 Process_ShowWindows(documentor.GetProcessID());
1568 // documentor.Puts("Activate\n");
1573 MenuDivider { helpMenu };
1576 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1577 bool NotifySelect(MenuItem selection, Modifiers mods)
1579 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1583 MenuDivider { helpMenu };
1586 helpMenu, $"Documentation Folder", d;
1587 bool NotifySelect(MenuItem selection, Modifiers mods)
1589 FindAndShellOpenInstalledFolder("doc");
1595 helpMenu, $"Samples Folder", s;
1596 bool NotifySelect(MenuItem selection, Modifiers mods)
1598 FindAndShellOpenInstalledFolder("samples");
1604 helpMenu, $"Extras Folder", x;
1605 bool NotifySelect(MenuItem selection, Modifiers mods)
1607 FindAndShellOpenInstalledFolder("extras");
1611 MenuDivider { helpMenu };
1614 helpMenu, $"Community Forums", f;
1615 bool NotifySelect(MenuItem selection, Modifiers mods)
1617 ShellOpen("http://ecere.com/forums");
1621 MenuDivider { helpMenu };
1624 helpMenu, $"About...", a;
1625 bool NotifySelect(MenuItem selection, Modifiers mods)
1627 AboutIDE { master = this }.Modal();
1632 property ToolBox toolBox
1634 get { return toolBox; }
1637 property Sheet sheet
1639 get { return sheet; }
1642 property Project project
1644 get { return projectView ? projectView.project : null; }
1647 property Workspace workspace
1649 get { return projectView ? projectView.workspace : null; }
1652 FindInFilesDialog findInFilesDialog
1655 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1662 #ifdef GDB_DEBUG_GUI
1665 master = this, parent = this;
1666 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1668 void OnCommand(const char * string)
1671 ide.debugger.SendGDBCommand(string);
1676 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1678 //app.driver = app.drivers[selection.id];
1679 #if defined(__unix__) || defined(__APPLE__)
1680 app.driver = selection.id ? "OpenGL" : "X";
1682 app.driver = selection.id ? "OpenGL" : "GDI";
1684 delete ideSettings.displayDriver;
1685 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1687 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1689 settingsContainer.Save();
1690 //SetDriverAndSkin();
1694 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1696 app.skin = app.skins[selection.id];
1701 void SetDriverAndSkin()
1704 for(c = 0; c < app.numSkins; c++)
1705 if(!strcmp(app.skins[c], app.skin))
1707 skinItems[c].checked = true;
1710 for(c = 0; c < app.numDrivers; c++)
1711 if(!strcmp(app.drivers[c], app.driver))
1713 driverItems[c].checked = true;
1718 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1720 Project project = workspace.projects.firstIterator.data;
1721 projectView = ProjectView
1724 fileName = fileName;
1726 void NotifyDestroyed(Window window, DialogResult result)
1729 text = titleECEREIDE;
1734 projectView.Create();
1735 RepositionWindows(false);
1737 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1738 projectView.workspace = workspace;
1739 projectView.project = project;
1740 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1743 updateRecentMenus();
1745 ide.breakpointsView.LoadFromWorkspace();
1746 ide.watchesView.LoadFromWorkspace();
1748 findInFilesDialog.projectNodeField.userData = projectView;
1751 char fileName[MAX_LOCATION];
1752 strcpy(fileName, project.topNode.path);
1753 PathCat(fileName, project.topNode.name);
1760 projectView.visible = false;
1761 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1763 if(findInFilesDialog)
1765 char workingDir[MAX_LOCATION];
1766 GetWorkingDir(workingDir, MAX_LOCATION);
1767 findInFilesDialog.SearchStop();
1768 findInFilesDialog.currentDirectory = workingDir;
1770 sheet.visible = false;
1771 toolBox.visible = false;
1772 outputView.visible = false;
1773 ideMainFrame.text = titleECEREIDE;
1775 ide.updateRecentMenus();
1781 void RepositionWindows(bool expand)
1786 bool callStackVisible = expand ? false : callStackView.visible;
1787 bool threadsVisible = expand ? false : threadsView.visible;
1788 bool watchesVisible = expand ? false : watchesView.visible;
1789 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1790 bool toolBoxVisible = toolBox.visible;
1791 bool outputVisible = expand ? false : outputView.visible;
1792 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1793 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1795 for(child = firstChild; child; child = child.next)
1797 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1798 child._class == class(Sheet) || child._class == class(ProjectView))
1800 Anchor anchor = child.anchor;
1801 anchor.top = topDistance;
1802 anchor.bottom = bottomDistance;
1803 if(child._class == class(CodeEditor) || child._class == class(Designer))
1805 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1806 anchor.right = toolBoxVisible ? 150 : 0;
1809 child.anchor = anchor;
1813 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1814 child._class == class(BreakpointsView))
1815 child.visible = false;
1818 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1820 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1824 bool ShowCodeEditor()
1827 activeClient.Activate();
1828 else if(projectView)
1830 projectView.visible = true;
1831 projectView.Activate();
1833 else if(sheet.visible)
1836 outputView.visible = false;
1840 void DocumentSaved(Window document, const char * fileName)
1842 ideConfig.recentFiles.addRecent(fileName);
1843 ideConfig.recentFiles.write(settingsContainer);
1844 ide.updateRecentFilesMenu();
1845 ide.AdjustFileMenus();
1848 bool Window::OnFileModified(FileChange fileChange, const char * param)
1851 sprintf(temp, $"The document %s was modified by another application.\n"
1852 "Would you like to reload it and lose your changes?", this.fileName);
1853 if(MessageBox { creationActivation = flash, type = yesNo, master = this/*.parent*/,
1854 text = $"Document has been modified", contents = temp }.Modal() == yes)
1856 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1857 char * fileName = CopyString(this.fileName);
1858 WindowState state = this.state;
1859 Anchor anchor = this.anchor;
1860 Size size = this.size;
1862 this.modifiedDocument = false;
1864 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1867 this.anchor = anchor;
1869 this.SetState(state, true, 0);
1877 void UpdateMakefiles()
1881 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
1882 for(prj : workspace.projects)
1883 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1888 void UpdateCompilerConfigs(bool mute)
1890 UpdateToolBarActiveCompilers();
1893 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1894 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
1897 projectView.ShowOutputBuildLog(true);
1898 projectView.DisplayCompiler(compiler, false);
1900 for(prj : workspace.projects)
1901 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1906 void UpdateToolBarActiveCompilers()
1908 toolBar.activeCompiler.Clear();
1909 for(compiler : ideConfig.compilers)
1911 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1912 if(workspace && workspace.activeCompiler && !strcmp(compiler.name, workspace.activeCompiler))
1913 toolBar.activeCompiler.currentRow = row;
1915 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1916 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1917 toolBar.activeBitDepth.SelectRow(toolBar.activeBitDepth.FindRow(workspace ? workspace.bitDepth : 0));
1920 void UpdateToolBarActiveConfigs(bool selectionOnly)
1922 bool commonSelected = false;
1923 DataRow row = toolBar.activeConfig.currentRow;
1925 row = toolBar.activeConfig.FindRow(1);
1928 toolBar.activeConfig.Clear();
1929 row = toolBar.activeConfig.AddString($"(Mixed)");
1934 char * configName = null;
1937 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1938 for(prj : workspace.projects)
1940 for(cfg : prj.configurations)
1943 configs[cfg.name] = 1;
1948 toolBar.activeConfig.AddString(&name);
1952 if(projectView && projectView.project)
1954 for(prj : workspace.projects)
1956 if(prj.config && prj.config.name)
1958 configName = prj.config.name;
1964 commonSelected = true;
1965 for(prj : workspace.projects)
1967 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1969 commonSelected = false;
1977 commonSelected = false;
1978 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1980 if(!strcmp(row.string, configName))
1982 toolBar.activeConfig.currentRow = row;
1983 commonSelected = true;
1990 toolBar.activeConfig.Sort(null, 0);
1992 toolBar.activeConfig.currentRow = row;
1997 bool unavailable = !project;
1999 projectAddItem.disabled = unavailable;
2000 toolBar.buttonAddProject.disabled = unavailable;
2002 projectSettingsItem.disabled = unavailable;
2004 projectBrowseFolderItem.disabled = unavailable;
2006 viewProjectItem.disabled = unavailable;
2008 toolBar.activeConfig.disabled = unavailable;
2009 toolBar.activeCompiler.disabled = unavailable;
2010 toolBar.activeBitDepth.disabled = unavailable;
2013 debugUseValgrindItem.disabled = unavailable;
2014 AdjustValgrindMenus();
2023 void AdjustValgrindMenus()
2025 bool unavailable = !project || !debugUseValgrindItem.checked;
2026 debugValgrindNoLeakCheckItem.disabled = unavailable;
2027 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2028 debugValgrindYesLeakCheckItem.disabled = unavailable;
2029 debugValgrindFullLeakCheckItem.disabled = unavailable;
2031 debugValgrindTrackOriginsItem.disabled = unavailable;
2033 debugValgrindRSDefaultItem.disabled = unavailable;
2034 debugValgrindRS0Item.disabled = unavailable;
2035 debugValgrindRS16Item.disabled = unavailable;
2036 debugValgrindRS32Item.disabled = unavailable;
2037 debugValgrindRS64Item.disabled = unavailable;
2038 debugValgrindRS128Item.disabled = unavailable;
2039 debugValgrindRS256Item.disabled = unavailable;
2040 debugValgrindRS512Item.disabled = unavailable;
2044 property bool hasOpenedCodeEditors
2049 for(w = firstChild; w; w = w.next)
2050 if(w._class == class(CodeEditor) &&
2051 w.isDocument && !w.closing && w.visible && w.created &&
2052 w.fileName && w.fileName[0])
2058 void AdjustFileMenus()
2060 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2062 projectQuickItem.disabled = unavailable;
2065 void AdjustBuildMenus()
2067 bool unavailable = project && projectView.buildInProgress;
2068 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2069 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2071 projectNewItem.disabled = unavailable;
2072 toolBar.buttonNewProject.disabled = unavailable;
2073 projectOpenItem.disabled = unavailable;
2074 toolBar.buttonOpenProject.disabled = unavailable;
2076 unavailable = !project || projectView.buildInProgress;
2078 projectCloseItem.disabled = unavailable;
2079 // toolBar.buttonCloseProject.disabled = unavailable;
2081 projectRunItem.disabled = naForRun;
2082 toolBar.buttonRun.disabled = naForRun;
2084 projectBuildItem.disabled = false;
2085 projectBuildItem.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2086 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2088 projectLinkItem.disabled = unavailable;
2089 toolBar.buttonReLink.disabled = unavailable;
2090 projectRebuildItem.disabled = unavailable;
2091 toolBar.buttonRebuild.disabled = unavailable;
2092 projectCleanItem.disabled = unavailable;
2093 toolBar.buttonClean.disabled = unavailable;
2094 projectCleanTargetItem.disabled = unavailable;
2095 projectRealCleanItem.disabled = unavailable;
2096 // toolBar.buttonRealClean.disabled = unavailable;
2097 projectRegenerateItem.disabled = unavailable;
2098 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2099 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2100 projectInstallItem.disabled = unavailable;
2101 toolBar.buttonInstall.disabled = unavailable;
2103 projectCompileItem.disabled = unavailable;
2105 AdjustPopupBuildMenus();
2108 void AdjustPopupBuildMenus()
2110 bool unavailable = !project || projectView.buildInProgress;
2112 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2115 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2116 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, mode);
2119 menu.disabled = false;
2120 menu.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2121 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2124 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, mode); if(menu) menu.disabled = unavailable;
2125 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, mode); if(menu) menu.disabled = unavailable;
2126 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, mode); if(menu) menu.disabled = unavailable;
2127 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, mode); if(menu) menu.disabled = unavailable;
2128 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, mode); if(menu) menu.disabled = unavailable;
2129 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, mode); if(menu) menu.disabled = unavailable;
2130 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, mode); if(menu) menu.disabled = unavailable;
2131 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, mode); if(menu) menu.disabled = unavailable;
2132 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, mode); if(menu) menu.disabled = unavailable;
2133 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, mode); if(menu) menu.disabled = unavailable;
2134 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, mode); if(menu) menu.disabled = unavailable;
2135 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, mode); if(menu) menu.disabled = unavailable;
2136 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, mode); if(menu) menu.disabled = unavailable;
2137 projectView.popupMenu.Update(null);
2141 property bool areDebugMenusUnavailable { get {
2143 project.GetTargetType(project.config) != executable ||
2144 projectView.buildInProgress == buildingMainProject;
2147 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2148 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2149 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2151 void AdjustDebugMenus()
2153 bool unavailable = areDebugMenusUnavailable;
2154 bool running = isDebuggerRunning;
2155 bool stopped = isDebuggerStopped;
2156 bool active = debugger.isActive;
2158 bool isNotRunning = unavailable || !running;
2159 bool isNotNotRunning = unavailable || running;
2160 bool isNotStopped = unavailable || !stopped;
2161 bool isNotActive = unavailable || !active;
2163 debugStartResumeItem.disabled = isNotNotRunning;
2164 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2165 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2168 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2169 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2172 debugBreakItem.disabled = isNotRunning;
2173 debugStopItem.disabled = isNotActive;
2174 debugRestartItem.disabled = isNotActive;
2177 toolBar.buttonDebugPause.disabled = isNotRunning;
2178 toolBar.buttonDebugStop.disabled = isNotActive;
2179 toolBar.buttonDebugRestart.disabled = isNotActive;
2182 debugStepIntoItem.disabled = isNotNotRunning;
2183 debugStepOverItem.disabled = isNotNotRunning;
2184 debugSkipStepOverItem.disabled = isNotNotRunning;
2185 debugStepOutItem.disabled = isNotStopped;
2186 debugSkipStepOutItem.disabled = isNotStopped;
2188 debugStepUntilItem.disabled = isNotStopped;
2189 debugSkipStepUntilItem.disabled = isNotStopped;
2193 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2194 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2195 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2196 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2197 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2199 if((Designer)GetActiveDesigner())
2201 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2203 codeEditor.AdjustDebugMenus();
2207 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2209 char tempString[MAX_LOCATION];
2210 strcpy(tempString, directory);
2211 if(saveSettings && !projectView)
2213 ideSettings.ideFileDialogLocation = directory;
2214 settingsContainer.Save();
2217 ideFileDialog.currentDirectory = tempString;
2218 codeEditorFileDialog.currentDirectory = tempString;
2219 codeEditorFormFileDialog.currentDirectory = tempString;
2222 void ChangeProjectFileDialogDirectory(char * directory)
2224 ideSettings.ideProjectFileDialogLocation = directory;
2225 settingsContainer.Save();
2228 Window FindWindow(const char * filePath)
2230 Window document = null;
2232 // TOCHECK: Do we need to change slashes here?
2233 for(document = firstChild; document; document = document.next)
2235 const char * fileName = document.fileName;
2236 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2238 document.visible = true;
2239 document.Activate();
2246 bool DontTerminateDebugSession(const char * title)
2248 if(debugger.isActive)
2250 if(MessageBox { type = yesNo, master = ide,
2251 contents = $"Do you want to terminate the debugging session in progress?",
2252 text = title }.Modal() == no)
2255 MessageBox msg { type = yesNo, master = ide,
2256 contents = "Do you want to terminate the debugging session in progress?",
2258 if(msg.Modal() == no)
2270 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2272 char extension[MAX_EXTENSION] = "";
2273 Window document = null;
2274 bool isProject = false;
2275 bool needFileModified = true;
2276 char winFilePath[MAX_LOCATION];
2277 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2278 Window currentDoc = activeClient;
2279 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2282 GetExtension(filePath, extension);
2286 strcpy(extension, type);
2288 if(strcmp(extension, ProjectExtension))
2290 for(document = firstChild; document; document = document.next)
2292 const char * fileName = document.fileName;
2293 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2295 document.visible = true;
2297 document.Activate();
2303 if(createIfFails == whatever)
2305 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2307 needFileModified = false;
2308 if(openMethod == normal)
2310 if(DontTerminateDebugSession($"Open Project"))
2319 Workspace workspace = null;
2321 if(FileExists(filePath))
2323 if(!strcmp(extension, ProjectExtension))
2325 char workspaceFile[MAX_LOCATION];
2326 strcpy(workspaceFile, filePath);
2327 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2328 workspace = LoadWorkspace(workspaceFile, filePath);
2330 else if(!strcmp(extension, WorkspaceExtension))
2331 workspace = LoadWorkspace(filePath, null);
2338 CreateProjectView(workspace, filePath);
2339 document = projectView;
2341 toolBox.visible = true;
2342 sheet.visible = true;
2343 projectView.MakeActive();
2345 workspace.ParseLoadedBreakpoints();
2346 workspace.DropInvalidBreakpoints(null);
2349 ide.projectView.ShowOutputBuildLog(true);
2351 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler);
2352 ide.projectView.DisplayCompiler(compiler, false);
2355 UpdateCompilerConfigs(false);
2358 char newWorkingDir[MAX_LOCATION];
2359 StripLastDirectory(filePath, newWorkingDir);
2360 ChangeFileDialogsDirectory(newWorkingDir, false);
2363 document.fileName = filePath;
2365 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2367 // this crashes on starting ide with epj file, solution please?
2368 // app.UpdateDisplay();
2370 workspace.OpenPreviouslyOpenedFiles(noParsing);
2371 workspace.holdTracking = true;
2372 ide.RepositionWindows(false);
2373 workspace.holdTracking = false;
2375 workspace.timer.Start();
2377 #if !defined(__WIN32__)
2378 // Valgrind Debug menu updates
2379 debugUseValgrindItem.checked = workspace.useValgrind;
2381 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2382 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2383 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2384 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2386 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2387 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2388 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2389 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2390 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2391 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2392 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2393 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2395 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2398 findInFilesDialog.mode = FindInFilesMode::project;
2399 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2402 char location[MAX_LOCATION];
2403 StripLastDirectory(ide.project.topNode.path, location);
2404 ChangeProjectFileDialogDirectory(location);
2411 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2413 ideProjectFileDialog.text = openProjectFileDialogTitle;
2414 if(ideProjectFileDialog.Modal() == cancel)
2416 filePath = ideProjectFileDialog.filePath;
2417 GetExtension(filePath, extension);
2428 else if(openMethod == add)
2433 char slashFilePath[MAX_LOCATION];
2434 GetSlashPathBuffer(slashFilePath, filePath);
2435 for(p : workspace.projects)
2437 if(!fstrcmp(p.filePath, slashFilePath))
2445 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2446 contents = $"This project is already present in workspace." }.Modal();
2450 prj = LoadProject(filePath, null);
2453 const char * activeConfigName = null;
2454 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
2455 prj.StartMonitoring();
2456 workspace.AddProject(prj, null);
2457 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2458 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2459 activeConfigName = toolBar.activeConfig.currentRow.string;
2460 if(activeConfigName)
2462 for(cfg : prj.configurations)
2464 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2472 projectView.AddNode(prj.topNode, null);
2473 workspace.modified = true;
2475 findInFilesDialog.AddProjectItem(prj);
2476 projectView.ShowOutputBuildLog(true);
2477 projectView.DisplayCompiler(compiler, false);
2478 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2482 char location[MAX_LOCATION];
2483 StripLastDirectory(prj.topNode.path, location);
2484 ChangeProjectFileDialogDirectory(location);
2487 // projectView is associated with the main project and not with the one just added but
2488 return projectView; // just to let the caller know something was opened
2496 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2497 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2498 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2500 if(FileExists(filePath))
2501 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2502 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2503 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2506 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2509 else if(!strcmp(extension, "3ds"))
2511 if(FileExists(filePath))
2512 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2513 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2514 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2518 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2521 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2522 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2523 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2524 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2525 !strcmp(extension, "js"))
2527 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2528 editor.updatingCode = true;
2529 if(editor.LoadFile(filePath))
2532 editor.visible = true;
2536 needFileModified = false;
2540 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2541 if(editor.LoadFile(filePath))
2544 editor.visible = true;
2548 needFileModified = false;
2551 if(document && (document._class == class(PictureEdit) ||
2552 document._class == class(ModelView)))
2557 document.fileName = filePath;
2558 if(workspace && !workspace.holdTracking)
2559 workspace.UpdateOpenedFileInfo(filePath, opened, true);
2563 if(!document && createIfFails != no)
2565 if(createIfFails != yes && !needFileModified &&
2566 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2567 createIfFails = yes;
2568 if(createIfFails == yes || createIfFails == whatever)
2570 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2572 document.fileName = filePath;
2578 if(projectView && document._class == class(CodeEditor) && workspace)
2579 workspace.RestorePreviouslyOpenedFileState((CodeEditor)document);
2581 if(needFileModified)
2582 document.OnFileModified = OnFileModified;
2583 document.NotifySaved = DocumentSaved;
2584 if(maximizeDoc && document.hasMaximize)
2585 document.state = maximized;
2589 ideConfig.recentWorkspaces.addRecent(document.fileName);
2590 ideConfig.recentWorkspaces.write(settingsContainer);
2591 ide.updateRecentProjectsMenu();
2594 workspace.recentFiles.addRecent(document.fileName);
2597 ideConfig.recentFiles.addRecent(document.fileName);
2598 ideConfig.recentFiles.write(settingsContainer);
2600 ide.updateRecentFilesMenu();
2601 ide.AdjustFileMenus();
2608 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2609 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2611 if(!parentClosing && ide.workspace)
2612 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2615 bool ModelView::ModelViewOnClose(bool parentClosing)
2617 if(!parentClosing && ide.workspace)
2618 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2621 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2623 if(!parentClosing && ide.workspace)
2624 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2629 void OnUnloadGraphics(Window window)
2631 display.ClearMaterials();
2632 display.ClearTextures();
2633 display.ClearMeshes();
2637 void UpdateStateLight(StatusField fld, bool on)
2639 fld.color = on ? lime : Color { 128,128,128 };
2640 fld.backColor = on ? dimGray : 0;
2644 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2646 UpdateStateLight(caps, app.GetKeyState(capsState));
2647 UpdateStateLight(num, app.GetKeyState(numState));
2651 bool OnKeyDown(Key key, unichar ch)
2655 case b: projectView.Update(null); break;
2656 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2657 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2662 bool OnKeyUp(Key key, unichar ch)
2666 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2667 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2672 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2675 projectView.GoToError(line, noParsing, objectFileExt);
2678 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2680 FileAttribs result { };
2681 FileAttribs fileAttribs;
2685 strcpy(selectedPath, prj.topNode.path);
2686 else if(dir && dir[0])
2687 strcpy(selectedPath, dir);
2689 selectedPath[0] = '\0';
2690 PathCat(selectedPath, filePath);
2692 if((fileAttribs = FileExists(selectedPath)).isFile)
2693 result = fileAttribs;
2697 for(p : workspace.projects)
2699 strcpy(selectedPath, p.topNode.path);
2700 PathCat(selectedPath, filePath);
2701 if((fileAttribs = FileExists(selectedPath)).isFile)
2704 result = fileAttribs;
2711 ProjectNode n = null;
2712 for(p : workspace.projects)
2714 if((n = p.topNode.Find(filePath, false)))
2716 n.GetFullFilePath(selectedPath, true);
2717 if((fileAttribs = FileExists(selectedPath)).isFile)
2720 result = fileAttribs;
2725 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2726 (fileAttribs = FileExists(selectedPath)).isFile)
2729 result = fileAttribs;
2737 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2740 const char *path = text;
2741 char *colon = strchr(text, ':');
2742 char filePath[MAX_LOCATION] = "";
2743 char completePath[MAX_LOCATION];
2744 int line = 0, col = 0;
2745 int len = strlen(text);
2747 FileAttribs fileAttribs;
2749 // support for valgrind output
2750 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2761 /*for(s=colon; *s; s++)
2770 //line = atoi(colon+1);
2772 // support for "Found n match(es) in "file/path";
2773 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)
2779 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2781 path = (colon - 1 > path) ? colon - 1 : path;
2782 colon = strstr(colon + 1, ":");
2784 if(*path == '*' && (s = strchr(path+1, '*')))
2786 while(isspace(*path)) path++;
2790 char * close = strchr(path, ')');
2794 strncpy(name, path+1, close - path - 1);
2795 name[close - path - 1] = '\0';
2796 for(p : ide.workspace.projects)
2798 if(!strcmp(p.name, name))
2808 prj = project ? project : (dir ? null : ide.project);
2811 strncpy(filePath, path, colon - path);
2812 filePath[colon - path] = '\0';
2813 line = atoi(colon + 1);
2814 colon = strstr(colon + 1, ":");
2816 col = atoi(colon + 1);
2818 else if(path - 1 >= text && *(path - 1) == '\"')
2820 colon = strchr(path, '\"');
2823 strncpy(filePath, path, colon - path);
2824 filePath[colon - path] = '\0';
2827 else if(path && !colon)
2829 strcpy(filePath, path);
2832 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2833 CodeLocationGoTo(completePath, fileAttribs, line, col);
2836 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2838 if(fileAttribs.isFile)
2840 char ext[MAX_EXTENSION];
2841 GetExtension(path, ext);
2843 if(binaryDocExt.Find(ext))
2845 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2846 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2848 char dirPath[MAX_LOCATION];
2849 StripLastDirectory(path, dirPath);
2854 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2855 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2857 EditBox editBox = codeEditor.editBox;
2858 editBox.GoToLineNum(line - 1);
2859 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2863 else if(fileAttribs.isDirectory)
2867 void OnRedraw(Surface surface)
2869 Bitmap bitmap = back.bitmap;
2871 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2874 void SheetSelected(SheetType sheetSelected)
2876 if(activeChild == sheet)
2878 if(sheetSelected == methods)
2880 viewPropertiesItem.accelerator = f4;
2881 viewPropertiesItem.parent = viewMenu;
2882 viewMethodsItem.parent = null;
2886 viewMethodsItem.accelerator = f4;
2887 viewMethodsItem.parent = viewMenu;
2888 viewPropertiesItem.parent = null;
2893 viewMethodsItem.parent = viewMenu;
2894 viewPropertiesItem.parent = viewMenu;
2895 if(sheetSelected == methods)
2897 viewMethodsItem.accelerator = f4;
2898 viewPropertiesItem.accelerator = 0;
2902 viewMethodsItem.accelerator = 0;
2903 viewPropertiesItem.accelerator = f4;
2908 void OnActivateClient(Window client, Window previous)
2910 //if(!client || client != previous)
2913 if(!client || client != previous)
2916 dataType = previous._class;
2917 if(previous && !strcmp(dataType.name, "CodeEditor"))
2919 ((CodeEditor)previous).UpdateFormCode();
2921 else if(previous && !strcmp(dataType.name, "Designer"))
2923 ((Designer)previous).codeEditor.UpdateFormCode();
2928 dataType = client._class;
2929 if(client && !strcmp(dataType.name, "CodeEditor"))
2931 CodeEditor codeEditor = (CodeEditor)client;
2932 SetPrivateModule(codeEditor.privateModule);
2933 SetCurrentContext(codeEditor.globalContext);
2934 SetTopContext(codeEditor.globalContext);
2935 SetGlobalContext(codeEditor.globalContext);
2937 SetDefines(&codeEditor.defines);
2938 SetImports(&codeEditor.imports);
2940 SetActiveDesigner(codeEditor.designer);
2942 sheet.codeEditor = codeEditor;
2943 toolBox.codeEditor = codeEditor;
2945 viewDesignerItem.parent = viewMenu;
2946 if(activeChild != codeEditor)
2948 viewCodeItem.parent = viewMenu;
2949 viewDesignerItem.accelerator = 0;
2950 viewCodeItem.accelerator = f8;
2954 viewCodeItem.parent = null;
2955 viewDesignerItem.accelerator = f8;
2958 else if(client && !strcmp(dataType.name, "Designer"))
2960 CodeEditor codeEditor = ((Designer)client).codeEditor;
2963 SetPrivateModule(codeEditor.privateModule);
2964 SetCurrentContext(codeEditor.globalContext);
2965 SetTopContext(codeEditor.globalContext);
2966 SetGlobalContext(codeEditor.globalContext);
2967 SetDefines(&codeEditor.defines);
2968 SetImports(&codeEditor.imports);
2972 SetPrivateModule(null);
2973 SetCurrentContext(null);
2974 SetTopContext(null);
2975 SetGlobalContext(null);
2980 SetActiveDesigner((Designer)client);
2982 sheet.codeEditor = codeEditor;
2983 toolBox.codeEditor = codeEditor;
2985 viewCodeItem.parent = viewMenu;
2986 if(activeChild != client)
2988 viewDesignerItem.parent = viewMenu;
2989 viewDesignerItem.accelerator = f8;
2990 viewCodeItem.accelerator = 0;
2994 viewDesignerItem.parent = null;
2995 viewCodeItem.accelerator = f8;
3000 if(!client && !projectView && sheet.visible)
3003 sheet.visible = false;
3004 toolBox.visible = false;
3007 sheet.codeEditor = null;
3008 toolBox.codeEditor = null;
3009 SetActiveDesigner(null);
3011 viewDesignerItem.parent = null;
3012 viewCodeItem.parent = null;
3015 SheetSelected(sheet.sheetSelected);
3018 projectCompileItem = null;
3023 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3025 CodeEditor codeEditor = (CodeEditor)client;
3026 EditBox editBox = codeEditor.editBox;
3028 statusBar.AddField(pos);
3030 caps = { width = 40, text = $"CAPS" };
3031 statusBar.AddField(caps);
3032 UpdateStateLight(caps, app.GetKeyState(capsState));
3034 ovr = { width = 36, text = $"OVR" };
3035 statusBar.AddField(ovr);
3036 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3038 num = { width = 36, text = $"NUM" };
3039 statusBar.AddField(num);
3040 UpdateStateLight(num, app.GetKeyState(numState));
3042 //statusBar.text = "Ready";
3044 if(projectView && projectView.project)
3046 bool isCObject = false;
3047 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3048 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3052 char nodeName[MAX_FILENAME];
3053 char name[MAX_FILENAME+96];
3055 ChangeExtension(node.name, "c", nodeName);
3056 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3057 projectCompileItem =
3059 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3061 bool NotifySelect(MenuItem selection, Modifiers mods)
3065 bool isCObject = false;
3066 bool isExcluded = false;
3067 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3071 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3074 List<ProjectNode> nodes { };
3076 projectView.Compile(node.project, nodes, normal, isCObject ? cObject : normal);
3084 projectMenu.AddDynamic(projectCompileItem, ide, false);
3090 caps = ovr = num = null;
3095 bool OnClose(bool parentClosing)
3097 //return !projectView.buildInProgress;
3098 if(projectView && projectView.buildInProgress)
3100 if(DontTerminateDebugSession($"Close IDE"))
3102 if(findInFilesDialog)
3103 findInFilesDialog.SearchStop();
3106 workspace.timer.Stop();
3109 ideMainFrame.Destroy(0);
3116 bool passThrough = false;
3117 bool debugWorkDir = false;
3118 char * passDebugWorkDir = null;
3119 bool openAsText = false;
3120 DynamicString passArgs { };
3123 for(c = 1; c<app.argc; c++)
3127 const char * arg = app.argv[c];
3128 char * buf = new char[strlen(arg)*2+1];
3130 passArgs.concat(" ");
3132 passArgs.concat(buf);
3135 else if(debugWorkDir)
3137 passDebugWorkDir = CopyString(app.argv[c]);
3138 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3139 debugWorkDir = false;
3141 else if(!strcmp(app.argv[c], "-t"))
3143 else if(!strcmp(app.argv[c], "-no-parsing"))
3144 ide.noParsing = true;
3145 else if(!strcmp(app.argv[c], "-debug-start"))
3146 ide.debugStart = true;
3147 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3148 debugWorkDir = true;
3149 else if(!strcmp(app.argv[c], "-@"))
3153 char fullPath[MAX_LOCATION];
3154 char parentPath[MAX_LOCATION];
3155 char ext[MAX_EXTENSION];
3157 FileAttribs dirAttribs;
3158 GetWorkingDir(fullPath, MAX_LOCATION);
3159 PathCat(fullPath, app.argv[c]);
3160 StripLastDirectory(fullPath, parentPath);
3161 GetExtension(app.argv[c], ext);
3162 isProject = !openAsText && !strcmpi(ext, "epj");
3164 if(isProject && c > 1 + (ide.debugStart ? 1 : 0)) continue;
3166 // Create directory for projects (only)
3167 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3169 if(isProject && !FileExists(fullPath))
3171 char name[MAX_LOCATION];
3172 NewProjectDialog newProjectDialog;
3176 projectView.visible = false;
3177 if(!projectView.Destroy(0))
3181 newProjectDialog = { master = this };
3183 strcpy(name, app.argv[c]);
3184 StripExtension(name);
3185 GetLastDirectory(name, name);
3186 newProjectDialog.projectName.contents = name;
3187 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3188 newProjectDialog.locationEditBox.path = parentPath;
3189 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3191 incref newProjectDialog;
3192 newProjectDialog.Modal();
3195 ideConfig.recentWorkspaces.addRecent(projectView.fileName);
3196 ideConfig.recentWorkspaces.write(settingsContainer);
3197 ide.updateRecentMenus();
3199 delete newProjectDialog;
3200 // Open only one project
3204 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3206 else if(strstr(fullPath, "http://") == fullPath)
3207 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3210 if(passThrough && projectView && projectView.project && workspace)
3211 workspace.commandLineArgs = passArgs;
3212 if(passDebugWorkDir && projectView && projectView.project && workspace)
3214 workspace.debugDir = passDebugWorkDir;
3215 delete passDebugWorkDir;
3218 UpdateToolBarActiveConfigs(false);
3219 UpdateToolBarActiveCompilers();
3226 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3229 projectView.visible = false;
3230 projectView.Destroy(0);
3233 #ifdef GDB_DEBUG_GUI
3234 gdbDialog.Destroy(0);
3239 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3243 char * oldPaths[128];
3244 String oldList = new char[maxPathLen];
3245 Array<String> newExePaths { };
3246 //Map<String, bool> exePathExists { };
3248 #if defined(__unix__) || defined(__APPLE__)
3249 Array<String> newLibPaths { };
3250 Map<String, bool> libPathExists { };
3255 for(prj : workspace.projects)
3257 DirExpression targetDirExp;
3259 // SKIP FIRST PROJECT...
3260 if(prj == workspace.projects.firstIterator.data) continue;
3262 // NOTE: Right now the additional project config dir will be
3263 // obtained when the debugger is started, so toggling it
3264 // while building will change which library gets used.
3265 // To go with the initial state, e.g. when F5 was pressed,
3266 // we nould need to keep a list of all project's active
3267 // config upon startup.
3268 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3270 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3274 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3275 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3279 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3280 if(cfg.targetType == sharedLibrary && cfg.debug)
3284 if(targetDirExp.dir)
3286 char buffer[MAX_LOCATION];
3287 #if defined(__WIN32__)
3288 Array<String> paths = newExePaths;
3290 Array<String> paths = newLibPaths;
3292 GetSystemPathBuffer(buffer, prj.topNode.path);
3293 PathCat(buffer, targetDirExp.dir);
3296 if(!fstrcmp(p, buffer))
3303 paths.Add(CopyString(buffer));
3305 delete targetDirExp;
3309 for(item : compiler.executableDirs)
3311 DirExpression dirExpr { };
3312 dirExpr.Evaluate(item, null, compiler, null, 0);
3315 for(p : newExePaths)
3317 if(!fstrcmp(p, dirExpr.dir))
3324 newExePaths.Add(CopySystemPath(dirExpr.dir));
3328 GetEnvironment("PATH", oldList, maxPathLen);
3330 printf("Old value of PATH: %s\n", oldList);
3332 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3333 for(c = 0; c < count; c++)
3336 for(p : newExePaths)
3338 if(!fstrcmp(p, oldPaths[c]))
3345 newExePaths.Add(CopySystemPath(oldPaths[c]));
3349 for(path : newExePaths)
3350 len += strlen(path) + 1;
3351 newList = new char[len + 1];
3353 for(path : newExePaths)
3355 strcat(newList, path);
3356 strcat(newList, pathListSep);
3358 newList[len - 1] = '\0';
3359 SetEnvironment("PATH", newList);
3361 printf("New value of PATH: %s\n", newList);
3368 #if defined(__unix__) || defined(__APPLE__)
3370 for(item : compiler.libraryDirs)
3372 if(!libPathExists[item]) // fstrcmp should be used
3374 String s = CopyString(item);
3376 libPathExists[s] = true;
3380 #if defined(__APPLE__)
3381 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3383 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3386 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3388 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3389 for(c = 0; c < count; c++)
3391 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3393 String s = CopyString(oldPaths[c]);
3395 libPathExists[s] = true;
3400 for(path : newLibPaths)
3401 len += strlen(path) + 1;
3402 newList = new char[len + 1];
3404 for(path : newLibPaths)
3406 strcat(newList, path);
3407 strcat(newList, pathListSep);
3409 newList[len - 1] = '\0';
3410 #if defined(__APPLE__)
3411 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3413 SetEnvironment("LD_LIBRARY_PATH", newList);
3416 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3422 delete libPathExists;
3425 if(compiler.distccEnabled && compiler.distccHosts)
3426 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3431 void DestroyTemporaryProjectDir()
3433 if(tmpPrjDir && tmpPrjDir[0])
3435 if(FileExists(tmpPrjDir).isDirectory)
3436 DestroyDir(tmpPrjDir);
3437 property::tmpPrjDir = null;
3443 // Graphics Driver Menu
3446 app.currentSkin.selectionColor = selectionColor;
3447 app.currentSkin.selectionText = selectionText;
3451 driverItems = new MenuItem[app.numDrivers];
3452 for(c = 0; c < app.numDrivers; c++)
3454 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3455 driverItems[c].id = c;
3456 driverItems[c].isRadio = true;
3459 driverItems = new MenuItem[2];
3460 #if defined(__unix__)
3461 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3462 driverItems[0].id = 0;
3463 driverItems[0].isRadio = true;
3465 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3466 driverItems[0].id = 0;
3467 driverItems[0].isRadio = true;
3469 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3470 driverItems[1].id = 1;
3471 driverItems[1].isRadio = true;
3473 /* skinItems = new MenuItem[app.numSkins];
3474 for(c = 0; c < app.numSkins; c++)
3476 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3477 skinItems[c].id = c;
3478 skinItems[c].isRadio = true;
3481 ideFileDialog.master = this;
3482 ideProjectFileDialog.master = this;
3484 //SetDriverAndSkin();
3488 void updateRecentMenus()
3490 updateRecentFilesMenu();
3491 updateRecentProjectsMenu();
3494 void updateRecentFilesMenu()
3497 char * itemPath = new char[MAX_LOCATION];
3498 char * itemName = new char[MAX_LOCATION+4];
3499 Workspace ws = workspace;
3500 RecentPaths recentFiles = ws ? ws.recentFiles : ideConfig.recentFiles;
3501 recentFilesMenu.Clear();
3502 for(recent : recentFiles)
3504 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3505 MakeSystemPath(itemPath);
3506 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3507 recentFilesMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3514 void updateRecentProjectsMenu()
3517 char * itemPath = new char[MAX_LOCATION];
3518 char * itemName = new char[MAX_LOCATION+4];
3519 recentProjectsMenu.Clear();
3520 for(recent : ideConfig.recentWorkspaces)
3522 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3523 MakeSystemPath(itemPath);
3524 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3525 recentProjectsMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3536 delete languageItems;
3540 documentor.Puts("Quit\n");
3547 void DestroyDir(char * path)
3549 RecursiveDeleteFolderFSI fsi { };
3554 #if defined(__WIN32__)
3555 define sdkDirName = "Ecere SDK";
3557 define sdkDirName = "ecere";
3560 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3563 char * v = new char[maxPathLen];
3567 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3568 StripLastDirectory(path, path);
3569 PathCat(path, subDir);
3570 if(name) PathCat(path, name);
3571 if(FileExists(path) & attribs) found = true;
3573 #if defined(__WIN32__)
3576 for(s : [ "ECERE_SDK_SRC", "AppData", "ALLUSERSPROFILE", "USERPROFILE", "HOMEPATH", "ProgramData", "ProgramFiles", "ProgramFiles(x86)", "SystemDrive" ])
3578 GetEnvironment(s, v, maxPathLen);
3581 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3582 if(!strcmp(s, "SystemDrive"))
3583 PathCat(path, "Program Files");
3584 if(strcmp(s, "ECERE_SDK_SRC"))
3585 PathCat(path, sdkDirName);
3586 PathCat(path, subDir);
3587 if(name) PathCat(path, name);
3588 if(FileExists(path) & attribs)
3603 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3604 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3607 p = new char[MAX_LOCATION];
3609 strcat(p, "/usr/share");
3613 for(c=0; c<numTokens; c++)
3615 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3616 PathCat(path, sdkDirName);
3617 PathCat(path, subDir);
3619 PathCat(path, name);
3620 if(FileExists(path) & attribs)
3633 void FindAndShellOpenInstalledFolder(const char * name)
3635 char path[MAX_LOCATION];
3636 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3640 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3642 char path[MAX_LOCATION];
3643 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3647 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3649 bool preserveRootFolder;
3651 void OutFolder(const char * folderPath, bool isRoot)
3653 if(!(preserveRootFolder && isRoot))
3654 RemoveDir(folderPath);
3657 bool OnFile(const char * filePath)
3659 DeleteFile(filePath);
3664 class IDEApp : GuiApplication
3666 //driver = "Win32Console";
3667 // driver = "OpenGL";
3671 TempFile includeFile { };
3676 char ext[MAX_EXTENSION];
3677 SetLoggingMode(stdOut, null);
3678 //SetLoggingMode(debug, null);
3680 settingsContainer.Load();
3682 if(ideSettings.language)
3684 const String language = GetLanguageString();
3685 if(ideSettings.language.OnCompare(language))
3687 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3692 ideConfig.compilers.read(settingsContainer);
3693 ideConfig.recentFiles.read(settingsContainer);
3694 ideConfig.recentWorkspaces.read(settingsContainer);
3696 // First count files arg to decide whether to maximize
3698 bool passThrough = false, debugWorkDir = false;
3701 for(c = 1; c<app.argc; c++)
3704 else if(debugWorkDir)
3705 debugWorkDir = false;
3706 else if(!strcmp(app.argv[c], "-t"));
3707 else if(!strcmp(app.argv[c], "-no-parsing"));
3708 else if(!strcmp(app.argv[c], "-debug-start"));
3709 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3710 debugWorkDir = true;
3711 else if(!strcmp(app.argv[c], "-@"))
3718 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3720 app.driver = "OpenGL";
3721 ide.driverItems[1].checked = true;
3725 #if defined(__unix__) || defined(__APPLE__)
3726 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3728 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3730 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3734 char model[MAX_LOCATION];
3735 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3737 ide.duck.modelFile = model;
3738 ide.duck.parent = ideMainFrame;
3741 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3742 ide.debugRubberDuck.disabled = false;
3746 desktop.caption = titleECEREIDE;
3749 for(c = 1; c<app.argc; c++)
3751 char fullPath[MAX_LOCATION];
3752 GetWorkingDir(fullPath, MAX_LOCATION);
3753 PathCat(fullPath, app.argv[c]);
3754 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3758 // Default to language specified by environment if no language selected
3759 if(!ideSettings.language)
3761 ideSettings.language = GetLanguageString();
3762 settingsContainer.Save();
3765 // Default to home directory if no directory yet set up
3766 if(!ideSettings.ideProjectFileDialogLocation[0])
3769 char location[MAX_LOCATION];
3770 char * home = getenv("HOME");
3771 char * homeDrive = getenv("HOMEDRIVE");
3772 char * homePath = getenv("HOMEPATH");
3773 char * userProfile = getenv("USERPROFILE");
3774 char * systemDrive = getenv("SystemDrive");
3775 if(home && FileExists(home).isDirectory)
3777 strcpy(location, home);
3780 if(!found && homeDrive && homePath)
3782 strcpy(location, homeDrive);
3783 PathCat(location, homePath);
3784 if(FileExists(location).isDirectory)
3787 if(!found && FileExists(userProfile).isDirectory)
3789 strcpy(location, userProfile);
3792 if(!found && FileExists(systemDrive).isDirectory)
3794 strcpy(location, systemDrive);
3799 ideSettings.ideProjectFileDialogLocation = location;
3800 if(!ideSettings.ideFileDialogLocation[0])
3801 ideSettings.ideFileDialogLocation = location;
3805 if(!LoadIncludeFile())
3806 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3808 // Create language menu
3810 String language = ideSettings.language;
3814 ide.languageItems = new MenuItem[languages.count];
3817 ide.languageItems[i] =
3819 ide.languageMenu, l.name;
3820 bitmap = { l.bitmap };
3824 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3826 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3828 // Re-select previous selected language if aborted
3829 String language = ideSettings.language;
3833 if(((!language || !language[0]) && i == 0) ||
3834 (language && !strcmpi(l.code, language)))
3836 ide.languageItems[i].checked = true;
3848 // Try to find country-specific language first
3854 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3856 ide.languageItems[i].checked = true;
3864 // Try generalizing locale
3865 if(!found && language)
3868 char genericLocale[256];
3870 strncpy(genericLocale, language, sizeof(genericLocale));
3871 genericLocale[sizeof(genericLocale)-1] = 0;
3873 under = strchr(genericLocale, '_');
3876 if(!strcmpi(genericLocale, "zh"))
3877 strcpy(genericLocale, "zh_CN");
3878 if(strcmp(genericLocale, language))
3882 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3884 ide.languageItems[i].checked = true;
3894 ide.languageItems[0].checked = true;
3896 MenuDivider { ide.languageMenu };
3899 ide.languageMenu, "Help Translate";
3901 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3903 ShellOpen("http://translations.launchpad.net/ecere");
3909 ideMainFrame.Create();
3910 if(app.argFilesCount > 1)
3911 ide.MenuWindowTileVert(null, 0);
3915 bool Cycle(bool idle)
3919 if(ide.documentor.Peek())
3922 ide.documentor.GetLine(line, sizeof(line));
3923 if(!strcmpi(line, "Exited"))
3925 ide.documentor.CloseInput();
3926 ide.documentor.CloseOutput();
3927 ide.documentor.Wait();
3928 delete ide.documentor;
3931 if(ide.documentor && ide.documentor.eof)
3933 ide.documentor.CloseInput();
3934 ide.documentor.CloseOutput();
3935 ide.documentor.Wait();
3936 delete ide.documentor;
3942 bool LoadIncludeFile()
3944 bool result = false;
3945 File include = FileOpen(":crossplatform.mk", read);
3948 File f = includeFile;
3951 for(; !include.Eof(); )
3954 int count = include.Read(buffer, 1, 4096);
3955 f.Write(buffer, 1, count);
3965 IDEMainFrame ideMainFrame { };
3967 define app = ((IDEApp)__thisModule);
3969 define titleECEREIDE = $"Ecere IDE (Debug)";
3971 define titleECEREIDE = $"Ecere IDE";