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 define maxPathLen = 65 * MAX_LOCATION;
64 class PathBackup : struct
71 oldPath = new char[maxPathLen];
72 oldLDPath = new char[maxPathLen];
74 GetEnvironment("PATH", oldPath, maxPathLen);
75 #if defined(__APPLE__)
76 GetEnvironment("DYLD_LIBRARY_PATH", oldLDPath, maxPathLen);
78 GetEnvironment("LD_LIBRARY_PATH", oldLDPath, maxPathLen);
84 SetEnvironment("PATH", oldPath);
85 #if defined(__APPLE__)
86 SetEnvironment("DYLD_LIBRARY_PATH", oldLDPath);
88 SetEnvironment("LD_LIBRARY_PATH", oldLDPath);
95 enum OpenCreateIfFails { no, yes, something, whatever };
96 enum OpenMethod { normal, add };
98 static Array<FileFilter> fileFilters
100 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
101 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
102 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
103 { $"Text files (*.txt, *.text, *.nfo, *.info)", "txt, text, nfo, info" },
104 { $"Web files (*.html, *.htm, *.xhtml, *.css, *.php, *.js, *.jsi, *.rb, *.xml)", "html, htm, xhtml, css, php, js, jsi, rb, xml" },
105 { $"Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", "jpg, jpeg, bmp, pcx, png, gif" },
106 { $"3D Studio Model Files (*.3ds)", "3ds" },
107 { $"All files", null }
110 static Array<FileType> fileTypes
112 { $"Based on extension", null },
115 { $"3D Studio Model", "3ds" }
118 static Array<FileFilter> projectFilters
120 { $"Project Files (*.epj)", ProjectExtension }
123 static Array<FileType> projectTypes
125 { $"Project File", ProjectExtension }
128 static Array<FileFilter> findInFilesFileFilters
130 { $"eC Files (*.ec, *.eh)", "ec, eh" },
131 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
132 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
133 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
134 { $"Text files (*.txt)", "txt" },
135 { $"All files", null }
138 FileDialog ideFileDialog
140 type = multiOpen, text = $"Open";
141 types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType), filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter);
144 define openProjectFileDialogTitle = $"Open Project";
145 define addProjectFileDialogTitle = $"Open Additional Project";
146 FileDialog ideProjectFileDialog
149 types = projectTypes.array, sizeTypes = projectTypes.count * sizeof(FileType), filters = projectFilters.array, sizeFilters = projectFilters.count * sizeof(FileFilter);
152 GlobalSettingsDialog globalSettingsDialog
154 ideSettings = ideSettings;
155 settingsContainer = settingsContainer;
157 void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange)
159 switch(globalSettingsChange)
164 for(child = ide.firstChild; child; child = child.next)
166 if(child._class == class(CodeEditor))
168 CodeEditor codeEditor = (CodeEditor) child;
169 codeEditor.editBox.freeCaret = ideSettings.useFreeCaret;
170 // codeEditor.editBox.lineNumbers = ideSettings.showLineNumbers;
171 codeEditor.editBox.caretFollowsScrolling = ideSettings.caretFollowsScrolling;
172 codeEditor.OnPostCreate(); // Update editBox margin size
179 case compilerSettings:
181 ide.UpdateCompilerConfigs(true);
188 void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
193 lineY = (line - 1) * lineH;
194 if(lineY + lineH > scrollY && lineY + lineH < scrollY + boxH)
196 Bitmap bitmap = resource.bitmap;
198 surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
203 #define IDEItem(x) (&((IDEWorkSpace)0).x)
205 class IDEToolbar : ToolBar
209 ToolButton buttonNewFile { this, toolTip = $"New file", menuItemPtr = IDEItem(fileNewItem) };
211 ToolButton buttonOpenFile { this, toolTip = $"Open file", menuItemPtr = IDEItem(fileOpenItem) };
213 // ToolButton buttonCloseFile { this, toolTip = $"Close file", menuItemPtr = IDEItem(fileCloseItem) };
215 ToolButton buttonSaveFile { this, toolTip = $"Save file", menuItemPtr = IDEItem(fileSaveItem) };
217 ToolButton buttonSaveAllFile { this, toolTip = $"Save all", menuItemPtr = IDEItem(fileSaveAllItem) };
219 ToolSeparator separator1 { this };
228 // ToolSeparator separator2 { this };
232 ToolButton buttonNewProject { this, toolTip = $"New project", menuItemPtr = IDEItem(projectNewItem) };
234 ToolButton buttonOpenProject { this, toolTip = $"Open project", menuItemPtr = IDEItem(projectOpenItem) };
235 // Add project to workspace
236 ToolButton buttonAddProject { this, toolTip = $"Add project to workspace", menuItemPtr = IDEItem(projectAddItem), disabled = true; };
238 // ToolButton buttonCloseProject { this, toolTip = $"Close project", menuItemPtr = IDEItem(projectCloseItem), disabled = true; };
240 ToolSeparator separator3 { this };
242 // Build/Execution options
244 ToolButton buttonBuild { this, toolTip = $"Build project", menuItemPtr = IDEItem(projectBuildItem), disabled = true; };
246 ToolButton buttonReLink { this, toolTip = $"Relink project", menuItemPtr = IDEItem(projectLinkItem), disabled = true; };
248 ToolButton buttonRebuild { this, toolTip = $"Rebuild project", menuItemPtr = IDEItem(projectRebuildItem), disabled = true; };
250 ToolButton buttonClean { this, toolTip = $"Clean project", menuItemPtr = IDEItem(projectCleanItem), disabled = true; };
252 // ToolButton buttonRealClean { this, toolTip = $"Real clean project", menuItemPtr = IDEItem(projectRealCleanItem), disabled = true; };
253 // Regenerate Makefile
254 ToolButton buttonRegenerateMakefile { this, toolTip = $"Regenerate Makefile", menuItemPtr = IDEItem(projectRegenerateItem), disabled = true; };
255 // Compile actual file
257 ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem), disabled = true; };
258 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
259 ToolButton buttonInstall { this, toolTip = $"Install", menuItemPtr = IDEItem(projectInstallItem), disabled = true; };
262 ToolSeparator separator4 { this };
266 ToolButton buttonDebugStartResume { this, toolTip = $"Start", menuItemPtr = IDEItem(debugStartResumeItem), disabled = true; };
268 ToolButton buttonDebugRestart { this, toolTip = $"Restart", menuItemPtr = IDEItem(debugRestartItem), disabled = true; };
270 ToolButton buttonDebugPause { this, toolTip = $"Break", menuItemPtr = IDEItem(debugBreakItem), disabled = true; };
272 ToolButton buttonDebugStop { this, toolTip = $"Stop", menuItemPtr = IDEItem(debugStopItem), disabled = true; };
274 //ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem) };
276 ToolButton buttonDebugStepInto { this, toolTip = $"Step Into", menuItemPtr = IDEItem(debugStepIntoItem), disabled = true; };
278 ToolButton buttonDebugStepOver { this, toolTip = $"Step Over", menuItemPtr = IDEItem(debugStepOverItem), disabled = true; };
280 ToolButton buttonDebugStepOut { this, toolTip = $"Step Out", menuItemPtr = IDEItem(debugStepOutItem), disabled = true; };
282 ToolButton buttonDebugSkipStepOver { this, toolTip = $"Step Over Skipping Breakpoints", menuItemPtr = IDEItem(debugSkipStepOverItem), disabled = true; };
284 ToolSeparator separator5 { this };
286 Window spacer5 { this, size = { 4 } };
290 this, toolTip = $"Active Configuration(s)", size = { 160 }, disabled = true;
291 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
294 ide.workspace.SelectActiveConfig(row.string);
299 Window spacer6 { this, size = { 4 } };
301 DropBox activeCompiler
303 this, toolTip = $"Active Compiler", size = { 160 }, disabled = true;
304 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
306 if(ide.workspace && ide.projectView && row && strcmp(row.string, ide.workspace.activeCompiler))
308 bool silent = ide.projectView.buildInProgress == none ? false : true;
309 CompilerConfig compiler = ideSettings.GetCompilerConfig(row.string);
310 ide.workspace.activeCompiler = row.string;
311 ide.projectView.ShowOutputBuildLog(!silent);
313 ide.projectView.DisplayCompiler(compiler, false);
314 for(prj : ide.workspace.projects)
315 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
317 ide.workspace.Save();
323 DropBox activeBitDepth
325 this, toolTip = $"Active Bit Length", size = { 60 }, disabled = true;
326 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
328 if(ide.workspace && ide.projectView && row)
330 bool silent = ide.projectView.buildInProgress == none ? false : true;
331 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
332 ide.workspace.bitDepth = (int)row.tag;
333 ide.projectView.ShowOutputBuildLog(!silent);
335 ide.projectView.DisplayCompiler(compiler, false);
336 for(prj : ide.workspace.projects)
337 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
339 ide.workspace.Save();
345 Window spacer7 { this, size = { 4 } };
350 row = activeBitDepth.AddString("Auto");
352 activeBitDepth.AddString("32 bit").tag = 32;
353 activeBitDepth.AddString("64 bit").tag = 64;
354 activeBitDepth.currentRow = row;
358 class IDEMainFrame : Window
360 background = formColor;
361 borderStyle = sizable;
365 minClientSize = { 600, 300 };
367 icon = { ":icon.png" };
368 text = titleECEREIDE;
372 anchor = { top = 0, right = 0, bottom = 0 };
375 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
382 isActiveClient = true;
384 direction = vertical;
385 background = formColor;
386 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
394 ((IDEWorkSpace)master).toolBar = null;
397 IDEWorkSpace ideWorkSpace { stack, this, toolBar = toolBar };
400 define ide = ideMainFrame.ideWorkSpace;
402 class IDEWorkSpace : Window
404 background = Color { 85, 85, 85 };
407 hasVertScroll = true;
408 hasHorzScroll = true;
410 isActiveClient = true;
411 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
415 MenuItem * driverItems, * skinItems, * languageItems;
416 StatusField pos { width = 150 };
417 StatusField ovr, caps, num;
420 BitmapResource back { ":ecereBack.jpg", window = this };
421 BitmapResource bmpBp { ":codeMarks/breakpoint.png", window = this };
422 BitmapResource bmpBpDisabled { ":codeMarks/breakpointDisabled.png", window = this };
423 BitmapResource bmpBpHalf { ":codeMarks/breakpointHalf.png", window = this };
424 BitmapResource bmpBpHalfDisabled { ":codeMarks/breakpointHalfDisabled.png", window = this };
425 BitmapResource bmpCursor { ":codeMarks/cursor.png", window = this };
426 BitmapResource bmpCursorError { ":codeMarks/cursorError.png", window = this };
427 BitmapResource bmpTopFrame { ":codeMarks/topFrame.png", window = this };
428 BitmapResource bmpTopFrameError { ":codeMarks/topFrameError.png", window = this };
429 BitmapResource bmpTopFrameHalf { ":codeMarks/topFrameHalf.png", window = this };
430 BitmapResource bmpTopFrameHalfError { ":codeMarks/topFrameHalfError.png", window = this };
432 BuildOutputMode rightClickMenuBuildOutputMode;
434 Debugger debugger { };
436 ProjectView projectView;
438 OutputView outputView
442 void OnGotoError(const char * line, bool noParsing)
444 CompilerConfig compiler = ide.workspace ? ideSettings.GetCompilerConfig(ide.workspace.activeCompiler) : null;
445 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
446 ide.GoToError(line, noParsing, objectFileExt);
449 void OnCodeLocationParseAndGoTo(const char * line)
451 CompilerConfig compiler = ide.workspace ? ideSettings.GetCompilerConfig(ide.workspace.activeCompiler) : null;
452 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
453 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir, objectFileExt);
456 bool OnKeyDown(Key key, unichar ch)
461 if(activeBox != findBox || !ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
462 ide.ShowCodeEditor();
466 OutputView::OnKeyDown(key, ch);
473 bool OnClose(bool parentClosing)
477 ide.RepositionWindows(false);
478 return parentClosing;
482 CallStackView callStackView
484 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
486 void OnSelectFrame(int frameIndex)
488 ide.debugger.GoToStackFrameLine(frameIndex, true, true);
490 ide.debugger.SelectFrame(frameIndex);
493 void OnToggleBreakpoint()
495 Debugger debugger = ide.debugger;
496 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
498 int line = debugger.activeFrame.line;
499 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line);
502 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
503 if(codeEditor) { codeEditor.Update(null); Activate(); }
508 bool OnKeyDown(Key key, unichar ch)
512 case escape: ide.ShowCodeEditor(); break;
517 bool OnClose(bool parentClosing)
521 ide.RepositionWindows(false);
522 return parentClosing;
525 void OnRedraw(Surface surface)
527 Debugger debugger = ide.debugger;
528 Frame activeFrame = debugger.activeFrame;
532 int lineCursor, lineTopFrame;
533 int lineH, scrollY, boxH;
535 Breakpoint bp = null;
538 scrollY = editBox.scroll.y;
539 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
540 //activeThread = debugger.activeThread;
541 //hitThread = debugger.hitThread;
542 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
544 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
545 if(activeFrame.absoluteFile)
547 for(i : ide.workspace.breakpoints; i.type == user)
549 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
550 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
551 activeFrame.line == i.line)
559 DrawLineMarginIcon(surface,
560 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
561 lineCursor /*1*/, lineH, scrollY, boxH);
563 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
564 DrawLineMarginIcon(surface,
565 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
566 1, lineH, scrollY, boxH);
568 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
569 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
570 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
572 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
573 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
575 if(editBox.horzScroll && editBox.horzScroll.visible)
577 surface.SetBackground(control);
578 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
583 WatchesView watchesView { parent = this };
584 ThreadsView threadsView
586 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
588 bool OnKeyDown(Key key, unichar ch)
592 case escape: ide.ShowCodeEditor(); break;
597 bool OnClose(bool parentClosing)
601 ide.RepositionWindows(false);
602 return parentClosing;
605 void OnSelectThread(int threadId)
608 ide.debugger.SelectThread(threadId);
611 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
614 Debugger debugger = ide.debugger;
615 *activeThread = debugger.activeThread;
616 *hitThread = debugger.hitThread;
617 *signalThread = debugger.signalThread;
622 BreakpointsView breakpointsView { parent = this };
624 ToolBox toolBox { parent = this, visible = false };
625 Sheet sheet { parent = this, visible = false };
628 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
630 Menu fileMenu { menu, $"File", f, hasMargin = true };
633 fileMenu, $"New", n, ctrlN;
634 bitmap = { ":actions/docNew.png" };
635 bool NotifySelect(MenuItem selection, Modifiers mods)
637 Window currentDoc = activeClient;
638 bool maximizeDoc = ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
639 Window document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, false);
640 RepositionWindows(false);
641 document.NotifySaved = DocumentSaved;
645 MenuItem fileOpenItem
647 fileMenu, $"Open...", o, ctrlO;
648 bitmap = { ":actions/docOpen.png" };
649 bool NotifySelect(MenuItem selection, Modifiers mods)
651 if(!projectView && ideSettings.ideFileDialogLocation)
652 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
655 if(ideFileDialog.Modal() == ok)
657 bool gotWhatWeWant = false;
659 int numSelections = ideFileDialog.numSelections;
660 const char * const * multiFilePaths = ideFileDialog.multiFilePaths;
662 for(c = 0; c < numSelections; c++)
664 if(OpenFile(multiFilePaths[c], false, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
665 gotWhatWeWant = true;
668 MessageBox { type = yesNo, master = this, text = $"Error opening file",
669 contents = $"Open a different file?" }.Modal() == no)
671 if(!projectView && gotWhatWeWant)
672 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
673 ide.RepositionWindows(false);
683 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
684 MenuDivider { fileMenu };
685 MenuItem fileSaveItem
687 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
689 // For the toolbar button; clients can still override that for the menu item
690 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
692 Window w = activeClient;
694 w.MenuFileSave(null, 0);
698 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
699 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
700 MenuDivider { fileMenu };
703 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
704 bool NotifySelect(MenuItem selection, Modifiers mods)
706 findInFilesDialog.replaceMode = false;
707 findInFilesDialog.Show();
711 MenuItem replaceInFiles
713 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
714 bool NotifySelect(MenuItem selection, Modifiers mods)
716 findInFilesDialog.replaceMode = true;
717 findInFilesDialog.Show();
721 MenuDivider { fileMenu };
722 MenuItem globalSettingsItem
724 fileMenu, $"Global Settings...", g;
725 bool NotifySelect(MenuItem selection, Modifiers mods)
727 globalSettingsDialog.master = this;
728 if(ide.workspace && ide.workspace.activeCompiler)
729 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.activeCompiler;
730 else if(ideSettings.defaultCompiler)
731 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
732 globalSettingsDialog.Modal();
736 MenuDivider { fileMenu };
737 Menu recentFilesMenu { fileMenu, $"Recent Files", r };
738 Menu recentProjectsMenu { fileMenu, $"Recent Projects", p };
739 MenuDivider { fileMenu };
742 fileMenu, $"Exit", x, altF4;
744 bool NotifySelect(MenuItem selection, Modifiers mods)
746 ideMainFrame.Destroy(0);
751 bool FileRecentFile(MenuItem selection, Modifiers mods)
754 RecentPaths recentFiles = workspace ? workspace.recentFiles : ideSettings.recentFiles;
755 for(file : recentFiles)
757 if(id == selection.id)
760 char extension[MAX_EXTENSION] = "";
761 GetExtension(file, extension);
762 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
763 if(mods.ctrl && !mods.shift)
765 char * command = PrintString("ecere-ide ", isProjectFile ? "-t " : "", file);
771 OpenFile(file, false, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
772 ide.RepositionWindows(false);
781 bool FileRecentProject(MenuItem selection, Modifiers mods)
784 for(file : ideSettings.recentProjects)
786 if(id == selection.id)
788 if(mods.ctrl && !mods.shift)
790 char * command = PrintString("ecere-ide ", file);
795 OpenFile(file, false, true, (mods.ctrl && mods.shift) ? "txt" : null, no, normal, mods.ctrl && mods.shift);
803 MenuPlacement editMenu { menu, $"Edit", e };
805 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
806 MenuItem projectNewItem
808 projectMenu, $"New...", n, Key { n, true, true };
809 bitmap = { ":actions/projNew.png" };
810 bool NotifySelect(MenuItem selection, Modifiers mods)
812 if(!DontTerminateDebugSession($"New Project"))
815 NewProjectDialog newProjectDialog { master = this };
816 incref newProjectDialog;
817 result = newProjectDialog.Modal();
822 newProjectDialog.CreateNewProject();
825 ideSettings.recentProjects.addRecent(CopyString(projectView.fileName));
826 ide.updateRecentProjectsMenu();
827 settingsContainer.Save();
831 delete newProjectDialog;
836 MenuItem projectOpenItem
838 projectMenu, $"Open...", o, Key { o, true, true };
839 bitmap = { ":actions/projOpen.png" };
840 bool NotifySelect(MenuItem selection, Modifiers mods)
842 if(ideSettings.ideProjectFileDialogLocation)
843 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
845 ideProjectFileDialog.text = openProjectFileDialogTitle;
846 if(ideProjectFileDialog.Modal() == ok)
848 OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
849 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
854 MenuItem projectQuickItem
856 projectMenu, $"Quick...", q, f7, disabled = true;
857 bool NotifySelect(MenuItem selection, Modifiers mods)
860 QuickProjectDialog { this }.Modal();
864 MenuItem projectAddItem
866 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
867 bitmap = { ":actions/projAdd.png" };
869 bool NotifySelect(MenuItem selection, Modifiers mods)
871 if(ideSettings.ideProjectFileDialogLocation)
872 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
874 ideProjectFileDialog.text = addProjectFileDialogTitle;
877 if(ideProjectFileDialog.Modal() == ok)
879 if(OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
881 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
882 contents = $"Add a different project?" }.Modal() == no)
893 MenuItem projectCloseItem
895 projectMenu, $"Close", c, disabled = true;
896 bool NotifySelect(MenuItem selection, Modifiers mods)
900 if(!ide.DontTerminateDebugSession($"Project Close"))
906 MenuDivider { projectMenu };
907 MenuItem projectSettingsItem
909 projectMenu, $"Settings...", s, altF7, disabled = true;
910 bool NotifySelect(MenuItem selection, Modifiers mods)
912 projectView.MenuSettings(projectView.active ? selection : null, mods);
916 MenuDivider { projectMenu };
917 MenuItem projectBrowseFolderItem
919 projectMenu, $"Browse Project Folder", p, disabled = true;
920 bool NotifySelect(MenuItem selection, Modifiers mods)
923 projectView.MenuBrowseFolder(null, mods);
927 MenuDivider { projectMenu };
928 MenuItem projectRunItem
930 projectMenu, $"Run", r, ctrlF5, disabled = true;
931 bitmap = { ":actions/run.png" };
932 bool NotifySelect(MenuItem selection, Modifiers mods)
935 projectView.Run(null, mods);
939 MenuItem projectBuildItem
941 projectMenu, $"Build", b, f7, disabled = true;
942 bitmap = { ":actions/build.png" };
943 bool NotifySelect(MenuItem selection, Modifiers mods)
947 if(projectView.buildInProgress == none)
948 projectView.ProjectBuild(projectView.active ? selection : null, mods);
950 projectView.stopBuild = true;
955 MenuItem projectLinkItem
957 projectMenu, $"Relink", l, disabled = true;
958 bitmap = { ":actions/relink.png" };
959 bool NotifySelect(MenuItem selection, Modifiers mods)
962 projectView.ProjectLink(projectView.active ? selection : null, mods);
966 MenuItem projectRebuildItem
968 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
969 bitmap = { ":actions/rebuild.png" };
970 bool NotifySelect(MenuItem selection, Modifiers mods)
973 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
977 MenuItem projectCleanTargetItem
979 projectMenu, $"Clean Target", g, disabled = true;
980 bitmap = { ":actions/clean.png" };
981 bool NotifySelect(MenuItem selection, Modifiers mods)
986 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
991 MenuItem projectCleanItem
993 projectMenu, $"Clean", e, disabled = true;
994 bitmap = { ":actions/clean.png" };
995 bool NotifySelect(MenuItem selection, Modifiers mods)
1000 projectView.ProjectClean(projectView.active ? selection : null, mods);
1005 MenuItem projectRealCleanItem
1007 projectMenu, $"Real Clean", disabled = true;
1008 bitmap = { ":actions/clean.png" };
1009 bool NotifySelect(MenuItem selection, Modifiers mods)
1014 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1019 MenuItem projectRegenerateItem
1021 projectMenu, $"Regenerate Makefile", m, disabled = true;
1022 bitmap = { ":actions/regMakefile.png" };
1023 bool NotifySelect(MenuItem selection, Modifiers mods)
1026 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1030 MenuItem projectInstallItem
1032 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
1033 projectMenu, $"Install", t, disabled = true;
1035 bitmap = { ":status/software-update-available.png" };
1036 bool NotifySelect(MenuItem selection, Modifiers mods)
1039 projectView.ProjectInstall(projectView.active ? selection : null, mods);
1043 MenuItem projectCompileItem;
1044 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1045 MenuItem debugStartResumeItem
1047 debugMenu, $"Start", s, f5, disabled = true;
1048 bitmap = { ":actions/debug.png" };
1049 NotifySelect = MenuDebugStart;
1051 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1055 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1056 if(!projectView.DebugStart())
1057 debugStartResumeItem.disabled = false; // same exception
1061 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1064 projectView.DebugResume();
1067 MenuItem debugRestartItem
1069 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1070 bitmap = { ":actions/restart.png" };
1071 bool NotifySelect(MenuItem selection, Modifiers mods)
1074 projectView.DebugRestart();
1078 MenuItem debugBreakItem
1080 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1081 bitmap = { ":actions/pause.png" };
1082 bool NotifySelect(MenuItem selection, Modifiers mods)
1084 if(projectView && projectView.buildInProgress != none)
1087 projectView.DebugBreak();
1091 MenuItem debugStopItem
1093 debugMenu, $"Stop", p, shiftF5, disabled = true;
1094 bitmap = { ":actions/stopDebug.png" };
1095 bool NotifySelect(MenuItem selection, Modifiers mods)
1098 projectView.DebugStop();
1102 MenuDivider { debugMenu };
1106 // nonClient = true,
1113 anchor = { right = 0, bottom = 0 },
1115 isActiveClient = false,
1117 clickThrough = true,
1118 size = { 500, 500 };
1120 bool OnLoadGraphics()
1122 ModelView::OnLoadGraphics();
1123 camera.position.z /= 1.3;
1124 camera.orientation = Euler { yaw = 280, pitch = 20 };
1130 bool OnRightButtonDown(int x, int y, Modifiers mods)
1132 if(!displaySystem.flags.flipping) return true;
1133 MenuWindowMove(null, 0);
1137 bool OnRightButtonUp(int x, int y, Modifiers mods)
1139 position = position;
1144 MenuItem debugRubberDuck
1146 debugMenu, $"Rubber Duck", checkable = true, disabled = true;
1147 bool NotifySelect(MenuItem selection, Modifiers mods)
1149 if(selection.checked)
1157 MenuDivider { debugMenu };
1158 MenuItem debugUseValgrindItem
1160 debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
1161 bool NotifySelect(MenuItem selection, Modifiers mods)
1165 ide.workspace.useValgrind = selection.checked;
1166 ide.workspace.Save();
1168 ide.AdjustValgrindMenus();
1172 Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
1173 MenuItem debugValgrindNoLeakCheckItem { debugValgrindLeakCheckItem, $"No" , f, id = ValgrindLeakCheck::no , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1174 MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; };
1175 MenuItem debugValgrindYesLeakCheckItem { debugValgrindLeakCheckItem, $"Yes" , f, id = ValgrindLeakCheck::yes , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1176 MenuItem debugValgrindFullLeakCheckItem { debugValgrindLeakCheckItem, $"Full" , f, id = ValgrindLeakCheck::full , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1177 bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
1181 if(selection.checked)
1183 ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
1185 debugValgrindNoLeakCheckItem.checked = debugValgrindNoLeakCheckItem.id == vgLeakCheck;
1186 debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
1187 debugValgrindYesLeakCheckItem.checked = debugValgrindYesLeakCheckItem.id == vgLeakCheck;
1188 debugValgrindFullLeakCheckItem.checked = debugValgrindFullLeakCheckItem.id == vgLeakCheck;
1190 ide.workspace.vgLeakCheck = vgLeakCheck;
1191 ide.workspace.Save();
1194 selection.checked = true;
1198 Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
1199 MenuItem debugValgrindRSDefaultItem { debugValgrindRedzoneSizeItem, $"Default", f, id = -1, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; };
1200 MenuItem debugValgrindRS0Item { debugValgrindRedzoneSizeItem, "0" , f, id = 0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1201 MenuItem debugValgrindRS16Item { debugValgrindRedzoneSizeItem, "16" , f, id = 16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1202 MenuItem debugValgrindRS32Item { debugValgrindRedzoneSizeItem, "32" , f, id = 32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1203 MenuItem debugValgrindRS64Item { debugValgrindRedzoneSizeItem, "64" , f, id = 64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1204 MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, "128" , f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1205 MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, "256" , f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1206 MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, "512" , f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1207 bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
1211 if(selection.checked)
1213 int vgRedzoneSize = (int)selection.id;
1215 debugValgrindRSDefaultItem.checked = debugValgrindRSDefaultItem.id == vgRedzoneSize;
1216 debugValgrindRS0Item.checked = debugValgrindRS0Item.id == vgRedzoneSize;
1217 debugValgrindRS16Item.checked = debugValgrindRS16Item.id == vgRedzoneSize;
1218 debugValgrindRS32Item.checked = debugValgrindRS32Item.id == vgRedzoneSize;
1219 debugValgrindRS64Item.checked = debugValgrindRS64Item.id == vgRedzoneSize;
1220 debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
1221 debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
1222 debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
1224 ide.workspace.vgRedzoneSize = vgRedzoneSize;
1225 ide.workspace.Save();
1228 selection.checked = true;
1232 MenuItem debugValgrindTrackOriginsItem
1234 debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
1235 bool NotifySelect(MenuItem selection, Modifiers mods)
1239 ide.workspace.vgTrackOrigins = selection.checked;
1240 ide.workspace.Save();
1246 MenuDivider { debugMenu };
1247 MenuItem debugStepIntoItem
1249 debugMenu, $"Step Into", i, f11, disabled = true;
1250 bitmap = { ":actions/stepInto.png" };
1251 bool NotifySelect(MenuItem selection, Modifiers mods)
1253 if(projectView) projectView.DebugStepInto();
1257 MenuItem debugStepOverItem
1259 debugMenu, $"Step Over", v, f10, disabled = true;
1260 bitmap = { ":actions/stepOver.png" };
1261 bool NotifySelect(MenuItem selection, Modifiers mods)
1263 if(projectView) projectView.DebugStepOver(false);
1267 MenuItem debugSkipStepOverItem
1269 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1270 bitmap = { ":actions/stepOverSkipBreak.png" };
1271 bool NotifySelect(MenuItem selection, Modifiers mods)
1273 if(projectView) projectView.DebugStepOver(true);
1277 MenuItem debugStepOutItem
1279 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1280 bitmap = { ":actions/stepOut.png" };
1281 bool NotifySelect(MenuItem selection, Modifiers mods)
1283 if(projectView) projectView.DebugStepOut(false);
1287 MenuItem debugSkipStepOutItem
1289 debugMenu, $"Step Out Skipping Breakpoints", n, Key { f11, ctrl = true, shift = true }, disabled = true;
1290 bitmap = { ":actions/skipBreaks.png" };
1291 bool NotifySelect(MenuItem selection, Modifiers mods)
1293 if(projectView) projectView.DebugStepOut(true);
1298 MenuItem debugStepUntilItem
1300 debugMenu, $"Step Over Until Next Line", x, disabled = true;
1301 bool NotifySelect(MenuItem selection, Modifiers mods)
1303 if(projectView) projectView.DebugStepUntil(false);
1307 MenuItem debugSkipStepUntilItem
1309 debugMenu, $"Step Over Until Next Line Skipping Breakpoints", e, Key { f10, shift = true, alt = true }, disabled = true;
1310 bool NotifySelect(MenuItem selection, Modifiers mods)
1312 if(projectView) projectView.DebugStepUntil(true);
1317 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1318 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1319 MenuPlacement debugRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level", l };
1320 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", g };
1322 MenuPlacement debugBpRunToCursorItem { debugMenu, $"BP Run To Cursor" };
1323 MenuPlacement debugBpSkipRunToCursorItem { debugMenu, $"BP Run To Cursor Skipping Breakpoints" };
1324 MenuPlacement debugBpRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level" };
1325 MenuPlacement debugBpSkipRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level Skipping Breakpoints" };
1327 //MenuDivider { debugMenu };
1328 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1329 MenuPlacement imageMenu { menu, $"Image", i };
1330 Menu viewMenu { menu, $"View", v };
1331 MenuItem viewProjectItem
1333 viewMenu, $"Project View", j, alt0, disabled = true;
1334 bool NotifySelect(MenuItem selection, Modifiers mods)
1338 projectView.visible = true;
1339 projectView.Activate();
1344 MenuPlacement { viewMenu, $"View Designer" };
1345 MenuPlacement { viewMenu, $"View Code" };
1346 MenuPlacement { viewMenu, $"View Properties" };
1347 MenuPlacement { viewMenu, $"View Methods" };
1348 MenuItem viewDesignerItem
1350 viewMenu, $"View Designer", d, f8;
1351 bool NotifySelect(MenuItem selection, Modifiers mods)
1353 Window client = activeClient;
1354 Class dataType = client._class;
1355 if(!strcmp(dataType.name, "Designer"))
1357 client.visible = true;
1361 ((CodeEditor)client).ViewDesigner();
1365 MenuItem viewCodeItem
1367 viewMenu, $"View Code", c, f8;
1368 bool NotifySelect(MenuItem selection, Modifiers mods)
1370 Window client = activeClient;
1371 Class dataType = client._class;
1372 if(!strcmp(dataType.name, "Designer"))
1373 client = ((Designer)client).codeEditor;
1376 // Do this after so the caret isn't moved yet...
1377 client.visible = true;
1381 MenuItem viewPropertiesItem
1383 viewMenu, $"View Properties", p, f4;
1384 bool NotifySelect(MenuItem selection, Modifiers mods)
1386 sheet.visible = true;
1387 sheet.sheetSelected = properties;
1392 MenuItem viewMethodsItem
1394 viewMenu, $"View Methods", m, f4;
1395 bool NotifySelect(MenuItem selection, Modifiers mods)
1397 sheet.visible = true;
1398 sheet.sheetSelected = methods;
1403 MenuItem viewToolBoxItem
1405 viewMenu, $"View Toolbox", x, f12;
1406 bool NotifySelect(MenuItem selection, Modifiers mods)
1408 toolBox.visible = true;
1413 MenuItem viewOutputItem
1415 viewMenu, $"Output", o, alt2;
1416 bool NotifySelect(MenuItem selection, Modifiers mods)
1422 MenuItem viewWatchesItem
1424 viewMenu, $"Watches", w, alt3;
1425 bool NotifySelect(MenuItem selection, Modifiers mods)
1431 MenuItem viewThreadsItem
1433 viewMenu, $"Threads", t, alt4;
1434 bool NotifySelect(MenuItem selection, Modifiers mods)
1440 MenuItem viewBreakpointsItem
1442 viewMenu, $"Breakpoints", b, alt5;
1443 bool NotifySelect(MenuItem selection, Modifiers mods)
1445 breakpointsView.Show();
1449 MenuItem viewCallStackItem
1451 viewMenu, $"Call Stack", s, alt7;
1452 bool NotifySelect(MenuItem selection, Modifiers mods)
1454 callStackView.Show();
1458 MenuItem viewAllDebugViews
1460 viewMenu, $"All Debug Views", a, alt9;
1461 bool NotifySelect(MenuItem selection, Modifiers mods)
1466 callStackView.Show();
1467 breakpointsView.Show();
1471 #ifdef GDB_DEBUG_GUI
1472 MenuDivider { viewMenu };
1473 MenuItem viewGDBItem
1475 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1476 bool NotifySelect(MenuItem selection, Modifiers mods)
1483 MenuDivider { viewMenu };
1484 MenuItem viewColorPicker
1486 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1487 bool NotifySelect(MenuItem selection, Modifiers mods)
1489 ColorPicker colorPicker { master = this };
1490 colorPicker.Modal();
1494 MenuDivider { viewMenu };
1498 viewMenu, "Full Screen", f, checkable = true;
1500 bool NotifySelect(MenuItem selection, Modifiers mods)
1502 app.fullScreen ^= true;
1504 anchor = { 0, 0, 0, 0 };
1509 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1511 MenuDivider { viewMenu };
1513 Menu languageMenu { viewMenu, "Language", l };
1515 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1516 Menu windowMenu { menu, $"Window", w };
1517 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1518 MenuDivider { windowMenu };
1519 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1520 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1521 MenuDivider { windowMenu };
1522 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1523 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1524 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1525 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1526 MenuDivider { windowMenu };
1527 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1528 Menu helpMenu { menu, $"Help", h };
1531 helpMenu, $"API Reference", r, f1;
1532 bool NotifySelect(MenuItem selection, Modifiers mods)
1536 char * p = new char[MAX_LOCATION];
1538 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1539 PathCat(p, "documentor");
1540 #if defined(__WIN32__)
1541 ChangeExtension(p, "exe", p);
1543 if(!FileExists(p).isFile)
1544 strcpy(p, "documentor");
1546 documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
1551 Process_ShowWindows(documentor.GetProcessID());
1552 // documentor.Puts("Activate\n");
1557 MenuDivider { helpMenu };
1560 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1561 bool NotifySelect(MenuItem selection, Modifiers mods)
1563 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1567 MenuDivider { helpMenu };
1570 helpMenu, $"Documentation Folder", d;
1571 bool NotifySelect(MenuItem selection, Modifiers mods)
1573 FindAndShellOpenInstalledFolder("doc");
1579 helpMenu, $"Samples Folder", s;
1580 bool NotifySelect(MenuItem selection, Modifiers mods)
1582 FindAndShellOpenInstalledFolder("samples");
1588 helpMenu, $"Extras Folder", x;
1589 bool NotifySelect(MenuItem selection, Modifiers mods)
1591 FindAndShellOpenInstalledFolder("extras");
1595 MenuDivider { helpMenu };
1598 helpMenu, $"Community Forums", f;
1599 bool NotifySelect(MenuItem selection, Modifiers mods)
1601 ShellOpen("http://ecere.com/forums");
1605 MenuDivider { helpMenu };
1608 helpMenu, $"About...", a;
1609 bool NotifySelect(MenuItem selection, Modifiers mods)
1611 AboutIDE { master = this }.Modal();
1616 property ToolBox toolBox
1618 get { return toolBox; }
1621 property Sheet sheet
1623 get { return sheet; }
1626 property Project project
1628 get { return projectView ? projectView.project : null; }
1631 property Workspace workspace
1633 get { return projectView ? projectView.workspace : null; }
1636 FindInFilesDialog findInFilesDialog
1639 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1646 #ifdef GDB_DEBUG_GUI
1649 master = this, parent = this;
1650 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1652 void OnCommand(const char * string)
1655 ide.debugger.SendGDBCommand(string);
1660 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1662 //app.driver = app.drivers[selection.id];
1663 #if defined(__unix__) || defined(__APPLE__)
1664 app.driver = selection.id ? "OpenGL" : "X";
1666 app.driver = selection.id ? "OpenGL" : "GDI";
1668 delete ideSettings.displayDriver;
1669 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1671 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1673 settingsContainer.Save();
1674 //SetDriverAndSkin();
1678 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1680 app.skin = app.skins[selection.id];
1685 void SetDriverAndSkin()
1688 for(c = 0; c < app.numSkins; c++)
1689 if(!strcmp(app.skins[c], app.skin))
1691 skinItems[c].checked = true;
1694 for(c = 0; c < app.numDrivers; c++)
1695 if(!strcmp(app.drivers[c], app.driver))
1697 driverItems[c].checked = true;
1702 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1704 Project project = workspace.projects.firstIterator.data;
1705 projectView = ProjectView
1708 fileName = fileName;
1710 void NotifyDestroyed(Window window, DialogResult result)
1713 text = titleECEREIDE;
1718 projectView.Create();
1719 RepositionWindows(false);
1721 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1722 projectView.workspace = workspace;
1723 projectView.project = project;
1724 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1727 updateRecentMenus();
1729 ide.breakpointsView.LoadFromWorkspace();
1730 ide.watchesView.LoadFromWorkspace();
1732 findInFilesDialog.projectNodeField.userData = projectView;
1735 char fileName[MAX_LOCATION];
1736 strcpy(fileName, project.topNode.path);
1737 PathCat(fileName, project.topNode.name);
1744 projectView.visible = false;
1745 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1747 if(findInFilesDialog)
1749 char workingDir[MAX_LOCATION];
1750 GetWorkingDir(workingDir, MAX_LOCATION);
1751 findInFilesDialog.SearchStop();
1752 findInFilesDialog.currentDirectory = workingDir;
1754 sheet.visible = false;
1755 toolBox.visible = false;
1756 outputView.visible = false;
1757 ideMainFrame.text = titleECEREIDE;
1759 ide.updateRecentMenus();
1765 void RepositionWindows(bool expand)
1770 bool callStackVisible = expand ? false : callStackView.visible;
1771 bool threadsVisible = expand ? false : threadsView.visible;
1772 bool watchesVisible = expand ? false : watchesView.visible;
1773 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1774 bool toolBoxVisible = toolBox.visible;
1775 bool outputVisible = expand ? false : outputView.visible;
1776 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1777 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1779 for(child = firstChild; child; child = child.next)
1781 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1782 child._class == class(Sheet) || child._class == class(ProjectView))
1784 Anchor anchor = child.anchor;
1785 anchor.top = topDistance;
1786 anchor.bottom = bottomDistance;
1787 if(child._class == class(CodeEditor) || child._class == class(Designer))
1789 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1790 anchor.right = toolBoxVisible ? 150 : 0;
1793 child.anchor = anchor;
1797 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1798 child._class == class(BreakpointsView))
1799 child.visible = false;
1802 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1804 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1808 bool ShowCodeEditor()
1811 activeClient.Activate();
1812 else if(projectView)
1814 projectView.visible = true;
1815 projectView.Activate();
1817 else if(sheet.visible)
1820 outputView.visible = false;
1824 void DocumentSaved(Window document, const char * fileName)
1826 ideSettings.recentFiles.addRecent(CopyString(fileName));
1827 ide.updateRecentFilesMenu();
1828 ide.AdjustFileMenus();
1829 settingsContainer.Save();
1832 bool Window::OnFileModified(FileChange fileChange, const char * param)
1835 sprintf(temp, $"The document %s was modified by another application.\n"
1836 "Would you like to reload it and lose your changes?", this.fileName);
1837 if(MessageBox { creationActivation = flash, type = yesNo, master = this/*.parent*/,
1838 text = $"Document has been modified", contents = temp }.Modal() == yes)
1840 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1841 char * fileName = CopyString(this.fileName);
1842 WindowState state = this.state;
1843 Anchor anchor = this.anchor;
1844 Size size = this.size;
1846 this.modifiedDocument = false;
1848 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1851 this.anchor = anchor;
1853 this.SetState(state, true, 0);
1861 void UpdateMakefiles()
1865 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
1866 for(prj : workspace.projects)
1867 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1872 void UpdateCompilerConfigs(bool mute)
1874 UpdateToolBarActiveCompilers();
1877 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1878 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
1881 projectView.ShowOutputBuildLog(true);
1882 projectView.DisplayCompiler(compiler, false);
1884 for(prj : workspace.projects)
1885 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1890 void UpdateToolBarActiveCompilers()
1892 toolBar.activeCompiler.Clear();
1893 for(compiler : ideSettings.compilerConfigs)
1895 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1896 if(workspace && workspace.activeCompiler && !strcmp(compiler.name, workspace.activeCompiler))
1897 toolBar.activeCompiler.currentRow = row;
1899 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1900 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1901 toolBar.activeBitDepth.SelectRow(toolBar.activeBitDepth.FindRow(workspace ? workspace.bitDepth : 0));
1904 void UpdateToolBarActiveConfigs(bool selectionOnly)
1906 bool commonSelected = false;
1907 DataRow row = toolBar.activeConfig.currentRow;
1909 row = toolBar.activeConfig.FindRow(1);
1912 toolBar.activeConfig.Clear();
1913 row = toolBar.activeConfig.AddString($"(Mixed)");
1918 char * configName = null;
1921 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1922 for(prj : workspace.projects)
1924 for(cfg : prj.configurations)
1927 configs[cfg.name] = 1;
1932 toolBar.activeConfig.AddString(&name);
1936 if(projectView && projectView.project)
1938 for(prj : workspace.projects)
1940 if(prj.config && prj.config.name)
1942 configName = prj.config.name;
1948 commonSelected = true;
1949 for(prj : workspace.projects)
1951 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1953 commonSelected = false;
1961 commonSelected = false;
1962 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1964 if(!strcmp(row.string, configName))
1966 toolBar.activeConfig.currentRow = row;
1967 commonSelected = true;
1974 toolBar.activeConfig.Sort(null, 0);
1976 toolBar.activeConfig.currentRow = row;
1981 bool unavailable = !project;
1983 projectAddItem.disabled = unavailable;
1984 toolBar.buttonAddProject.disabled = unavailable;
1986 projectSettingsItem.disabled = unavailable;
1988 projectBrowseFolderItem.disabled = unavailable;
1990 viewProjectItem.disabled = unavailable;
1992 toolBar.activeConfig.disabled = unavailable;
1993 toolBar.activeCompiler.disabled = unavailable;
1994 toolBar.activeBitDepth.disabled = unavailable;
1997 debugUseValgrindItem.disabled = unavailable;
1998 AdjustValgrindMenus();
2007 void AdjustValgrindMenus()
2009 bool unavailable = !project || !debugUseValgrindItem.checked;
2010 debugValgrindNoLeakCheckItem.disabled = unavailable;
2011 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2012 debugValgrindYesLeakCheckItem.disabled = unavailable;
2013 debugValgrindFullLeakCheckItem.disabled = unavailable;
2015 debugValgrindTrackOriginsItem.disabled = unavailable;
2017 debugValgrindRSDefaultItem.disabled = unavailable;
2018 debugValgrindRS0Item.disabled = unavailable;
2019 debugValgrindRS16Item.disabled = unavailable;
2020 debugValgrindRS32Item.disabled = unavailable;
2021 debugValgrindRS64Item.disabled = unavailable;
2022 debugValgrindRS128Item.disabled = unavailable;
2023 debugValgrindRS256Item.disabled = unavailable;
2024 debugValgrindRS512Item.disabled = unavailable;
2028 property bool hasOpenedCodeEditors
2033 for(w = firstChild; w; w = w.next)
2034 if(w._class == class(CodeEditor) &&
2035 w.isDocument && !w.closing && w.visible && w.created &&
2036 w.fileName && w.fileName[0])
2042 void AdjustFileMenus()
2044 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2046 projectQuickItem.disabled = unavailable;
2049 void AdjustBuildMenus()
2051 bool unavailable = project && projectView.buildInProgress;
2052 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2053 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2055 projectNewItem.disabled = unavailable;
2056 toolBar.buttonNewProject.disabled = unavailable;
2057 projectOpenItem.disabled = unavailable;
2058 toolBar.buttonOpenProject.disabled = unavailable;
2060 unavailable = !project || projectView.buildInProgress;
2062 projectCloseItem.disabled = unavailable;
2063 // toolBar.buttonCloseProject.disabled = unavailable;
2065 projectRunItem.disabled = naForRun;
2066 toolBar.buttonRun.disabled = naForRun;
2068 projectBuildItem.disabled = false;
2069 projectBuildItem.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2070 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2072 projectLinkItem.disabled = unavailable;
2073 toolBar.buttonReLink.disabled = unavailable;
2074 projectRebuildItem.disabled = unavailable;
2075 toolBar.buttonRebuild.disabled = unavailable;
2076 projectCleanItem.disabled = unavailable;
2077 toolBar.buttonClean.disabled = unavailable;
2078 projectCleanTargetItem.disabled = unavailable;
2079 projectRealCleanItem.disabled = unavailable;
2080 // toolBar.buttonRealClean.disabled = unavailable;
2081 projectRegenerateItem.disabled = unavailable;
2082 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2083 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2084 projectInstallItem.disabled = unavailable;
2085 toolBar.buttonInstall.disabled = unavailable;
2087 projectCompileItem.disabled = unavailable;
2089 AdjustPopupBuildMenus();
2092 void AdjustPopupBuildMenus()
2094 bool unavailable = !project || projectView.buildInProgress;
2096 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2099 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2100 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, mode);
2103 menu.disabled = false;
2104 menu.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2105 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2108 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, mode); if(menu) menu.disabled = unavailable;
2109 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, mode); if(menu) menu.disabled = unavailable;
2110 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, mode); if(menu) menu.disabled = unavailable;
2111 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, mode); if(menu) menu.disabled = unavailable;
2112 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, mode); if(menu) menu.disabled = unavailable;
2113 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, mode); if(menu) menu.disabled = unavailable;
2114 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, mode); if(menu) menu.disabled = unavailable;
2115 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, mode); if(menu) menu.disabled = unavailable;
2116 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, mode); if(menu) menu.disabled = unavailable;
2117 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, mode); if(menu) menu.disabled = unavailable;
2118 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, mode); if(menu) menu.disabled = unavailable;
2119 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, mode); if(menu) menu.disabled = unavailable;
2120 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, mode); if(menu) menu.disabled = unavailable;
2121 projectView.popupMenu.Update(null);
2125 property bool areDebugMenusUnavailable { get {
2127 project.GetTargetType(project.config) != executable ||
2128 projectView.buildInProgress == buildingMainProject;
2131 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2132 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2133 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2135 void AdjustDebugMenus()
2137 bool unavailable = areDebugMenusUnavailable;
2138 bool running = isDebuggerRunning;
2139 bool stopped = isDebuggerStopped;
2140 bool active = debugger.isActive;
2142 bool isNotRunning = unavailable || !running;
2143 bool isNotNotRunning = unavailable || running;
2144 bool isNotStopped = unavailable || !stopped;
2145 bool isNotActive = unavailable || !active;
2147 debugStartResumeItem.disabled = isNotNotRunning;
2148 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2149 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2152 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2153 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2156 debugBreakItem.disabled = isNotRunning;
2157 debugStopItem.disabled = isNotActive;
2158 debugRestartItem.disabled = isNotActive;
2161 toolBar.buttonDebugPause.disabled = isNotRunning;
2162 toolBar.buttonDebugStop.disabled = isNotActive;
2163 toolBar.buttonDebugRestart.disabled = isNotActive;
2166 debugStepIntoItem.disabled = isNotNotRunning;
2167 debugStepOverItem.disabled = isNotNotRunning;
2168 debugSkipStepOverItem.disabled = isNotNotRunning;
2169 debugStepOutItem.disabled = isNotStopped;
2170 debugSkipStepOutItem.disabled = isNotStopped;
2172 debugStepUntilItem.disabled = isNotStopped;
2173 debugSkipStepUntilItem.disabled = isNotStopped;
2177 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2178 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2179 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2180 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2181 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2183 if((Designer)GetActiveDesigner())
2185 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2187 codeEditor.AdjustDebugMenus();
2191 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2193 char tempString[MAX_LOCATION];
2194 strcpy(tempString, directory);
2195 if(saveSettings && !projectView)
2197 ideSettings.ideFileDialogLocation = directory;
2198 settingsContainer.Save();
2201 ideFileDialog.currentDirectory = tempString;
2202 codeEditorFileDialog.currentDirectory = tempString;
2203 codeEditorFormFileDialog.currentDirectory = tempString;
2206 void ChangeProjectFileDialogDirectory(char * directory)
2208 ideSettings.ideProjectFileDialogLocation = directory;
2209 settingsContainer.Save();
2212 Window FindWindow(const char * filePath)
2214 Window document = null;
2216 // TOCHECK: Do we need to change slashes here?
2217 for(document = firstChild; document; document = document.next)
2219 const char * fileName = document.fileName;
2220 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2222 document.visible = true;
2223 document.Activate();
2230 bool DontTerminateDebugSession(const char * title)
2232 if(debugger.isActive)
2234 if(MessageBox { type = yesNo, master = ide,
2235 contents = $"Do you want to terminate the debugging session in progress?",
2236 text = title }.Modal() == no)
2239 MessageBox msg { type = yesNo, master = ide,
2240 contents = "Do you want to terminate the debugging session in progress?",
2242 if(msg.Modal() == no)
2254 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2256 char extension[MAX_EXTENSION] = "";
2257 Window document = null;
2258 bool isProject = false;
2259 bool needFileModified = true;
2260 char winFilePath[MAX_LOCATION];
2261 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2262 Window currentDoc = activeClient;
2263 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2266 GetExtension(filePath, extension);
2270 strcpy(extension, type);
2272 if(strcmp(extension, ProjectExtension))
2274 for(document = firstChild; document; document = document.next)
2276 const char * fileName = document.fileName;
2277 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2279 document.visible = true;
2281 document.Activate();
2287 if(createIfFails == whatever)
2289 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2291 needFileModified = false;
2292 if(openMethod == normal)
2294 if(DontTerminateDebugSession($"Open Project"))
2303 Workspace workspace = null;
2305 if(FileExists(filePath))
2307 if(!strcmp(extension, ProjectExtension))
2309 char workspaceFile[MAX_LOCATION];
2310 strcpy(workspaceFile, filePath);
2311 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2312 workspace = LoadWorkspace(workspaceFile, filePath);
2314 else if(!strcmp(extension, WorkspaceExtension))
2315 workspace = LoadWorkspace(filePath, null);
2322 CreateProjectView(workspace, filePath);
2323 document = projectView;
2325 toolBox.visible = true;
2326 sheet.visible = true;
2327 projectView.MakeActive();
2329 workspace.ParseLoadedBreakpoints();
2330 workspace.DropInvalidBreakpoints(null);
2333 ide.projectView.ShowOutputBuildLog(true);
2335 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
2336 ide.projectView.DisplayCompiler(compiler, false);
2339 UpdateCompilerConfigs(false);
2342 char newWorkingDir[MAX_LOCATION];
2343 StripLastDirectory(filePath, newWorkingDir);
2344 ChangeFileDialogsDirectory(newWorkingDir, false);
2347 document.fileName = filePath;
2349 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2351 // this crashes on starting ide with epj file, solution please?
2352 // app.UpdateDisplay();
2354 workspace.OpenPreviouslyOpenedFiles(noParsing);
2355 workspace.holdTracking = true;
2356 ide.RepositionWindows(false);
2357 workspace.holdTracking = false;
2359 workspace.timer.Start();
2361 #if !defined(__WIN32__)
2362 // Valgrind Debug menu updates
2363 debugUseValgrindItem.checked = workspace.useValgrind;
2365 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2366 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2367 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2368 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2370 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2371 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2372 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2373 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2374 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2375 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2376 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2377 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2379 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2382 findInFilesDialog.mode = FindInFilesMode::project;
2383 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2386 char location[MAX_LOCATION];
2387 StripLastDirectory(ide.project.topNode.path, location);
2388 ChangeProjectFileDialogDirectory(location);
2395 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2397 ideProjectFileDialog.text = openProjectFileDialogTitle;
2398 if(ideProjectFileDialog.Modal() == cancel)
2400 filePath = ideProjectFileDialog.filePath;
2401 GetExtension(filePath, extension);
2412 else if(openMethod == add)
2417 char slashFilePath[MAX_LOCATION];
2418 GetSlashPathBuffer(slashFilePath, filePath);
2419 for(p : workspace.projects)
2421 if(!fstrcmp(p.filePath, slashFilePath))
2429 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2430 contents = $"This project is already present in workspace." }.Modal();
2434 prj = LoadProject(filePath, null);
2437 const char * activeConfigName = null;
2438 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
2439 prj.StartMonitoring();
2440 workspace.AddProject(prj, null);
2441 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2442 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2443 activeConfigName = toolBar.activeConfig.currentRow.string;
2444 if(activeConfigName)
2446 for(cfg : prj.configurations)
2448 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2456 projectView.AddNode(prj.topNode, null);
2457 workspace.modified = true;
2459 findInFilesDialog.AddProjectItem(prj);
2460 projectView.ShowOutputBuildLog(true);
2461 projectView.DisplayCompiler(compiler, false);
2462 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2466 char location[MAX_LOCATION];
2467 StripLastDirectory(prj.topNode.path, location);
2468 ChangeProjectFileDialogDirectory(location);
2471 // projectView is associated with the main project and not with the one just added but
2472 return projectView; // just to let the caller know something was opened
2480 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2481 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2482 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2484 if(FileExists(filePath))
2485 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2486 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2487 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2490 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2493 else if(!strcmp(extension, "3ds"))
2495 if(FileExists(filePath))
2496 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2497 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2498 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2502 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2505 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2506 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2507 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2508 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2509 !strcmp(extension, "js"))
2511 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2512 editor.updatingCode = true;
2513 if(editor.LoadFile(filePath))
2516 editor.visible = true;
2520 needFileModified = false;
2524 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2525 if(editor.LoadFile(filePath))
2528 editor.visible = true;
2532 needFileModified = false;
2535 if(document && (document._class == class(PictureEdit) ||
2536 document._class == class(ModelView)))
2541 document.fileName = filePath;
2542 if(workspace && !workspace.holdTracking)
2543 workspace.UpdateOpenedFileInfo(filePath, opened, true);
2547 if(!document && createIfFails != no)
2549 if(createIfFails != yes && !needFileModified &&
2550 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2551 createIfFails = yes;
2552 if(createIfFails == yes || createIfFails == whatever)
2554 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2556 document.fileName = filePath;
2562 if(projectView && document._class == class(CodeEditor) && workspace)
2563 workspace.RestorePreviouslyOpenedFileState((CodeEditor)document);
2565 if(needFileModified)
2566 document.OnFileModified = OnFileModified;
2567 document.NotifySaved = DocumentSaved;
2568 if(maximizeDoc && document.hasMaximize)
2569 document.state = maximized;
2572 ideSettings.recentProjects.addRecent(CopyString(document.fileName));
2574 ideSettings.recentFiles.addRecent(CopyString(document.fileName));
2575 ide.AdjustFileMenus();
2576 ide.updateRecentFilesMenu();
2577 settingsContainer.Save();
2585 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2586 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2588 if(!parentClosing && ide.workspace)
2589 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2592 bool ModelView::ModelViewOnClose(bool parentClosing)
2594 if(!parentClosing && ide.workspace)
2595 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2598 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2600 if(!parentClosing && ide.workspace)
2601 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2606 void OnUnloadGraphics(Window window)
2608 display.ClearMaterials();
2609 display.ClearTextures();
2610 display.ClearMeshes();
2614 void UpdateStateLight(StatusField fld, bool on)
2616 fld.color = on ? lime : Color { 128,128,128 };
2617 fld.backColor = on ? dimGray : 0;
2621 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2623 UpdateStateLight(caps, app.GetKeyState(capsState));
2624 UpdateStateLight(num, app.GetKeyState(numState));
2628 bool OnKeyDown(Key key, unichar ch)
2632 case b: projectView.Update(null); break;
2633 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2634 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2639 bool OnKeyUp(Key key, unichar ch)
2643 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2644 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2649 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2652 projectView.GoToError(line, noParsing, objectFileExt);
2655 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2657 FileAttribs result { };
2658 FileAttribs fileAttribs;
2662 strcpy(selectedPath, prj.topNode.path);
2663 else if(dir && dir[0])
2664 strcpy(selectedPath, dir);
2666 selectedPath[0] = '\0';
2667 PathCat(selectedPath, filePath);
2669 if((fileAttribs = FileExists(selectedPath)).isFile)
2670 result = fileAttribs;
2674 for(p : workspace.projects)
2676 strcpy(selectedPath, p.topNode.path);
2677 PathCat(selectedPath, filePath);
2678 if((fileAttribs = FileExists(selectedPath)).isFile)
2681 result = fileAttribs;
2688 ProjectNode n = null;
2689 for(p : workspace.projects)
2691 if((n = p.topNode.Find(filePath, false)))
2693 n.GetFullFilePath(selectedPath, true);
2694 if((fileAttribs = FileExists(selectedPath)).isFile)
2697 result = fileAttribs;
2702 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2703 (fileAttribs = FileExists(selectedPath)).isFile)
2706 result = fileAttribs;
2714 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2717 const char *path = text;
2718 char *colon = strchr(text, ':');
2719 char filePath[MAX_LOCATION] = "";
2720 char completePath[MAX_LOCATION];
2721 int line = 0, col = 0;
2722 int len = strlen(text);
2724 FileAttribs fileAttribs;
2726 // support for valgrind output
2727 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2738 /*for(s=colon; *s; s++)
2747 //line = atoi(colon+1);
2749 // support for "Found n match(es) in "file/path";
2750 else if(path[len-1] == '\"' && strstr(path, $"Found %d match%s in \"%s\"%s\n\n"."Found") && strstr(path, $"match") && strstr(path, $"in") && (s = strstr(path, "\"")) && s != path+len-1)
2756 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2758 path = (colon - 1 > path) ? colon - 1 : path;
2759 colon = strstr(colon + 1, ":");
2761 if(*path == '*' && (s = strchr(path+1, '*')))
2763 while(isspace(*path)) path++;
2767 char * close = strchr(path, ')');
2771 strncpy(name, path+1, close - path - 1);
2772 name[close - path - 1] = '\0';
2773 for(p : ide.workspace.projects)
2775 if(!strcmp(p.name, name))
2785 prj = project ? project : (dir ? null : ide.project);
2788 strncpy(filePath, path, colon - path);
2789 filePath[colon - path] = '\0';
2790 line = atoi(colon + 1);
2791 colon = strstr(colon + 1, ":");
2793 col = atoi(colon + 1);
2795 else if(path - 1 >= text && *(path - 1) == '\"')
2797 colon = strchr(path, '\"');
2800 strncpy(filePath, path, colon - path);
2801 filePath[colon - path] = '\0';
2804 else if(path && !colon)
2806 strcpy(filePath, path);
2809 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2810 CodeLocationGoTo(completePath, fileAttribs, line, col);
2813 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2815 if(fileAttribs.isFile)
2817 char ext[MAX_EXTENSION];
2818 GetExtension(path, ext);
2820 if(binaryDocExt.Find(ext))
2822 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2823 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2825 char dirPath[MAX_LOCATION];
2826 StripLastDirectory(path, dirPath);
2831 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2832 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2834 EditBox editBox = codeEditor.editBox;
2835 editBox.GoToLineNum(line - 1);
2836 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2840 else if(fileAttribs.isDirectory)
2844 void OnRedraw(Surface surface)
2846 Bitmap bitmap = back.bitmap;
2848 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2851 void SheetSelected(SheetType sheetSelected)
2853 if(activeChild == sheet)
2855 if(sheetSelected == methods)
2857 viewPropertiesItem.accelerator = f4;
2858 viewPropertiesItem.parent = viewMenu;
2859 viewMethodsItem.parent = null;
2863 viewMethodsItem.accelerator = f4;
2864 viewMethodsItem.parent = viewMenu;
2865 viewPropertiesItem.parent = null;
2870 viewMethodsItem.parent = viewMenu;
2871 viewPropertiesItem.parent = viewMenu;
2872 if(sheetSelected == methods)
2874 viewMethodsItem.accelerator = f4;
2875 viewPropertiesItem.accelerator = 0;
2879 viewMethodsItem.accelerator = 0;
2880 viewPropertiesItem.accelerator = f4;
2885 void OnActivateClient(Window client, Window previous)
2887 //if(!client || client != previous)
2890 if(!client || client != previous)
2893 dataType = previous._class;
2894 if(previous && !strcmp(dataType.name, "CodeEditor"))
2896 ((CodeEditor)previous).UpdateFormCode();
2898 else if(previous && !strcmp(dataType.name, "Designer"))
2900 ((Designer)previous).codeEditor.UpdateFormCode();
2905 dataType = client._class;
2906 if(client && !strcmp(dataType.name, "CodeEditor"))
2908 CodeEditor codeEditor = (CodeEditor)client;
2909 SetPrivateModule(codeEditor.privateModule);
2910 SetCurrentContext(codeEditor.globalContext);
2911 SetTopContext(codeEditor.globalContext);
2912 SetGlobalContext(codeEditor.globalContext);
2914 SetDefines(&codeEditor.defines);
2915 SetImports(&codeEditor.imports);
2917 SetActiveDesigner(codeEditor.designer);
2919 sheet.codeEditor = codeEditor;
2920 toolBox.codeEditor = codeEditor;
2922 viewDesignerItem.parent = viewMenu;
2923 if(activeChild != codeEditor)
2925 viewCodeItem.parent = viewMenu;
2926 viewDesignerItem.accelerator = 0;
2927 viewCodeItem.accelerator = f8;
2931 viewCodeItem.parent = null;
2932 viewDesignerItem.accelerator = f8;
2935 else if(client && !strcmp(dataType.name, "Designer"))
2937 CodeEditor codeEditor = ((Designer)client).codeEditor;
2940 SetPrivateModule(codeEditor.privateModule);
2941 SetCurrentContext(codeEditor.globalContext);
2942 SetTopContext(codeEditor.globalContext);
2943 SetGlobalContext(codeEditor.globalContext);
2944 SetDefines(&codeEditor.defines);
2945 SetImports(&codeEditor.imports);
2949 SetPrivateModule(null);
2950 SetCurrentContext(null);
2951 SetTopContext(null);
2952 SetGlobalContext(null);
2957 SetActiveDesigner((Designer)client);
2959 sheet.codeEditor = codeEditor;
2960 toolBox.codeEditor = codeEditor;
2962 viewCodeItem.parent = viewMenu;
2963 if(activeChild != client)
2965 viewDesignerItem.parent = viewMenu;
2966 viewDesignerItem.accelerator = f8;
2967 viewCodeItem.accelerator = 0;
2971 viewDesignerItem.parent = null;
2972 viewCodeItem.accelerator = f8;
2977 if(!client && !projectView && sheet.visible)
2980 sheet.visible = false;
2981 toolBox.visible = false;
2984 sheet.codeEditor = null;
2985 toolBox.codeEditor = null;
2986 SetActiveDesigner(null);
2988 viewDesignerItem.parent = null;
2989 viewCodeItem.parent = null;
2992 SheetSelected(sheet.sheetSelected);
2995 projectCompileItem = null;
3000 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3002 CodeEditor codeEditor = (CodeEditor)client;
3003 EditBox editBox = codeEditor.editBox;
3005 statusBar.AddField(pos);
3007 caps = { width = 40, text = $"CAPS" };
3008 statusBar.AddField(caps);
3009 UpdateStateLight(caps, app.GetKeyState(capsState));
3011 ovr = { width = 36, text = $"OVR" };
3012 statusBar.AddField(ovr);
3013 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3015 num = { width = 36, text = $"NUM" };
3016 statusBar.AddField(num);
3017 UpdateStateLight(num, app.GetKeyState(numState));
3019 //statusBar.text = "Ready";
3021 if(projectView && projectView.project)
3023 bool isCObject = false;
3024 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3025 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3029 char nodeName[MAX_FILENAME];
3030 char name[MAX_FILENAME+96];
3032 ChangeExtension(node.name, "c", nodeName);
3033 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3034 projectCompileItem =
3036 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3038 bool NotifySelect(MenuItem selection, Modifiers mods)
3042 bool isCObject = false;
3043 bool isExcluded = false;
3044 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3048 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3051 List<ProjectNode> nodes { };
3053 projectView.Compile(node.project, nodes, normal, isCObject ? cObject : normal);
3061 projectMenu.AddDynamic(projectCompileItem, ide, false);
3067 caps = ovr = num = null;
3072 bool OnClose(bool parentClosing)
3074 //return !projectView.buildInProgress;
3075 if(projectView && projectView.buildInProgress)
3077 if(DontTerminateDebugSession($"Close IDE"))
3079 if(findInFilesDialog)
3080 findInFilesDialog.SearchStop();
3083 workspace.timer.Stop();
3086 ideMainFrame.Destroy(0);
3093 bool passThrough = false;
3094 bool debugWorkDir = false;
3095 char * passDebugWorkDir = null;
3096 bool openAsText = false;
3097 DynamicString passArgs { };
3100 for(c = 1; c<app.argc; c++)
3104 const char * arg = app.argv[c];
3105 char * buf = new char[strlen(arg)*2+1];
3107 passArgs.concat(" ");
3109 passArgs.concat(buf);
3112 else if(debugWorkDir)
3114 passDebugWorkDir = CopyString(app.argv[c]);
3115 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3116 debugWorkDir = false;
3118 else if(!strcmp(app.argv[c], "-t"))
3120 else if(!strcmp(app.argv[c], "-no-parsing"))
3121 ide.noParsing = true;
3122 else if(!strcmp(app.argv[c], "-debug-start"))
3123 ide.debugStart = true;
3124 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3125 debugWorkDir = true;
3126 else if(!strcmp(app.argv[c], "-@"))
3130 char fullPath[MAX_LOCATION];
3131 char parentPath[MAX_LOCATION];
3132 char ext[MAX_EXTENSION];
3134 FileAttribs dirAttribs;
3135 GetWorkingDir(fullPath, MAX_LOCATION);
3136 PathCat(fullPath, app.argv[c]);
3137 StripLastDirectory(fullPath, parentPath);
3138 GetExtension(app.argv[c], ext);
3139 isProject = !openAsText && !strcmpi(ext, "epj");
3141 if(isProject && c > 1 + (ide.debugStart ? 1 : 0)) continue;
3143 // Create directory for projects (only)
3144 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3146 if(isProject && !FileExists(fullPath))
3148 char name[MAX_LOCATION];
3149 NewProjectDialog newProjectDialog;
3153 projectView.visible = false;
3154 if(!projectView.Destroy(0))
3158 newProjectDialog = { master = this };
3160 strcpy(name, app.argv[c]);
3161 StripExtension(name);
3162 GetLastDirectory(name, name);
3163 newProjectDialog.projectName.contents = name;
3164 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3165 newProjectDialog.locationEditBox.path = parentPath;
3166 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3168 incref newProjectDialog;
3169 newProjectDialog.Modal();
3172 ideSettings.recentProjects.addRecent(CopyString(projectView.fileName));
3173 ide.updateRecentMenus();
3174 settingsContainer.Save();
3176 delete newProjectDialog;
3177 // Open only one project
3181 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3183 else if(strstr(fullPath, "http://") == fullPath)
3184 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3187 if(passThrough && projectView && projectView.project && workspace)
3188 workspace.commandLineArgs = passArgs;
3189 if(passDebugWorkDir && projectView && projectView.project && workspace)
3191 workspace.debugDir = passDebugWorkDir;
3192 delete passDebugWorkDir;
3195 UpdateToolBarActiveConfigs(false);
3196 UpdateToolBarActiveCompilers();
3203 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3206 projectView.visible = false;
3207 projectView.Destroy(0);
3210 #ifdef GDB_DEBUG_GUI
3211 gdbDialog.Destroy(0);
3216 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3220 char * oldPaths[128];
3221 String oldList = new char[maxPathLen];
3222 Array<String> newExePaths { };
3223 //Map<String, bool> exePathExists { };
3225 #if defined(__unix__) || defined(__APPLE__)
3226 Array<String> newLibPaths { };
3227 Map<String, bool> libPathExists { };
3232 for(prj : workspace.projects)
3234 DirExpression targetDirExp;
3236 // SKIP FIRST PROJECT...
3237 if(prj == workspace.projects.firstIterator.data) continue;
3239 // NOTE: Right now the additional project config dir will be
3240 // obtained when the debugger is started, so toggling it
3241 // while building will change which library gets used.
3242 // To go with the initial state, e.g. when F5 was pressed,
3243 // we nould need to keep a list of all project's active
3244 // config upon startup.
3245 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3247 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3251 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3252 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3256 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3257 if(cfg.targetType == sharedLibrary && cfg.debug)
3261 if(targetDirExp.dir)
3263 char buffer[MAX_LOCATION];
3264 #if defined(__WIN32__)
3265 Array<String> paths = newExePaths;
3267 Array<String> paths = newLibPaths;
3269 GetSystemPathBuffer(buffer, prj.topNode.path);
3270 PathCat(buffer, targetDirExp.dir);
3273 if(!fstrcmp(p, buffer))
3280 paths.Add(CopyString(buffer));
3282 delete targetDirExp;
3286 for(item : compiler.executableDirs)
3288 DirExpression dirExpr { };
3289 dirExpr.Evaluate(item, null, compiler, null, 0);
3292 for(p : newExePaths)
3294 if(!fstrcmp(p, dirExpr.dir))
3301 newExePaths.Add(CopySystemPath(dirExpr.dir));
3305 GetEnvironment("PATH", oldList, maxPathLen);
3307 printf("Old value of PATH: %s\n", oldList);
3309 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3310 for(c = 0; c < count; c++)
3313 for(p : newExePaths)
3315 if(!fstrcmp(p, oldPaths[c]))
3322 newExePaths.Add(CopySystemPath(oldPaths[c]));
3326 for(path : newExePaths)
3327 len += strlen(path) + 1;
3328 newList = new char[len + 1];
3330 for(path : newExePaths)
3332 strcat(newList, path);
3333 strcat(newList, pathListSep);
3335 newList[len - 1] = '\0';
3336 SetEnvironment("PATH", newList);
3338 printf("New value of PATH: %s\n", newList);
3345 #if defined(__unix__) || defined(__APPLE__)
3347 for(item : compiler.libraryDirs)
3349 if(!libPathExists[item]) // fstrcmp should be used
3351 String s = CopyString(item);
3353 libPathExists[s] = true;
3357 #if defined(__APPLE__)
3358 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3360 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3363 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3365 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3366 for(c = 0; c < count; c++)
3368 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3370 String s = CopyString(oldPaths[c]);
3372 libPathExists[s] = true;
3377 for(path : newLibPaths)
3378 len += strlen(path) + 1;
3379 newList = new char[len + 1];
3381 for(path : newLibPaths)
3383 strcat(newList, path);
3384 strcat(newList, pathListSep);
3386 newList[len - 1] = '\0';
3387 #if defined(__APPLE__)
3388 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3390 SetEnvironment("LD_LIBRARY_PATH", newList);
3393 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3399 delete libPathExists;
3402 if(compiler.distccEnabled && compiler.distccHosts)
3403 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3408 void DestroyTemporaryProjectDir()
3410 if(tmpPrjDir && tmpPrjDir[0])
3412 if(FileExists(tmpPrjDir).isDirectory)
3413 DestroyDir(tmpPrjDir);
3414 property::tmpPrjDir = null;
3420 // Graphics Driver Menu
3423 app.currentSkin.selectionColor = selectionColor;
3424 app.currentSkin.selectionText = selectionText;
3428 driverItems = new MenuItem[app.numDrivers];
3429 for(c = 0; c < app.numDrivers; c++)
3431 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3432 driverItems[c].id = c;
3433 driverItems[c].isRadio = true;
3436 driverItems = new MenuItem[2];
3437 #if defined(__unix__)
3438 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3439 driverItems[0].id = 0;
3440 driverItems[0].isRadio = true;
3442 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3443 driverItems[0].id = 0;
3444 driverItems[0].isRadio = true;
3446 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3447 driverItems[1].id = 1;
3448 driverItems[1].isRadio = true;
3450 /* skinItems = new MenuItem[app.numSkins];
3451 for(c = 0; c < app.numSkins; c++)
3453 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3454 skinItems[c].id = c;
3455 skinItems[c].isRadio = true;
3458 ideFileDialog.master = this;
3459 ideProjectFileDialog.master = this;
3461 //SetDriverAndSkin();
3465 void updateRecentMenus()
3467 updateRecentFilesMenu();
3468 updateRecentProjectsMenu();
3471 void updateRecentFilesMenu()
3474 char * itemPath = new char[MAX_LOCATION];
3475 char * itemName = new char[MAX_LOCATION+4];
3476 Workspace ws = workspace;
3477 RecentPaths recentFiles = ws ? ws.recentFiles : ideSettings.recentFiles;
3478 recentFilesMenu.Clear();
3479 for(recent : recentFiles)
3481 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3482 MakeSystemPath(itemPath);
3483 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3484 recentFilesMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3491 void updateRecentProjectsMenu()
3494 char * itemPath = new char[MAX_LOCATION];
3495 char * itemName = new char[MAX_LOCATION+4];
3496 recentProjectsMenu.Clear();
3497 for(recent : ideSettings.recentProjects)
3499 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3500 MakeSystemPath(itemPath);
3501 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3502 recentProjectsMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3513 delete languageItems;
3517 documentor.Puts("Quit\n");
3524 void DestroyDir(char * path)
3526 RecursiveDeleteFolderFSI fsi { };
3531 #if defined(__WIN32__)
3532 define sdkDirName = "Ecere SDK";
3534 define sdkDirName = "ecere";
3537 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3540 char * v = new char[maxPathLen];
3544 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3545 StripLastDirectory(path, path);
3546 PathCat(path, subDir);
3547 if(name) PathCat(path, name);
3548 if(FileExists(path) & attribs) found = true;
3550 #if defined(__WIN32__)
3553 for(s : [ "ECERE_SDK_SRC", "AppData", "ALLUSERSPROFILE", "USERPROFILE", "HOMEPATH", "ProgramData", "ProgramFiles", "ProgramFiles(x86)", "SystemDrive" ])
3555 GetEnvironment(s, v, maxPathLen);
3558 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3559 if(!strcmp(s, "SystemDrive"))
3560 PathCat(path, "Program Files");
3561 if(strcmp(s, "ECERE_SDK_SRC"))
3562 PathCat(path, sdkDirName);
3563 PathCat(path, subDir);
3564 if(name) PathCat(path, name);
3565 if(FileExists(path) & attribs)
3580 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3581 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3584 p = new char[MAX_LOCATION];
3586 strcat(p, "/usr/share");
3590 for(c=0; c<numTokens; c++)
3592 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3593 PathCat(path, sdkDirName);
3594 PathCat(path, subDir);
3596 PathCat(path, name);
3597 if(FileExists(path) & attribs)
3610 void FindAndShellOpenInstalledFolder(const char * name)
3612 char path[MAX_LOCATION];
3613 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3617 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3619 char path[MAX_LOCATION];
3620 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3624 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3626 bool preserveRootFolder;
3628 void OutFolder(const char * folderPath, bool isRoot)
3630 if(!(preserveRootFolder && isRoot))
3631 RemoveDir(folderPath);
3634 bool OnFile(const char * filePath)
3636 DeleteFile(filePath);
3641 class IDEApp : GuiApplication
3643 //driver = "Win32Console";
3644 // driver = "OpenGL";
3648 TempFile includeFile { };
3653 char ext[MAX_EXTENSION];
3654 SetLoggingMode(stdOut, null);
3655 //SetLoggingMode(debug, null);
3657 settingsContainer.Load();
3659 if(ideSettings.language)
3661 const String language = GetLanguageString();
3662 if(ideSettings.language.OnCompare(language))
3664 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3669 // First count files arg to decide whether to maximize
3671 bool passThrough = false, debugWorkDir = false;
3674 for(c = 1; c<app.argc; c++)
3677 else if(debugWorkDir)
3678 debugWorkDir = false;
3679 else if(!strcmp(app.argv[c], "-t"));
3680 else if(!strcmp(app.argv[c], "-no-parsing"));
3681 else if(!strcmp(app.argv[c], "-debug-start"));
3682 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3683 debugWorkDir = true;
3684 else if(!strcmp(app.argv[c], "-@"))
3691 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3693 app.driver = "OpenGL";
3694 ide.driverItems[1].checked = true;
3698 #if defined(__unix__) || defined(__APPLE__)
3699 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3701 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3703 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3707 char model[MAX_LOCATION];
3708 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3710 ide.duck.modelFile = model;
3711 ide.duck.parent = ideMainFrame;
3714 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3715 ide.debugRubberDuck.disabled = false;
3719 desktop.caption = titleECEREIDE;
3722 for(c = 1; c<app.argc; c++)
3724 char fullPath[MAX_LOCATION];
3725 GetWorkingDir(fullPath, MAX_LOCATION);
3726 PathCat(fullPath, app.argv[c]);
3727 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3731 // Default to language specified by environment if no language selected
3732 if(!ideSettings.language)
3734 ideSettings.language = GetLanguageString();
3735 settingsContainer.Save();
3738 // Default to home directory if no directory yet set up
3739 if(!ideSettings.ideProjectFileDialogLocation[0])
3742 char location[MAX_LOCATION];
3743 char * home = getenv("HOME");
3744 char * homeDrive = getenv("HOMEDRIVE");
3745 char * homePath = getenv("HOMEPATH");
3746 char * userProfile = getenv("USERPROFILE");
3747 char * systemDrive = getenv("SystemDrive");
3748 if(home && FileExists(home).isDirectory)
3750 strcpy(location, home);
3753 if(!found && homeDrive && homePath)
3755 strcpy(location, homeDrive);
3756 PathCat(location, homePath);
3757 if(FileExists(location).isDirectory)
3760 if(!found && FileExists(userProfile).isDirectory)
3762 strcpy(location, userProfile);
3765 if(!found && FileExists(systemDrive).isDirectory)
3767 strcpy(location, systemDrive);
3772 ideSettings.ideProjectFileDialogLocation = location;
3773 if(!ideSettings.ideFileDialogLocation[0])
3774 ideSettings.ideFileDialogLocation = location;
3778 if(!LoadIncludeFile())
3779 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3781 // Create language menu
3783 String language = ideSettings.language;
3787 ide.languageItems = new MenuItem[languages.count];
3790 ide.languageItems[i] =
3792 ide.languageMenu, l.name;
3793 bitmap = { l.bitmap };
3797 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3799 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3801 // Re-select previous selected language if aborted
3802 String language = ideSettings.language;
3806 if(((!language || !language[0]) && i == 0) ||
3807 (language && !strcmpi(l.code, language)))
3809 ide.languageItems[i].checked = true;
3821 // Try to find country-specific language first
3827 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3829 ide.languageItems[i].checked = true;
3837 // Try generalizing locale
3838 if(!found && language)
3841 char genericLocale[256];
3843 strncpy(genericLocale, language, sizeof(genericLocale));
3844 genericLocale[sizeof(genericLocale)-1] = 0;
3846 under = strchr(genericLocale, '_');
3849 if(!strcmpi(genericLocale, "zh"))
3850 strcpy(genericLocale, "zh_CN");
3851 if(strcmp(genericLocale, language))
3855 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3857 ide.languageItems[i].checked = true;
3867 ide.languageItems[0].checked = true;
3869 MenuDivider { ide.languageMenu };
3872 ide.languageMenu, "Help Translate";
3874 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3876 ShellOpen("http://translations.launchpad.net/ecere");
3882 ideMainFrame.Create();
3883 if(app.argFilesCount > 1)
3884 ide.MenuWindowTileVert(null, 0);
3888 bool Cycle(bool idle)
3892 if(ide.documentor.Peek())
3895 ide.documentor.GetLine(line, sizeof(line));
3896 if(!strcmpi(line, "Exited"))
3898 ide.documentor.CloseInput();
3899 ide.documentor.CloseOutput();
3900 ide.documentor.Wait();
3901 delete ide.documentor;
3904 if(ide.documentor && ide.documentor.eof)
3906 ide.documentor.CloseInput();
3907 ide.documentor.CloseOutput();
3908 ide.documentor.Wait();
3909 delete ide.documentor;
3915 bool LoadIncludeFile()
3917 bool result = false;
3918 File include = FileOpen(":crossplatform.mk", read);
3921 File f = includeFile;
3924 for(; !include.Eof(); )
3927 int count = include.Read(buffer, 1, 4096);
3928 f.Write(buffer, 1, count);
3938 IDEMainFrame ideMainFrame { };
3940 define app = ((IDEApp)__thisModule);
3942 define titleECEREIDE = $"Ecere IDE (Debug)";
3944 define titleECEREIDE = $"Ecere IDE";