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 recentFiles { fileMenu, $"Recent Files", r };
738 Menu recentProjects { 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 for(file : ideSettings.recentFiles)
756 if(id == selection.id)
759 char extension[MAX_EXTENSION] = "";
760 GetExtension(file, extension);
761 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
762 if(mods.ctrl && !mods.shift)
764 char * command = PrintString("ecere-ide ", isProjectFile ? "-t " : "", file);
770 OpenFile(file, false, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
771 ide.RepositionWindows(false);
780 bool FileRecentProject(MenuItem selection, Modifiers mods)
783 for(file : ideSettings.recentProjects)
785 if(id == selection.id)
787 if(mods.ctrl && !mods.shift)
789 char * command = PrintString("ecere-ide ", file);
794 OpenFile(file, false, true, (mods.ctrl && mods.shift) ? "txt" : null, no, normal, mods.ctrl && mods.shift);
802 MenuPlacement editMenu { menu, $"Edit", e };
804 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
805 MenuItem projectNewItem
807 projectMenu, $"New...", n, Key { n, true, true };
808 bitmap = { ":actions/projNew.png" };
809 bool NotifySelect(MenuItem selection, Modifiers mods)
811 if(!DontTerminateDebugSession($"New Project"))
814 NewProjectDialog newProjectDialog { master = this };
815 incref newProjectDialog;
816 result = newProjectDialog.Modal();
821 newProjectDialog.CreateNewProject();
824 ideSettings.AddRecentProject(projectView.fileName);
825 ide.UpdateRecentMenus();
826 settingsContainer.Save();
830 delete newProjectDialog;
835 MenuItem projectOpenItem
837 projectMenu, $"Open...", o, Key { o, true, true };
838 bitmap = { ":actions/projOpen.png" };
839 bool NotifySelect(MenuItem selection, Modifiers mods)
841 if(ideSettings.ideProjectFileDialogLocation)
842 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
844 ideProjectFileDialog.text = openProjectFileDialogTitle;
845 if(ideProjectFileDialog.Modal() == ok)
847 OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
848 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
853 MenuItem projectQuickItem
855 projectMenu, $"Quick...", q, f7, disabled = true;
856 bool NotifySelect(MenuItem selection, Modifiers mods)
859 QuickProjectDialog { this }.Modal();
863 MenuItem projectAddItem
865 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
866 bitmap = { ":actions/projAdd.png" };
868 bool NotifySelect(MenuItem selection, Modifiers mods)
870 if(ideSettings.ideProjectFileDialogLocation)
871 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
873 ideProjectFileDialog.text = addProjectFileDialogTitle;
876 if(ideProjectFileDialog.Modal() == ok)
878 if(OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
880 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
881 contents = $"Add a different project?" }.Modal() == no)
892 MenuItem projectCloseItem
894 projectMenu, $"Close", c, disabled = true;
895 bool NotifySelect(MenuItem selection, Modifiers mods)
899 if(!ide.DontTerminateDebugSession($"Project Close"))
905 MenuDivider { projectMenu };
906 MenuItem projectSettingsItem
908 projectMenu, $"Settings...", s, altF7, disabled = true;
909 bool NotifySelect(MenuItem selection, Modifiers mods)
911 projectView.MenuSettings(projectView.active ? selection : null, mods);
915 MenuDivider { projectMenu };
916 MenuItem projectBrowseFolderItem
918 projectMenu, $"Browse Project Folder", p, disabled = true;
919 bool NotifySelect(MenuItem selection, Modifiers mods)
922 projectView.MenuBrowseFolder(null, mods);
926 MenuDivider { projectMenu };
927 MenuItem projectRunItem
929 projectMenu, $"Run", r, ctrlF5, disabled = true;
930 bitmap = { ":actions/run.png" };
931 bool NotifySelect(MenuItem selection, Modifiers mods)
934 projectView.Run(null, mods);
938 MenuItem projectBuildItem
940 projectMenu, $"Build", b, f7, disabled = true;
941 bitmap = { ":actions/build.png" };
942 bool NotifySelect(MenuItem selection, Modifiers mods)
946 if(projectView.buildInProgress == none)
947 projectView.ProjectBuild(projectView.active ? selection : null, mods);
949 projectView.stopBuild = true;
954 MenuItem projectLinkItem
956 projectMenu, $"Relink", l, disabled = true;
957 bitmap = { ":actions/relink.png" };
958 bool NotifySelect(MenuItem selection, Modifiers mods)
961 projectView.ProjectLink(projectView.active ? selection : null, mods);
965 MenuItem projectRebuildItem
967 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
968 bitmap = { ":actions/rebuild.png" };
969 bool NotifySelect(MenuItem selection, Modifiers mods)
972 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
976 MenuItem projectCleanTargetItem
978 projectMenu, $"Clean Target", g, disabled = true;
979 bitmap = { ":actions/clean.png" };
980 bool NotifySelect(MenuItem selection, Modifiers mods)
985 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
990 MenuItem projectCleanItem
992 projectMenu, $"Clean", e, disabled = true;
993 bitmap = { ":actions/clean.png" };
994 bool NotifySelect(MenuItem selection, Modifiers mods)
999 projectView.ProjectClean(projectView.active ? selection : null, mods);
1004 MenuItem projectRealCleanItem
1006 projectMenu, $"Real Clean", disabled = true;
1007 bitmap = { ":actions/clean.png" };
1008 bool NotifySelect(MenuItem selection, Modifiers mods)
1013 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1018 MenuItem projectRegenerateItem
1020 projectMenu, $"Regenerate Makefile", m, disabled = true;
1021 bitmap = { ":actions/regMakefile.png" };
1022 bool NotifySelect(MenuItem selection, Modifiers mods)
1025 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1029 MenuItem projectInstallItem
1031 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
1032 projectMenu, $"Install", t, disabled = true;
1034 bitmap = { ":status/software-update-available.png" };
1035 bool NotifySelect(MenuItem selection, Modifiers mods)
1038 projectView.ProjectInstall(projectView.active ? selection : null, mods);
1042 MenuItem projectCompileItem;
1043 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1044 MenuItem debugStartResumeItem
1046 debugMenu, $"Start", s, f5, disabled = true;
1047 bitmap = { ":actions/debug.png" };
1048 NotifySelect = MenuDebugStart;
1050 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1054 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1055 if(!projectView.DebugStart())
1056 debugStartResumeItem.disabled = false; // same exception
1060 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1063 projectView.DebugResume();
1066 MenuItem debugRestartItem
1068 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1069 bitmap = { ":actions/restart.png" };
1070 bool NotifySelect(MenuItem selection, Modifiers mods)
1073 projectView.DebugRestart();
1077 MenuItem debugBreakItem
1079 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1080 bitmap = { ":actions/pause.png" };
1081 bool NotifySelect(MenuItem selection, Modifiers mods)
1083 if(projectView && projectView.buildInProgress != none)
1086 projectView.DebugBreak();
1090 MenuItem debugStopItem
1092 debugMenu, $"Stop", p, shiftF5, disabled = true;
1093 bitmap = { ":actions/stopDebug.png" };
1094 bool NotifySelect(MenuItem selection, Modifiers mods)
1097 projectView.DebugStop();
1101 MenuDivider { debugMenu };
1105 // nonClient = true,
1112 anchor = { right = 0, bottom = 0 },
1114 isActiveClient = false,
1116 clickThrough = true,
1117 size = { 500, 500 };
1119 bool OnLoadGraphics()
1121 ModelView::OnLoadGraphics();
1122 camera.position.z /= 1.3;
1123 camera.orientation = Euler { yaw = 280, pitch = 20 };
1129 bool OnRightButtonDown(int x, int y, Modifiers mods)
1131 if(!displaySystem.flags.flipping) return true;
1132 MenuWindowMove(null, 0);
1136 bool OnRightButtonUp(int x, int y, Modifiers mods)
1138 position = position;
1143 MenuItem debugRubberDuck
1145 debugMenu, $"Rubber Duck", checkable = true, disabled = true;
1146 bool NotifySelect(MenuItem selection, Modifiers mods)
1148 if(selection.checked)
1156 MenuDivider { debugMenu };
1157 MenuItem debugUseValgrindItem
1159 debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
1160 bool NotifySelect(MenuItem selection, Modifiers mods)
1164 ide.workspace.useValgrind = selection.checked;
1165 ide.workspace.Save();
1167 ide.AdjustValgrindMenus();
1171 Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
1172 MenuItem debugValgrindNoLeakCheckItem { debugValgrindLeakCheckItem, $"No" , f, id = ValgrindLeakCheck::no , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1173 MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; };
1174 MenuItem debugValgrindYesLeakCheckItem { debugValgrindLeakCheckItem, $"Yes" , f, id = ValgrindLeakCheck::yes , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1175 MenuItem debugValgrindFullLeakCheckItem { debugValgrindLeakCheckItem, $"Full" , f, id = ValgrindLeakCheck::full , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1176 bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
1180 if(selection.checked)
1182 ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
1184 debugValgrindNoLeakCheckItem.checked = debugValgrindNoLeakCheckItem.id == vgLeakCheck;
1185 debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
1186 debugValgrindYesLeakCheckItem.checked = debugValgrindYesLeakCheckItem.id == vgLeakCheck;
1187 debugValgrindFullLeakCheckItem.checked = debugValgrindFullLeakCheckItem.id == vgLeakCheck;
1189 ide.workspace.vgLeakCheck = vgLeakCheck;
1190 ide.workspace.Save();
1193 selection.checked = true;
1197 Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
1198 MenuItem debugValgrindRSDefaultItem { debugValgrindRedzoneSizeItem, $"Default", f, id = -1, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; };
1199 MenuItem debugValgrindRS0Item { debugValgrindRedzoneSizeItem, "0" , f, id = 0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1200 MenuItem debugValgrindRS16Item { debugValgrindRedzoneSizeItem, "16" , f, id = 16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1201 MenuItem debugValgrindRS32Item { debugValgrindRedzoneSizeItem, "32" , f, id = 32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1202 MenuItem debugValgrindRS64Item { debugValgrindRedzoneSizeItem, "64" , f, id = 64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1203 MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, "128" , f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1204 MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, "256" , f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1205 MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, "512" , f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1206 bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
1210 if(selection.checked)
1212 int vgRedzoneSize = (int)selection.id;
1214 debugValgrindRSDefaultItem.checked = debugValgrindRSDefaultItem.id == vgRedzoneSize;
1215 debugValgrindRS0Item.checked = debugValgrindRS0Item.id == vgRedzoneSize;
1216 debugValgrindRS16Item.checked = debugValgrindRS16Item.id == vgRedzoneSize;
1217 debugValgrindRS32Item.checked = debugValgrindRS32Item.id == vgRedzoneSize;
1218 debugValgrindRS64Item.checked = debugValgrindRS64Item.id == vgRedzoneSize;
1219 debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
1220 debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
1221 debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
1223 ide.workspace.vgRedzoneSize = vgRedzoneSize;
1224 ide.workspace.Save();
1227 selection.checked = true;
1231 MenuItem debugValgrindTrackOriginsItem
1233 debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
1234 bool NotifySelect(MenuItem selection, Modifiers mods)
1238 ide.workspace.vgTrackOrigins = selection.checked;
1239 ide.workspace.Save();
1245 MenuDivider { debugMenu };
1246 MenuItem debugStepIntoItem
1248 debugMenu, $"Step Into", i, f11, disabled = true;
1249 bitmap = { ":actions/stepInto.png" };
1250 bool NotifySelect(MenuItem selection, Modifiers mods)
1252 if(projectView) projectView.DebugStepInto();
1256 MenuItem debugStepOverItem
1258 debugMenu, $"Step Over", v, f10, disabled = true;
1259 bitmap = { ":actions/stepOver.png" };
1260 bool NotifySelect(MenuItem selection, Modifiers mods)
1262 if(projectView) projectView.DebugStepOver(false);
1266 MenuItem debugSkipStepOverItem
1268 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1269 bitmap = { ":actions/stepOverSkipBreak.png" };
1270 bool NotifySelect(MenuItem selection, Modifiers mods)
1272 if(projectView) projectView.DebugStepOver(true);
1276 MenuItem debugStepOutItem
1278 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1279 bitmap = { ":actions/stepOut.png" };
1280 bool NotifySelect(MenuItem selection, Modifiers mods)
1282 if(projectView) projectView.DebugStepOut(false);
1286 MenuItem debugSkipStepOutItem
1288 debugMenu, $"Step Out Skipping Breakpoints", n, Key { f11, ctrl = true, shift = true }, disabled = true;
1289 bitmap = { ":actions/skipBreaks.png" };
1290 bool NotifySelect(MenuItem selection, Modifiers mods)
1292 if(projectView) projectView.DebugStepOut(true);
1297 MenuItem debugStepUntilItem
1299 debugMenu, $"Step Over Until Next Line", x, disabled = true;
1300 bool NotifySelect(MenuItem selection, Modifiers mods)
1302 if(projectView) projectView.DebugStepUntil(false);
1306 MenuItem debugSkipStepUntilItem
1308 debugMenu, $"Step Over Until Next Line Skipping Breakpoints", e, Key { f10, shift = true, alt = true }, disabled = true;
1309 bool NotifySelect(MenuItem selection, Modifiers mods)
1311 if(projectView) projectView.DebugStepUntil(true);
1316 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1317 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1318 MenuPlacement debugRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level", l };
1319 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", g };
1321 MenuPlacement debugBpRunToCursorItem { debugMenu, $"BP Run To Cursor" };
1322 MenuPlacement debugBpSkipRunToCursorItem { debugMenu, $"BP Run To Cursor Skipping Breakpoints" };
1323 MenuPlacement debugBpRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level" };
1324 MenuPlacement debugBpSkipRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level Skipping Breakpoints" };
1326 //MenuDivider { debugMenu };
1327 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1328 MenuPlacement imageMenu { menu, $"Image", i };
1329 Menu viewMenu { menu, $"View", v };
1330 MenuItem viewProjectItem
1332 viewMenu, $"Project View", j, alt0, disabled = true;
1333 bool NotifySelect(MenuItem selection, Modifiers mods)
1337 projectView.visible = true;
1338 projectView.Activate();
1343 MenuPlacement { viewMenu, $"View Designer" };
1344 MenuPlacement { viewMenu, $"View Code" };
1345 MenuPlacement { viewMenu, $"View Properties" };
1346 MenuPlacement { viewMenu, $"View Methods" };
1347 MenuItem viewDesignerItem
1349 viewMenu, $"View Designer", d, f8;
1350 bool NotifySelect(MenuItem selection, Modifiers mods)
1352 Window client = activeClient;
1353 Class dataType = client._class;
1354 if(!strcmp(dataType.name, "Designer"))
1356 client.visible = true;
1360 ((CodeEditor)client).ViewDesigner();
1364 MenuItem viewCodeItem
1366 viewMenu, $"View Code", c, f8;
1367 bool NotifySelect(MenuItem selection, Modifiers mods)
1369 Window client = activeClient;
1370 Class dataType = client._class;
1371 if(!strcmp(dataType.name, "Designer"))
1372 client = ((Designer)client).codeEditor;
1375 // Do this after so the caret isn't moved yet...
1376 client.visible = true;
1380 MenuItem viewPropertiesItem
1382 viewMenu, $"View Properties", p, f4;
1383 bool NotifySelect(MenuItem selection, Modifiers mods)
1385 sheet.visible = true;
1386 sheet.sheetSelected = properties;
1391 MenuItem viewMethodsItem
1393 viewMenu, $"View Methods", m, f4;
1394 bool NotifySelect(MenuItem selection, Modifiers mods)
1396 sheet.visible = true;
1397 sheet.sheetSelected = methods;
1402 MenuItem viewToolBoxItem
1404 viewMenu, $"View Toolbox", x, f12;
1405 bool NotifySelect(MenuItem selection, Modifiers mods)
1407 toolBox.visible = true;
1412 MenuItem viewOutputItem
1414 viewMenu, $"Output", o, alt2;
1415 bool NotifySelect(MenuItem selection, Modifiers mods)
1421 MenuItem viewWatchesItem
1423 viewMenu, $"Watches", w, alt3;
1424 bool NotifySelect(MenuItem selection, Modifiers mods)
1430 MenuItem viewThreadsItem
1432 viewMenu, $"Threads", t, alt4;
1433 bool NotifySelect(MenuItem selection, Modifiers mods)
1439 MenuItem viewBreakpointsItem
1441 viewMenu, $"Breakpoints", b, alt5;
1442 bool NotifySelect(MenuItem selection, Modifiers mods)
1444 breakpointsView.Show();
1448 MenuItem viewCallStackItem
1450 viewMenu, $"Call Stack", s, alt7;
1451 bool NotifySelect(MenuItem selection, Modifiers mods)
1453 callStackView.Show();
1457 MenuItem viewAllDebugViews
1459 viewMenu, $"All Debug Views", a, alt9;
1460 bool NotifySelect(MenuItem selection, Modifiers mods)
1465 callStackView.Show();
1466 breakpointsView.Show();
1470 #ifdef GDB_DEBUG_GUI
1471 MenuDivider { viewMenu };
1472 MenuItem viewGDBItem
1474 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1475 bool NotifySelect(MenuItem selection, Modifiers mods)
1482 MenuDivider { viewMenu };
1483 MenuItem viewColorPicker
1485 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1486 bool NotifySelect(MenuItem selection, Modifiers mods)
1488 ColorPicker colorPicker { master = this };
1489 colorPicker.Modal();
1493 MenuDivider { viewMenu };
1497 viewMenu, "Full Screen", f, checkable = true;
1499 bool NotifySelect(MenuItem selection, Modifiers mods)
1501 app.fullScreen ^= true;
1503 anchor = { 0, 0, 0, 0 };
1508 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1510 MenuDivider { viewMenu };
1512 Menu languageMenu { viewMenu, "Language", l };
1514 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1515 Menu windowMenu { menu, $"Window", w };
1516 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1517 MenuDivider { windowMenu };
1518 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1519 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1520 MenuDivider { windowMenu };
1521 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1522 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1523 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1524 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1525 MenuDivider { windowMenu };
1526 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1527 Menu helpMenu { menu, $"Help", h };
1530 helpMenu, $"API Reference", r, f1;
1531 bool NotifySelect(MenuItem selection, Modifiers mods)
1535 char * p = new char[MAX_LOCATION];
1537 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1538 PathCat(p, "documentor");
1539 #if defined(__WIN32__)
1540 ChangeExtension(p, "exe", p);
1542 if(!FileExists(p).isFile)
1543 strcpy(p, "documentor");
1545 documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
1550 Process_ShowWindows(documentor.GetProcessID());
1551 // documentor.Puts("Activate\n");
1556 MenuDivider { helpMenu };
1559 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1560 bool NotifySelect(MenuItem selection, Modifiers mods)
1562 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1566 MenuDivider { helpMenu };
1569 helpMenu, $"Documentation Folder", d;
1570 bool NotifySelect(MenuItem selection, Modifiers mods)
1572 FindAndShellOpenInstalledFolder("doc");
1578 helpMenu, $"Samples Folder", s;
1579 bool NotifySelect(MenuItem selection, Modifiers mods)
1581 FindAndShellOpenInstalledFolder("samples");
1587 helpMenu, $"Extras Folder", x;
1588 bool NotifySelect(MenuItem selection, Modifiers mods)
1590 FindAndShellOpenInstalledFolder("extras");
1594 MenuDivider { helpMenu };
1597 helpMenu, $"Community Forums", f;
1598 bool NotifySelect(MenuItem selection, Modifiers mods)
1600 ShellOpen("http://ecere.com/forums");
1604 MenuDivider { helpMenu };
1607 helpMenu, $"About...", a;
1608 bool NotifySelect(MenuItem selection, Modifiers mods)
1610 AboutIDE { master = this }.Modal();
1615 property ToolBox toolBox
1617 get { return toolBox; }
1620 property Sheet sheet
1622 get { return sheet; }
1625 property Project project
1627 get { return projectView ? projectView.project : null; }
1630 property Workspace workspace
1632 get { return projectView ? projectView.workspace : null; }
1635 FindInFilesDialog findInFilesDialog
1638 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1645 #ifdef GDB_DEBUG_GUI
1648 master = this, parent = this;
1649 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1651 void OnCommand(const char * string)
1654 ide.debugger.SendGDBCommand(string);
1659 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1661 //app.driver = app.drivers[selection.id];
1662 #if defined(__unix__) || defined(__APPLE__)
1663 app.driver = selection.id ? "OpenGL" : "X";
1665 app.driver = selection.id ? "OpenGL" : "GDI";
1667 delete ideSettings.displayDriver;
1668 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1670 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1672 settingsContainer.Save();
1673 //SetDriverAndSkin();
1677 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1679 app.skin = app.skins[selection.id];
1684 void SetDriverAndSkin()
1687 for(c = 0; c < app.numSkins; c++)
1688 if(!strcmp(app.skins[c], app.skin))
1690 skinItems[c].checked = true;
1693 for(c = 0; c < app.numDrivers; c++)
1694 if(!strcmp(app.drivers[c], app.driver))
1696 driverItems[c].checked = true;
1701 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1703 Project project = workspace.projects.firstIterator.data;
1704 projectView = ProjectView
1707 fileName = fileName;
1709 void NotifyDestroyed(Window window, DialogResult result)
1712 text = titleECEREIDE;
1717 projectView.Create();
1718 RepositionWindows(false);
1720 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1721 projectView.workspace = workspace;
1722 projectView.project = project;
1723 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1727 ide.breakpointsView.LoadFromWorkspace();
1728 ide.watchesView.LoadFromWorkspace();
1730 findInFilesDialog.projectNodeField.userData = projectView;
1733 char fileName[MAX_LOCATION];
1734 strcpy(fileName, project.topNode.path);
1735 PathCat(fileName, project.topNode.name);
1742 projectView.visible = false;
1743 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1745 if(findInFilesDialog)
1747 char workingDir[MAX_LOCATION];
1748 GetWorkingDir(workingDir, MAX_LOCATION);
1749 findInFilesDialog.SearchStop();
1750 findInFilesDialog.currentDirectory = workingDir;
1752 sheet.visible = false;
1753 toolBox.visible = false;
1754 outputView.visible = false;
1755 ideMainFrame.text = titleECEREIDE;
1762 void RepositionWindows(bool expand)
1767 bool callStackVisible = expand ? false : callStackView.visible;
1768 bool threadsVisible = expand ? false : threadsView.visible;
1769 bool watchesVisible = expand ? false : watchesView.visible;
1770 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1771 bool toolBoxVisible = toolBox.visible;
1772 bool outputVisible = expand ? false : outputView.visible;
1773 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1774 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1776 for(child = firstChild; child; child = child.next)
1778 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1779 child._class == class(Sheet) || child._class == class(ProjectView))
1781 Anchor anchor = child.anchor;
1782 anchor.top = topDistance;
1783 anchor.bottom = bottomDistance;
1784 if(child._class == class(CodeEditor) || child._class == class(Designer))
1786 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1787 anchor.right = toolBoxVisible ? 150 : 0;
1790 child.anchor = anchor;
1794 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1795 child._class == class(BreakpointsView))
1796 child.visible = false;
1799 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1801 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1805 bool ShowCodeEditor()
1808 activeClient.Activate();
1809 else if(projectView)
1811 projectView.visible = true;
1812 projectView.Activate();
1814 else if(sheet.visible)
1817 outputView.visible = false;
1821 void DocumentSaved(Window document, const char * fileName)
1823 ideSettings.AddRecentFile(fileName);
1824 ide.UpdateRecentMenus();
1825 ide.AdjustFileMenus();
1826 settingsContainer.Save();
1829 bool Window::OnFileModified(FileChange fileChange, const char * param)
1832 sprintf(temp, $"The document %s was modified by another application.\n"
1833 "Would you like to reload it and lose your changes?", this.fileName);
1834 if(MessageBox { creationActivation = flash, type = yesNo, master = this/*.parent*/,
1835 text = $"Document has been modified", contents = temp }.Modal() == yes)
1837 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1838 char * fileName = CopyString(this.fileName);
1839 WindowState state = this.state;
1840 Anchor anchor = this.anchor;
1841 Size size = this.size;
1843 this.modifiedDocument = false;
1845 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1848 this.anchor = anchor;
1850 this.SetState(state, true, 0);
1858 void UpdateMakefiles()
1862 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
1863 for(prj : workspace.projects)
1864 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1869 void UpdateCompilerConfigs(bool mute)
1871 UpdateToolBarActiveCompilers();
1874 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1875 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
1878 projectView.ShowOutputBuildLog(true);
1879 projectView.DisplayCompiler(compiler, false);
1881 for(prj : workspace.projects)
1882 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1887 void UpdateToolBarActiveCompilers()
1889 toolBar.activeCompiler.Clear();
1890 for(compiler : ideSettings.compilerConfigs)
1892 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1893 if(workspace && workspace.activeCompiler && !strcmp(compiler.name, workspace.activeCompiler))
1894 toolBar.activeCompiler.currentRow = row;
1896 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1897 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1898 toolBar.activeBitDepth.SelectRow(toolBar.activeBitDepth.FindRow(workspace ? workspace.bitDepth : 0));
1901 void UpdateToolBarActiveConfigs(bool selectionOnly)
1903 bool commonSelected = false;
1904 DataRow row = toolBar.activeConfig.currentRow;
1906 row = toolBar.activeConfig.FindRow(1);
1909 toolBar.activeConfig.Clear();
1910 row = toolBar.activeConfig.AddString($"(Mixed)");
1915 char * configName = null;
1918 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1919 for(prj : workspace.projects)
1921 for(cfg : prj.configurations)
1924 configs[cfg.name] = 1;
1929 toolBar.activeConfig.AddString(&name);
1933 if(projectView && projectView.project)
1935 for(prj : workspace.projects)
1937 if(prj.config && prj.config.name)
1939 configName = prj.config.name;
1945 commonSelected = true;
1946 for(prj : workspace.projects)
1948 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1950 commonSelected = false;
1958 commonSelected = false;
1959 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1961 if(!strcmp(row.string, configName))
1963 toolBar.activeConfig.currentRow = row;
1964 commonSelected = true;
1971 toolBar.activeConfig.Sort(null, 0);
1973 toolBar.activeConfig.currentRow = row;
1978 bool unavailable = !project;
1980 projectAddItem.disabled = unavailable;
1981 toolBar.buttonAddProject.disabled = unavailable;
1983 projectSettingsItem.disabled = unavailable;
1985 projectBrowseFolderItem.disabled = unavailable;
1987 viewProjectItem.disabled = unavailable;
1989 toolBar.activeConfig.disabled = unavailable;
1990 toolBar.activeCompiler.disabled = unavailable;
1991 toolBar.activeBitDepth.disabled = unavailable;
1994 debugUseValgrindItem.disabled = unavailable;
1995 AdjustValgrindMenus();
2004 void AdjustValgrindMenus()
2006 bool unavailable = !project || !debugUseValgrindItem.checked;
2007 debugValgrindNoLeakCheckItem.disabled = unavailable;
2008 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2009 debugValgrindYesLeakCheckItem.disabled = unavailable;
2010 debugValgrindFullLeakCheckItem.disabled = unavailable;
2012 debugValgrindTrackOriginsItem.disabled = unavailable;
2014 debugValgrindRSDefaultItem.disabled = unavailable;
2015 debugValgrindRS0Item.disabled = unavailable;
2016 debugValgrindRS16Item.disabled = unavailable;
2017 debugValgrindRS32Item.disabled = unavailable;
2018 debugValgrindRS64Item.disabled = unavailable;
2019 debugValgrindRS128Item.disabled = unavailable;
2020 debugValgrindRS256Item.disabled = unavailable;
2021 debugValgrindRS512Item.disabled = unavailable;
2025 property bool hasOpenedCodeEditors
2030 for(w = firstChild; w; w = w.next)
2031 if(w._class == class(CodeEditor) &&
2032 w.isDocument && !w.closing && w.visible && w.created &&
2033 w.fileName && w.fileName[0])
2039 void AdjustFileMenus()
2041 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2043 projectQuickItem.disabled = unavailable;
2046 void AdjustBuildMenus()
2048 bool unavailable = project && projectView.buildInProgress;
2049 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2050 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2052 projectNewItem.disabled = unavailable;
2053 toolBar.buttonNewProject.disabled = unavailable;
2054 projectOpenItem.disabled = unavailable;
2055 toolBar.buttonOpenProject.disabled = unavailable;
2057 unavailable = !project || projectView.buildInProgress;
2059 projectCloseItem.disabled = unavailable;
2060 // toolBar.buttonCloseProject.disabled = unavailable;
2062 projectRunItem.disabled = naForRun;
2063 toolBar.buttonRun.disabled = naForRun;
2065 projectBuildItem.disabled = false;
2066 projectBuildItem.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2067 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2069 projectLinkItem.disabled = unavailable;
2070 toolBar.buttonReLink.disabled = unavailable;
2071 projectRebuildItem.disabled = unavailable;
2072 toolBar.buttonRebuild.disabled = unavailable;
2073 projectCleanItem.disabled = unavailable;
2074 toolBar.buttonClean.disabled = unavailable;
2075 projectCleanTargetItem.disabled = unavailable;
2076 projectRealCleanItem.disabled = unavailable;
2077 // toolBar.buttonRealClean.disabled = unavailable;
2078 projectRegenerateItem.disabled = unavailable;
2079 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2080 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2081 projectInstallItem.disabled = unavailable;
2082 toolBar.buttonInstall.disabled = unavailable;
2084 projectCompileItem.disabled = unavailable;
2086 AdjustPopupBuildMenus();
2089 void AdjustPopupBuildMenus()
2091 bool unavailable = !project || projectView.buildInProgress;
2093 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2096 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2097 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, mode);
2100 menu.disabled = false;
2101 menu.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2102 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2105 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, mode); if(menu) menu.disabled = unavailable;
2106 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, mode); if(menu) menu.disabled = unavailable;
2107 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, mode); if(menu) menu.disabled = unavailable;
2108 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, mode); if(menu) menu.disabled = unavailable;
2109 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, mode); if(menu) menu.disabled = unavailable;
2110 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, mode); if(menu) menu.disabled = unavailable;
2111 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, mode); if(menu) menu.disabled = unavailable;
2112 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, mode); if(menu) menu.disabled = unavailable;
2113 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, mode); if(menu) menu.disabled = unavailable;
2114 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, mode); if(menu) menu.disabled = unavailable;
2115 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, mode); if(menu) menu.disabled = unavailable;
2116 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, mode); if(menu) menu.disabled = unavailable;
2117 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, mode); if(menu) menu.disabled = unavailable;
2118 projectView.popupMenu.Update(null);
2122 property bool areDebugMenusUnavailable { get {
2124 project.GetTargetType(project.config) != executable ||
2125 projectView.buildInProgress == buildingMainProject;
2128 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2129 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2130 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2132 void AdjustDebugMenus()
2134 bool unavailable = areDebugMenusUnavailable;
2135 bool running = isDebuggerRunning;
2136 bool stopped = isDebuggerStopped;
2137 bool active = debugger.isActive;
2139 bool isNotRunning = unavailable || !running;
2140 bool isNotNotRunning = unavailable || running;
2141 bool isNotStopped = unavailable || !stopped;
2142 bool isNotActive = unavailable || !active;
2144 debugStartResumeItem.disabled = isNotNotRunning;
2145 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2146 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2149 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2150 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2153 debugBreakItem.disabled = isNotRunning;
2154 debugStopItem.disabled = isNotActive;
2155 debugRestartItem.disabled = isNotActive;
2158 toolBar.buttonDebugPause.disabled = isNotRunning;
2159 toolBar.buttonDebugStop.disabled = isNotActive;
2160 toolBar.buttonDebugRestart.disabled = isNotActive;
2163 debugStepIntoItem.disabled = isNotNotRunning;
2164 debugStepOverItem.disabled = isNotNotRunning;
2165 debugSkipStepOverItem.disabled = isNotNotRunning;
2166 debugStepOutItem.disabled = isNotStopped;
2167 debugSkipStepOutItem.disabled = isNotStopped;
2169 debugStepUntilItem.disabled = isNotStopped;
2170 debugSkipStepUntilItem.disabled = isNotStopped;
2174 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2175 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2176 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2177 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2178 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2180 if((Designer)GetActiveDesigner())
2182 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2184 codeEditor.AdjustDebugMenus();
2188 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2190 char tempString[MAX_LOCATION];
2191 strcpy(tempString, directory);
2192 if(saveSettings && !projectView)
2194 ideSettings.ideFileDialogLocation = directory;
2195 settingsContainer.Save();
2198 ideFileDialog.currentDirectory = tempString;
2199 codeEditorFileDialog.currentDirectory = tempString;
2200 codeEditorFormFileDialog.currentDirectory = tempString;
2203 void ChangeProjectFileDialogDirectory(char * directory)
2205 ideSettings.ideProjectFileDialogLocation = directory;
2206 settingsContainer.Save();
2209 Window FindWindow(const char * filePath)
2211 Window document = null;
2213 // TOCHECK: Do we need to change slashes here?
2214 for(document = firstChild; document; document = document.next)
2216 const char * fileName = document.fileName;
2217 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2219 document.visible = true;
2220 document.Activate();
2227 bool DontTerminateDebugSession(const char * title)
2229 if(debugger.isActive)
2231 if(MessageBox { type = yesNo, master = ide,
2232 contents = $"Do you want to terminate the debugging session in progress?",
2233 text = title }.Modal() == no)
2236 MessageBox msg { type = yesNo, master = ide,
2237 contents = "Do you want to terminate the debugging session in progress?",
2239 if(msg.Modal() == no)
2251 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2253 char extension[MAX_EXTENSION] = "";
2254 Window document = null;
2255 bool isProject = false;
2256 bool needFileModified = true;
2257 char winFilePath[MAX_LOCATION];
2258 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2259 Window currentDoc = activeClient;
2260 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2263 GetExtension(filePath, extension);
2267 strcpy(extension, type);
2269 if(strcmp(extension, ProjectExtension))
2271 for(document = firstChild; document; document = document.next)
2273 const char * fileName = document.fileName;
2274 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2276 document.visible = true;
2278 document.Activate();
2284 if(createIfFails == whatever)
2286 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2288 needFileModified = false;
2289 if(openMethod == normal)
2291 if(DontTerminateDebugSession($"Open Project"))
2300 Workspace workspace = null;
2302 if(FileExists(filePath))
2304 if(!strcmp(extension, ProjectExtension))
2306 char workspaceFile[MAX_LOCATION];
2307 strcpy(workspaceFile, filePath);
2308 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2309 workspace = LoadWorkspace(workspaceFile, filePath);
2311 else if(!strcmp(extension, WorkspaceExtension))
2312 workspace = LoadWorkspace(filePath, null);
2319 CreateProjectView(workspace, filePath);
2320 document = projectView;
2322 toolBox.visible = true;
2323 sheet.visible = true;
2324 projectView.MakeActive();
2326 workspace.ParseLoadedBreakpoints();
2327 workspace.DropInvalidBreakpoints(null);
2330 ide.projectView.ShowOutputBuildLog(true);
2332 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
2333 ide.projectView.DisplayCompiler(compiler, false);
2336 UpdateCompilerConfigs(false);
2339 char newWorkingDir[MAX_LOCATION];
2340 StripLastDirectory(filePath, newWorkingDir);
2341 ChangeFileDialogsDirectory(newWorkingDir, false);
2344 document.fileName = filePath;
2346 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2348 // this crashes on starting ide with epj file, solution please?
2349 // app.UpdateDisplay();
2351 workspace.OpenPreviouslyOpenedFiles(noParsing);
2352 workspace.holdTracking = true;
2353 ide.RepositionWindows(false);
2354 workspace.holdTracking = false;
2356 workspace.timer.Start();
2358 #if !defined(__WIN32__)
2359 // Valgrind Debug menu updates
2360 debugUseValgrindItem.checked = workspace.useValgrind;
2362 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2363 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2364 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2365 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2367 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2368 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2369 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2370 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2371 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2372 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2373 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2374 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2376 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2379 findInFilesDialog.mode = FindInFilesMode::project;
2380 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2383 char location[MAX_LOCATION];
2384 StripLastDirectory(ide.project.topNode.path, location);
2385 ChangeProjectFileDialogDirectory(location);
2392 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2394 ideProjectFileDialog.text = openProjectFileDialogTitle;
2395 if(ideProjectFileDialog.Modal() == cancel)
2397 filePath = ideProjectFileDialog.filePath;
2398 GetExtension(filePath, extension);
2409 else if(openMethod == add)
2414 char slashFilePath[MAX_LOCATION];
2415 GetSlashPathBuffer(slashFilePath, filePath);
2416 for(p : workspace.projects)
2418 if(!fstrcmp(p.filePath, slashFilePath))
2426 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2427 contents = $"This project is already present in workspace." }.Modal();
2431 prj = LoadProject(filePath, null);
2434 const char * activeConfigName = null;
2435 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
2436 prj.StartMonitoring();
2437 workspace.AddProject(prj, null);
2438 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2439 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2440 activeConfigName = toolBar.activeConfig.currentRow.string;
2441 if(activeConfigName)
2443 for(cfg : prj.configurations)
2445 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2453 projectView.AddNode(prj.topNode, null);
2454 workspace.modified = true;
2456 findInFilesDialog.AddProjectItem(prj);
2457 projectView.ShowOutputBuildLog(true);
2458 projectView.DisplayCompiler(compiler, false);
2459 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2463 char location[MAX_LOCATION];
2464 StripLastDirectory(prj.topNode.path, location);
2465 ChangeProjectFileDialogDirectory(location);
2468 // projectView is associated with the main project and not with the one just added but
2469 return projectView; // just to let the caller know something was opened
2477 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2478 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2479 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2481 if(FileExists(filePath))
2482 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2483 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2484 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2487 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2490 else if(!strcmp(extension, "3ds"))
2492 if(FileExists(filePath))
2493 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2494 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2495 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2499 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2502 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2503 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2504 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2505 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2506 !strcmp(extension, "js"))
2508 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2509 editor.updatingCode = true;
2510 if(editor.LoadFile(filePath))
2513 editor.visible = true;
2517 needFileModified = false;
2521 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2522 if(editor.LoadFile(filePath))
2525 editor.visible = true;
2529 needFileModified = false;
2532 if(document && (document._class == class(PictureEdit) ||
2533 document._class == class(ModelView)))
2538 document.fileName = filePath;
2539 if(workspace && !workspace.holdTracking)
2540 workspace.UpdateOpenedFileInfo(filePath, opened);
2544 if(!document && createIfFails != no)
2546 if(createIfFails != yes && !needFileModified &&
2547 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2548 createIfFails = yes;
2549 if(createIfFails == yes || createIfFails == whatever)
2551 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2553 document.fileName = filePath;
2559 if(projectView && document._class == class(CodeEditor) && workspace)
2560 workspace.RestorePreviouslyOpenedFileState((CodeEditor)document);
2562 if(needFileModified)
2563 document.OnFileModified = OnFileModified;
2564 document.NotifySaved = DocumentSaved;
2565 if(maximizeDoc && document.hasMaximize)
2566 document.state = maximized;
2569 ideSettings.AddRecentProject(document.fileName);
2571 ideSettings.AddRecentFile(document.fileName);
2572 ide.UpdateRecentMenus();
2573 ide.AdjustFileMenus();
2574 settingsContainer.Save();
2582 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2583 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2585 if(!parentClosing && ide.workspace)
2586 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2589 bool ModelView::ModelViewOnClose(bool parentClosing)
2591 if(!parentClosing && ide.workspace)
2592 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2595 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2597 if(!parentClosing && ide.workspace)
2598 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2603 void OnUnloadGraphics(Window window)
2605 display.ClearMaterials();
2606 display.ClearTextures();
2607 display.ClearMeshes();
2611 void UpdateStateLight(StatusField fld, bool on)
2613 fld.color = on ? lime : Color { 128,128,128 };
2614 fld.backColor = on ? dimGray : 0;
2618 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2620 UpdateStateLight(caps, app.GetKeyState(capsState));
2621 UpdateStateLight(num, app.GetKeyState(numState));
2625 bool OnKeyDown(Key key, unichar ch)
2629 case b: projectView.Update(null); break;
2630 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2631 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2636 bool OnKeyUp(Key key, unichar ch)
2640 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2641 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2646 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2649 projectView.GoToError(line, noParsing, objectFileExt);
2652 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2654 FileAttribs result { };
2655 FileAttribs fileAttribs;
2659 strcpy(selectedPath, prj.topNode.path);
2660 else if(dir && dir[0])
2661 strcpy(selectedPath, dir);
2663 selectedPath[0] = '\0';
2664 PathCat(selectedPath, filePath);
2666 if((fileAttribs = FileExists(selectedPath)).isFile)
2667 result = fileAttribs;
2671 for(p : workspace.projects)
2673 strcpy(selectedPath, p.topNode.path);
2674 PathCat(selectedPath, filePath);
2675 if((fileAttribs = FileExists(selectedPath)).isFile)
2678 result = fileAttribs;
2685 ProjectNode n = null;
2686 for(p : workspace.projects)
2688 if((n = p.topNode.Find(filePath, false)))
2690 n.GetFullFilePath(selectedPath, true);
2691 if((fileAttribs = FileExists(selectedPath)).isFile)
2694 result = fileAttribs;
2699 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2700 (fileAttribs = FileExists(selectedPath)).isFile)
2703 result = fileAttribs;
2711 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2714 const char *path = text;
2715 char *colon = strchr(text, ':');
2716 char filePath[MAX_LOCATION] = "";
2717 char completePath[MAX_LOCATION];
2718 int line = 0, col = 0;
2719 int len = strlen(text);
2721 FileAttribs fileAttribs;
2723 // support for valgrind output
2724 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2735 /*for(s=colon; *s; s++)
2744 //line = atoi(colon+1);
2746 // support for "Found n match(es) in "file/path";
2747 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)
2753 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2755 path = (colon - 1 > path) ? colon - 1 : path;
2756 colon = strstr(colon + 1, ":");
2758 if(*path == '*' && (s = strchr(path+1, '*')))
2760 while(isspace(*path)) path++;
2764 char * close = strchr(path, ')');
2768 strncpy(name, path+1, close - path - 1);
2769 name[close - path - 1] = '\0';
2770 for(p : ide.workspace.projects)
2772 if(!strcmp(p.name, name))
2782 prj = project ? project : (dir ? null : ide.project);
2785 strncpy(filePath, path, colon - path);
2786 filePath[colon - path] = '\0';
2787 line = atoi(colon + 1);
2788 colon = strstr(colon + 1, ":");
2790 col = atoi(colon + 1);
2792 else if(path - 1 >= text && *(path - 1) == '\"')
2794 colon = strchr(path, '\"');
2797 strncpy(filePath, path, colon - path);
2798 filePath[colon - path] = '\0';
2801 else if(path && !colon)
2803 strcpy(filePath, path);
2806 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2807 CodeLocationGoTo(completePath, fileAttribs, line, col);
2810 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2812 if(fileAttribs.isFile)
2814 char ext[MAX_EXTENSION];
2815 GetExtension(path, ext);
2817 if(binaryDocExt.Find(ext))
2819 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2820 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2822 char dirPath[MAX_LOCATION];
2823 StripLastDirectory(path, dirPath);
2828 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2829 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2831 EditBox editBox = codeEditor.editBox;
2832 editBox.GoToLineNum(line - 1);
2833 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2837 else if(fileAttribs.isDirectory)
2841 void OnRedraw(Surface surface)
2843 Bitmap bitmap = back.bitmap;
2845 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2848 void SheetSelected(SheetType sheetSelected)
2850 if(activeChild == sheet)
2852 if(sheetSelected == methods)
2854 viewPropertiesItem.accelerator = f4;
2855 viewPropertiesItem.parent = viewMenu;
2856 viewMethodsItem.parent = null;
2860 viewMethodsItem.accelerator = f4;
2861 viewMethodsItem.parent = viewMenu;
2862 viewPropertiesItem.parent = null;
2867 viewMethodsItem.parent = viewMenu;
2868 viewPropertiesItem.parent = viewMenu;
2869 if(sheetSelected == methods)
2871 viewMethodsItem.accelerator = f4;
2872 viewPropertiesItem.accelerator = 0;
2876 viewMethodsItem.accelerator = 0;
2877 viewPropertiesItem.accelerator = f4;
2882 void OnActivateClient(Window client, Window previous)
2884 //if(!client || client != previous)
2887 if(!client || client != previous)
2890 dataType = previous._class;
2891 if(previous && !strcmp(dataType.name, "CodeEditor"))
2893 ((CodeEditor)previous).UpdateFormCode();
2895 else if(previous && !strcmp(dataType.name, "Designer"))
2897 ((Designer)previous).codeEditor.UpdateFormCode();
2902 dataType = client._class;
2903 if(client && !strcmp(dataType.name, "CodeEditor"))
2905 CodeEditor codeEditor = (CodeEditor)client;
2906 SetPrivateModule(codeEditor.privateModule);
2907 SetCurrentContext(codeEditor.globalContext);
2908 SetTopContext(codeEditor.globalContext);
2909 SetGlobalContext(codeEditor.globalContext);
2911 SetDefines(&codeEditor.defines);
2912 SetImports(&codeEditor.imports);
2914 SetActiveDesigner(codeEditor.designer);
2916 sheet.codeEditor = codeEditor;
2917 toolBox.codeEditor = codeEditor;
2919 viewDesignerItem.parent = viewMenu;
2920 if(activeChild != codeEditor)
2922 viewCodeItem.parent = viewMenu;
2923 viewDesignerItem.accelerator = 0;
2924 viewCodeItem.accelerator = f8;
2928 viewCodeItem.parent = null;
2929 viewDesignerItem.accelerator = f8;
2932 else if(client && !strcmp(dataType.name, "Designer"))
2934 CodeEditor codeEditor = ((Designer)client).codeEditor;
2937 SetPrivateModule(codeEditor.privateModule);
2938 SetCurrentContext(codeEditor.globalContext);
2939 SetTopContext(codeEditor.globalContext);
2940 SetGlobalContext(codeEditor.globalContext);
2941 SetDefines(&codeEditor.defines);
2942 SetImports(&codeEditor.imports);
2946 SetPrivateModule(null);
2947 SetCurrentContext(null);
2948 SetTopContext(null);
2949 SetGlobalContext(null);
2954 SetActiveDesigner((Designer)client);
2956 sheet.codeEditor = codeEditor;
2957 toolBox.codeEditor = codeEditor;
2959 viewCodeItem.parent = viewMenu;
2960 if(activeChild != client)
2962 viewDesignerItem.parent = viewMenu;
2963 viewDesignerItem.accelerator = f8;
2964 viewCodeItem.accelerator = 0;
2968 viewDesignerItem.parent = null;
2969 viewCodeItem.accelerator = f8;
2974 if(!client && !projectView && sheet.visible)
2977 sheet.visible = false;
2978 toolBox.visible = false;
2981 sheet.codeEditor = null;
2982 toolBox.codeEditor = null;
2983 SetActiveDesigner(null);
2985 viewDesignerItem.parent = null;
2986 viewCodeItem.parent = null;
2989 SheetSelected(sheet.sheetSelected);
2992 projectCompileItem = null;
2997 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
2999 CodeEditor codeEditor = (CodeEditor)client;
3000 EditBox editBox = codeEditor.editBox;
3002 statusBar.AddField(pos);
3004 caps = { width = 40, text = $"CAPS" };
3005 statusBar.AddField(caps);
3006 UpdateStateLight(caps, app.GetKeyState(capsState));
3008 ovr = { width = 36, text = $"OVR" };
3009 statusBar.AddField(ovr);
3010 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3012 num = { width = 36, text = $"NUM" };
3013 statusBar.AddField(num);
3014 UpdateStateLight(num, app.GetKeyState(numState));
3016 //statusBar.text = "Ready";
3018 if(projectView && projectView.project)
3020 bool isCObject = false;
3021 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3022 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3026 char nodeName[MAX_FILENAME];
3027 char name[MAX_FILENAME+96];
3029 ChangeExtension(node.name, "c", nodeName);
3030 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3031 projectCompileItem =
3033 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3035 bool NotifySelect(MenuItem selection, Modifiers mods)
3039 bool isCObject = false;
3040 bool isExcluded = false;
3041 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3045 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3048 List<ProjectNode> nodes { };
3050 projectView.Compile(node.project, nodes, normal, isCObject ? cObject : normal);
3058 projectMenu.AddDynamic(projectCompileItem, ide, false);
3064 caps = ovr = num = null;
3069 bool OnClose(bool parentClosing)
3071 //return !projectView.buildInProgress;
3072 if(projectView && projectView.buildInProgress)
3074 if(DontTerminateDebugSession($"Close IDE"))
3076 if(findInFilesDialog)
3077 findInFilesDialog.SearchStop();
3080 workspace.timer.Stop();
3083 ideMainFrame.Destroy(0);
3090 bool passThrough = false;
3091 bool debugWorkDir = false;
3092 char * passDebugWorkDir = null;
3093 bool openAsText = false;
3094 DynamicString passArgs { };
3097 for(c = 1; c<app.argc; c++)
3101 const char * arg = app.argv[c];
3102 char * buf = new char[strlen(arg)*2+1];
3104 passArgs.concat(" ");
3106 passArgs.concat(buf);
3109 else if(debugWorkDir)
3111 passDebugWorkDir = CopyString(app.argv[c]);
3112 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3113 debugWorkDir = false;
3115 else if(!strcmp(app.argv[c], "-t"))
3117 else if(!strcmp(app.argv[c], "-no-parsing"))
3118 ide.noParsing = true;
3119 else if(!strcmp(app.argv[c], "-debug-start"))
3120 ide.debugStart = true;
3121 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3122 debugWorkDir = true;
3123 else if(!strcmp(app.argv[c], "-@"))
3127 char fullPath[MAX_LOCATION];
3128 char parentPath[MAX_LOCATION];
3129 char ext[MAX_EXTENSION];
3131 FileAttribs dirAttribs;
3132 GetWorkingDir(fullPath, MAX_LOCATION);
3133 PathCat(fullPath, app.argv[c]);
3134 StripLastDirectory(fullPath, parentPath);
3135 GetExtension(app.argv[c], ext);
3136 isProject = !openAsText && !strcmpi(ext, "epj");
3138 if(isProject && c > 1 + (ide.debugStart ? 1 : 0)) continue;
3140 // Create directory for projects (only)
3141 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3143 if(isProject && !FileExists(fullPath))
3145 char name[MAX_LOCATION];
3146 NewProjectDialog newProjectDialog;
3150 projectView.visible = false;
3151 if(!projectView.Destroy(0))
3155 newProjectDialog = { master = this };
3157 strcpy(name, app.argv[c]);
3158 StripExtension(name);
3159 GetLastDirectory(name, name);
3160 newProjectDialog.projectName.contents = name;
3161 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3162 newProjectDialog.locationEditBox.path = parentPath;
3163 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3165 incref newProjectDialog;
3166 newProjectDialog.Modal();
3169 ideSettings.AddRecentProject(projectView.fileName);
3170 ide.UpdateRecentMenus();
3171 settingsContainer.Save();
3173 delete newProjectDialog;
3174 // Open only one project
3178 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3180 else if(strstr(fullPath, "http://") == fullPath)
3181 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3184 if(passThrough && projectView && projectView.project && workspace)
3185 workspace.commandLineArgs = passArgs;
3186 if(passDebugWorkDir && projectView && projectView.project && workspace)
3188 workspace.debugDir = passDebugWorkDir;
3189 delete passDebugWorkDir;
3192 UpdateToolBarActiveConfigs(false);
3193 UpdateToolBarActiveCompilers();
3200 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3203 projectView.visible = false;
3204 projectView.Destroy(0);
3207 #ifdef GDB_DEBUG_GUI
3208 gdbDialog.Destroy(0);
3213 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3217 char * oldPaths[128];
3218 String oldList = new char[maxPathLen];
3219 Array<String> newExePaths { };
3220 //Map<String, bool> exePathExists { };
3222 #if defined(__unix__) || defined(__APPLE__)
3223 Array<String> newLibPaths { };
3224 Map<String, bool> libPathExists { };
3229 for(prj : workspace.projects)
3231 DirExpression targetDirExp;
3233 // SKIP FIRST PROJECT...
3234 if(prj == workspace.projects.firstIterator.data) continue;
3236 // NOTE: Right now the additional project config dir will be
3237 // obtained when the debugger is started, so toggling it
3238 // while building will change which library gets used.
3239 // To go with the initial state, e.g. when F5 was pressed,
3240 // we nould need to keep a list of all project's active
3241 // config upon startup.
3242 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3244 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3248 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3249 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3253 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3254 if(cfg.targetType == sharedLibrary && cfg.debug)
3258 if(targetDirExp.dir)
3260 char buffer[MAX_LOCATION];
3261 #if defined(__WIN32__)
3262 Array<String> paths = newExePaths;
3264 Array<String> paths = newLibPaths;
3266 GetSystemPathBuffer(buffer, prj.topNode.path);
3267 PathCat(buffer, targetDirExp.dir);
3270 if(!fstrcmp(p, buffer))
3277 paths.Add(CopyString(buffer));
3279 delete targetDirExp;
3283 for(item : compiler.executableDirs)
3285 DirExpression dirExpr { };
3286 dirExpr.Evaluate(item, null, compiler, null, 0);
3289 for(p : newExePaths)
3291 if(!fstrcmp(p, dirExpr.dir))
3298 newExePaths.Add(CopySystemPath(dirExpr.dir));
3302 GetEnvironment("PATH", oldList, maxPathLen);
3304 printf("Old value of PATH: %s\n", oldList);
3306 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3307 for(c = 0; c < count; c++)
3310 for(p : newExePaths)
3312 if(!fstrcmp(p, oldPaths[c]))
3319 newExePaths.Add(CopySystemPath(oldPaths[c]));
3323 for(path : newExePaths)
3324 len += strlen(path) + 1;
3325 newList = new char[len + 1];
3327 for(path : newExePaths)
3329 strcat(newList, path);
3330 strcat(newList, pathListSep);
3332 newList[len - 1] = '\0';
3333 SetEnvironment("PATH", newList);
3335 printf("New value of PATH: %s\n", newList);
3342 #if defined(__unix__) || defined(__APPLE__)
3344 for(item : compiler.libraryDirs)
3346 if(!libPathExists[item]) // fstrcmp should be used
3348 String s = CopyString(item);
3350 libPathExists[s] = true;
3354 #if defined(__APPLE__)
3355 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3357 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3360 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3362 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3363 for(c = 0; c < count; c++)
3365 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3367 String s = CopyString(oldPaths[c]);
3369 libPathExists[s] = true;
3374 for(path : newLibPaths)
3375 len += strlen(path) + 1;
3376 newList = new char[len + 1];
3378 for(path : newLibPaths)
3380 strcat(newList, path);
3381 strcat(newList, pathListSep);
3383 newList[len - 1] = '\0';
3384 #if defined(__APPLE__)
3385 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3387 SetEnvironment("LD_LIBRARY_PATH", newList);
3390 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3396 delete libPathExists;
3399 if(compiler.distccEnabled && compiler.distccHosts)
3400 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3405 void DestroyTemporaryProjectDir()
3407 if(tmpPrjDir && tmpPrjDir[0])
3409 if(FileExists(tmpPrjDir).isDirectory)
3410 DestroyDir(tmpPrjDir);
3411 property::tmpPrjDir = null;
3417 // Graphics Driver Menu
3420 app.currentSkin.selectionColor = selectionColor;
3421 app.currentSkin.selectionText = selectionText;
3425 driverItems = new MenuItem[app.numDrivers];
3426 for(c = 0; c < app.numDrivers; c++)
3428 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3429 driverItems[c].id = c;
3430 driverItems[c].isRadio = true;
3433 driverItems = new MenuItem[2];
3434 #if defined(__unix__)
3435 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3436 driverItems[0].id = 0;
3437 driverItems[0].isRadio = true;
3439 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3440 driverItems[0].id = 0;
3441 driverItems[0].isRadio = true;
3443 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3444 driverItems[1].id = 1;
3445 driverItems[1].isRadio = true;
3447 /* skinItems = new MenuItem[app.numSkins];
3448 for(c = 0; c < app.numSkins; c++)
3450 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3451 skinItems[c].id = c;
3452 skinItems[c].isRadio = true;
3455 ideFileDialog.master = this;
3456 ideProjectFileDialog.master = this;
3458 //SetDriverAndSkin();
3462 void UpdateRecentMenus()
3465 Menu fileMenu = menu.FindMenu($"File");
3466 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3467 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3468 char * itemPath = new char[MAX_LOCATION];
3469 char * itemName = new char[MAX_LOCATION+4];
3471 recentFiles.Clear();
3474 for(recent : ideSettings.recentFiles)
3476 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3477 MakeSystemPath(itemPath);
3478 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3479 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3483 recentProjects.Clear();
3485 for(recent : ideSettings.recentProjects)
3487 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3488 MakeSystemPath(itemPath);
3489 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3490 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3502 delete languageItems;
3506 documentor.Puts("Quit\n");
3513 void DestroyDir(char * path)
3515 RecursiveDeleteFolderFSI fsi { };
3520 #if defined(__WIN32__)
3521 define sdkDirName = "Ecere SDK";
3523 define sdkDirName = "ecere";
3526 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3529 char * v = new char[maxPathLen];
3533 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3534 StripLastDirectory(path, path);
3535 PathCat(path, subDir);
3536 if(name) PathCat(path, name);
3537 if(FileExists(path) & attribs) found = true;
3539 #if defined(__WIN32__)
3542 for(s : [ "ECERE_SDK_SRC", "AppData", "ALLUSERSPROFILE", "USERPROFILE", "HOMEPATH", "ProgramData", "ProgramFiles", "ProgramFiles(x86)", "SystemDrive" ])
3544 GetEnvironment(s, v, maxPathLen);
3547 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3548 if(!strcmp(s, "SystemDrive"))
3549 PathCat(path, "Program Files");
3550 if(strcmp(s, "ECERE_SDK_SRC"))
3551 PathCat(path, sdkDirName);
3552 PathCat(path, subDir);
3553 if(name) PathCat(path, name);
3554 if(FileExists(path) & attribs)
3569 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3570 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3573 p = new char[MAX_LOCATION];
3575 strcat(p, "/usr/share");
3579 for(c=0; c<numTokens; c++)
3581 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3582 PathCat(path, sdkDirName);
3583 PathCat(path, subDir);
3585 PathCat(path, name);
3586 if(FileExists(path) & attribs)
3599 void FindAndShellOpenInstalledFolder(const char * name)
3601 char path[MAX_LOCATION];
3602 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3606 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3608 char path[MAX_LOCATION];
3609 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3613 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3615 bool preserveRootFolder;
3617 void OutFolder(const char * folderPath, bool isRoot)
3619 if(!(preserveRootFolder && isRoot))
3620 RemoveDir(folderPath);
3623 bool OnFile(const char * filePath)
3625 DeleteFile(filePath);
3630 class IDEApp : GuiApplication
3632 //driver = "Win32Console";
3633 // driver = "OpenGL";
3637 TempFile includeFile { };
3642 char ext[MAX_EXTENSION];
3643 SetLoggingMode(stdOut, null);
3644 //SetLoggingMode(debug, null);
3646 settingsContainer.Load();
3648 if(ideSettings.language)
3650 const String language = GetLanguageString();
3651 if(ideSettings.language.OnCompare(language))
3653 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3658 // First count files arg to decide whether to maximize
3660 bool passThrough = false, debugWorkDir = false;
3663 for(c = 1; c<app.argc; c++)
3666 else if(debugWorkDir)
3667 debugWorkDir = false;
3668 else if(!strcmp(app.argv[c], "-t"));
3669 else if(!strcmp(app.argv[c], "-no-parsing"));
3670 else if(!strcmp(app.argv[c], "-debug-start"));
3671 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3672 debugWorkDir = true;
3673 else if(!strcmp(app.argv[c], "-@"))
3680 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3682 app.driver = "OpenGL";
3683 ide.driverItems[1].checked = true;
3687 #if defined(__unix__) || defined(__APPLE__)
3688 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3690 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3692 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3696 char model[MAX_LOCATION];
3697 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3699 ide.duck.modelFile = model;
3700 ide.duck.parent = ideMainFrame;
3703 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3704 ide.debugRubberDuck.disabled = false;
3708 desktop.caption = titleECEREIDE;
3711 for(c = 1; c<app.argc; c++)
3713 char fullPath[MAX_LOCATION];
3714 GetWorkingDir(fullPath, MAX_LOCATION);
3715 PathCat(fullPath, app.argv[c]);
3716 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3720 // Default to language specified by environment if no language selected
3721 if(!ideSettings.language)
3723 ideSettings.language = GetLanguageString();
3724 settingsContainer.Save();
3727 // Default to home directory if no directory yet set up
3728 if(!ideSettings.ideProjectFileDialogLocation[0])
3731 char location[MAX_LOCATION];
3732 char * home = getenv("HOME");
3733 char * homeDrive = getenv("HOMEDRIVE");
3734 char * homePath = getenv("HOMEPATH");
3735 char * userProfile = getenv("USERPROFILE");
3736 char * systemDrive = getenv("SystemDrive");
3737 if(home && FileExists(home).isDirectory)
3739 strcpy(location, home);
3742 if(!found && homeDrive && homePath)
3744 strcpy(location, homeDrive);
3745 PathCat(location, homePath);
3746 if(FileExists(location).isDirectory)
3749 if(!found && FileExists(userProfile).isDirectory)
3751 strcpy(location, userProfile);
3754 if(!found && FileExists(systemDrive).isDirectory)
3756 strcpy(location, systemDrive);
3761 ideSettings.ideProjectFileDialogLocation = location;
3762 if(!ideSettings.ideFileDialogLocation[0])
3763 ideSettings.ideFileDialogLocation = location;
3767 if(!LoadIncludeFile())
3768 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3770 // Create language menu
3772 String language = ideSettings.language;
3776 ide.languageItems = new MenuItem[languages.count];
3779 ide.languageItems[i] =
3781 ide.languageMenu, l.name;
3782 bitmap = { l.bitmap };
3786 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3788 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3790 // Re-select previous selected language if aborted
3791 String language = ideSettings.language;
3795 if(((!language || !language[0]) && i == 0) ||
3796 (language && !strcmpi(l.code, language)))
3798 ide.languageItems[i].checked = true;
3810 // Try to find country-specific language first
3816 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3818 ide.languageItems[i].checked = true;
3826 // Try generalizing locale
3827 if(!found && language)
3830 char genericLocale[256];
3832 strncpy(genericLocale, language, sizeof(genericLocale));
3833 genericLocale[sizeof(genericLocale)-1] = 0;
3835 under = strchr(genericLocale, '_');
3838 if(!strcmpi(genericLocale, "zh"))
3839 strcpy(genericLocale, "zh_CN");
3840 if(strcmp(genericLocale, language))
3844 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3846 ide.languageItems[i].checked = true;
3856 ide.languageItems[0].checked = true;
3858 MenuDivider { ide.languageMenu };
3861 ide.languageMenu, "Help Translate";
3863 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3865 ShellOpen("http://translations.launchpad.net/ecere");
3871 ideMainFrame.Create();
3872 if(app.argFilesCount > 1)
3873 ide.MenuWindowTileVert(null, 0);
3877 bool Cycle(bool idle)
3881 if(ide.documentor.Peek())
3884 ide.documentor.GetLine(line, sizeof(line));
3885 if(!strcmpi(line, "Exited"))
3887 ide.documentor.CloseInput();
3888 ide.documentor.CloseOutput();
3889 ide.documentor.Wait();
3890 delete ide.documentor;
3893 if(ide.documentor && ide.documentor.eof)
3895 ide.documentor.CloseInput();
3896 ide.documentor.CloseOutput();
3897 ide.documentor.Wait();
3898 delete ide.documentor;
3904 bool LoadIncludeFile()
3906 bool result = false;
3907 File include = FileOpen(":crossplatform.mk", read);
3910 File f = includeFile;
3913 for(; !include.Eof(); )
3916 int count = include.Read(buffer, 1, 4096);
3917 f.Write(buffer, 1, count);
3927 IDEMainFrame ideMainFrame { };
3929 define app = ((IDEApp)__thisModule);
3931 define titleECEREIDE = $"Ecere IDE (Debug)";
3933 define titleECEREIDE = $"Ecere IDE";