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.compiler))
308 bool silent = ide.projectView.buildInProgress == none ? false : true;
309 CompilerConfig compiler = ideSettings.GetCompilerConfig(row.string);
310 ide.workspace.compiler = 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.compiler);
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.compiler) : 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.compiler) : 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.compiler)
729 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.compiler;
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"));
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)
789 char * command = PrintString("ecere-ide ", file);
794 OpenFile(file, false, true, 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.compiler);
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.compiler);
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.compiler && !strcmp(compiler.name, workspace.compiler))
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.compiler);
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.holdTracking = true;
2352 for(ofi : workspace.openedFiles)
2354 if(ofi.state != closed)
2356 Window file = OpenFile(ofi.path, false, true, null, no, normal, noParsing);
2359 char fileName[MAX_LOCATION];
2361 GetLastDirectory(ofi.path, fileName);
2362 node = projectView.project.topNode.Find(fileName, true);
2364 node.EnsureVisible();
2368 ide.RepositionWindows(false);
2369 workspace.holdTracking = false;
2371 workspace.timer.Start();
2373 #if !defined(__WIN32__)
2374 // Valgrind Debug menu updates
2375 debugUseValgrindItem.checked = workspace.useValgrind;
2377 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2378 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2379 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2380 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2382 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2383 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2384 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2385 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2386 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2387 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2388 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2389 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2391 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2394 findInFilesDialog.mode = FindInFilesMode::project;
2395 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2398 char location[MAX_LOCATION];
2399 StripLastDirectory(ide.project.topNode.path, location);
2400 ChangeProjectFileDialogDirectory(location);
2407 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2409 ideProjectFileDialog.text = openProjectFileDialogTitle;
2410 if(ideProjectFileDialog.Modal() == cancel)
2412 filePath = ideProjectFileDialog.filePath;
2413 GetExtension(filePath, extension);
2424 else if(openMethod == add)
2429 char slashFilePath[MAX_LOCATION];
2430 GetSlashPathBuffer(slashFilePath, filePath);
2431 for(p : workspace.projects)
2433 if(!fstrcmp(p.filePath, slashFilePath))
2441 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2442 contents = $"This project is already present in workspace." }.Modal();
2446 prj = LoadProject(filePath, null);
2449 const char * activeConfigName = null;
2450 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2451 prj.StartMonitoring();
2452 workspace.projects.Add(prj);
2453 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2454 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2455 activeConfigName = toolBar.activeConfig.currentRow.string;
2456 if(activeConfigName)
2458 for(cfg : prj.configurations)
2460 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2468 projectView.AddNode(prj.topNode, null);
2469 workspace.modified = true;
2471 findInFilesDialog.AddProjectItem(prj);
2472 projectView.ShowOutputBuildLog(true);
2473 projectView.DisplayCompiler(compiler, false);
2474 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2478 char location[MAX_LOCATION];
2479 StripLastDirectory(prj.topNode.path, location);
2480 ChangeProjectFileDialogDirectory(location);
2483 // projectView is associated with the main project and not with the one just added but
2484 return projectView; // just to let the caller know something was opened
2492 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2493 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2494 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2496 if(FileExists(filePath))
2497 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2498 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2499 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2502 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2505 else if(!strcmp(extension, "3ds"))
2507 if(FileExists(filePath))
2508 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2509 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2510 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2514 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2517 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2518 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2519 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2520 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2521 !strcmp(extension, "js"))
2523 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2524 editor.updatingCode = true;
2525 if(editor.LoadFile(filePath))
2528 editor.visible = true;
2532 needFileModified = false;
2536 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2537 if(editor.LoadFile(filePath))
2540 editor.visible = true;
2544 needFileModified = false;
2547 if(document && (document._class == class(PictureEdit) ||
2548 document._class == class(ModelView)))
2553 document.fileName = filePath;
2554 if(workspace && !workspace.holdTracking)
2555 workspace.UpdateOpenedFileInfo(filePath, opened);
2559 if(!document && createIfFails != no)
2561 if(createIfFails != yes && !needFileModified &&
2562 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2563 createIfFails = yes;
2564 if(createIfFails == yes || createIfFails == whatever)
2566 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2568 document.fileName = filePath;
2574 if(projectView && document._class == class(CodeEditor) && workspace)
2576 int lineNumber, position;
2578 CodeEditor editor = (CodeEditor)document;
2579 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2580 editor.openedFileInfo.holdTracking = true;
2581 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2582 position = Max(editor.openedFileInfo.position - 1, 0);
2583 if(editor.editBox.GoToLineNum(lineNumber))
2584 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2585 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2586 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2587 editor.editBox.scroll = scroll;
2588 editor.openedFileInfo.holdTracking = false;
2591 if(needFileModified)
2592 document.OnFileModified = OnFileModified;
2593 document.NotifySaved = DocumentSaved;
2594 if(maximizeDoc && document.hasMaximize)
2595 document.state = maximized;
2598 ideSettings.AddRecentProject(document.fileName);
2600 ideSettings.AddRecentFile(document.fileName);
2601 ide.UpdateRecentMenus();
2602 ide.AdjustFileMenus();
2603 settingsContainer.Save();
2611 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2612 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2614 if(!parentClosing && ide.workspace)
2615 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2618 bool ModelView::ModelViewOnClose(bool parentClosing)
2620 if(!parentClosing && ide.workspace)
2621 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2624 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2626 if(!parentClosing && ide.workspace)
2627 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2632 void OnUnloadGraphics(Window window)
2634 display.ClearMaterials();
2635 display.ClearTextures();
2636 display.ClearMeshes();
2640 void UpdateStateLight(StatusField fld, bool on)
2642 fld.color = on ? lime : Color { 128,128,128 };
2643 fld.backColor = on ? dimGray : 0;
2647 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2649 UpdateStateLight(caps, app.GetKeyState(capsState));
2650 UpdateStateLight(num, app.GetKeyState(numState));
2654 bool OnKeyDown(Key key, unichar ch)
2658 case b: projectView.Update(null); break;
2659 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2660 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2665 bool OnKeyUp(Key key, unichar ch)
2669 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2670 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2675 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2678 projectView.GoToError(line, noParsing, objectFileExt);
2681 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2683 FileAttribs result { };
2684 FileAttribs fileAttribs;
2688 strcpy(selectedPath, prj.topNode.path);
2689 else if(dir && dir[0])
2690 strcpy(selectedPath, dir);
2692 selectedPath[0] = '\0';
2693 PathCat(selectedPath, filePath);
2695 if((fileAttribs = FileExists(selectedPath)).isFile)
2696 result = fileAttribs;
2700 for(p : workspace.projects)
2702 strcpy(selectedPath, p.topNode.path);
2703 PathCat(selectedPath, filePath);
2704 if((fileAttribs = FileExists(selectedPath)).isFile)
2707 result = fileAttribs;
2714 ProjectNode n = null;
2715 for(p : workspace.projects)
2717 if((n = p.topNode.Find(filePath, false)))
2719 n.GetFullFilePath(selectedPath, true);
2720 if((fileAttribs = FileExists(selectedPath)).isFile)
2723 result = fileAttribs;
2728 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2729 (fileAttribs = FileExists(selectedPath)).isFile)
2732 result = fileAttribs;
2740 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2743 const char *path = text;
2744 char *colon = strchr(text, ':');
2745 char filePath[MAX_LOCATION] = "";
2746 char completePath[MAX_LOCATION];
2747 int line = 0, col = 0;
2748 int len = strlen(text);
2750 FileAttribs fileAttribs;
2752 // support for valgrind output
2753 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2764 /*for(s=colon; *s; s++)
2773 //line = atoi(colon+1);
2775 // support for "Found n match(es) in "file/path";
2776 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)
2782 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2784 path = (colon - 1 > path) ? colon - 1 : path;
2785 colon = strstr(colon + 1, ":");
2787 if(*path == '*' && (s = strchr(path+1, '*')))
2789 while(isspace(*path)) path++;
2793 char * close = strchr(path, ')');
2797 strncpy(name, path+1, close - path - 1);
2798 name[close - path - 1] = '\0';
2799 for(p : ide.workspace.projects)
2801 if(!strcmp(p.name, name))
2811 prj = project ? project : (dir ? null : ide.project);
2814 strncpy(filePath, path, colon - path);
2815 filePath[colon - path] = '\0';
2816 line = atoi(colon + 1);
2817 colon = strstr(colon + 1, ":");
2819 col = atoi(colon + 1);
2821 else if(path - 1 >= text && *(path - 1) == '\"')
2823 colon = strchr(path, '\"');
2826 strncpy(filePath, path, colon - path);
2827 filePath[colon - path] = '\0';
2830 else if(path && !colon)
2832 strcpy(filePath, path);
2835 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2836 CodeLocationGoTo(completePath, fileAttribs, line, col);
2839 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2841 if(fileAttribs.isFile)
2843 char ext[MAX_EXTENSION];
2844 GetExtension(path, ext);
2846 if(binaryDocExt.Find(ext))
2848 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2849 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2851 char dirPath[MAX_LOCATION];
2852 StripLastDirectory(path, dirPath);
2857 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2858 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2860 EditBox editBox = codeEditor.editBox;
2861 editBox.GoToLineNum(line - 1);
2862 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2866 else if(fileAttribs.isDirectory)
2870 void OnRedraw(Surface surface)
2872 Bitmap bitmap = back.bitmap;
2874 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2877 void SheetSelected(SheetType sheetSelected)
2879 if(activeChild == sheet)
2881 if(sheetSelected == methods)
2883 viewPropertiesItem.accelerator = f4;
2884 viewPropertiesItem.parent = viewMenu;
2885 viewMethodsItem.parent = null;
2889 viewMethodsItem.accelerator = f4;
2890 viewMethodsItem.parent = viewMenu;
2891 viewPropertiesItem.parent = null;
2896 viewMethodsItem.parent = viewMenu;
2897 viewPropertiesItem.parent = viewMenu;
2898 if(sheetSelected == methods)
2900 viewMethodsItem.accelerator = f4;
2901 viewPropertiesItem.accelerator = 0;
2905 viewMethodsItem.accelerator = 0;
2906 viewPropertiesItem.accelerator = f4;
2911 void OnActivateClient(Window client, Window previous)
2913 //if(!client || client != previous)
2916 if(!client || client != previous)
2919 dataType = previous._class;
2920 if(previous && !strcmp(dataType.name, "CodeEditor"))
2922 ((CodeEditor)previous).UpdateFormCode();
2924 else if(previous && !strcmp(dataType.name, "Designer"))
2926 ((Designer)previous).codeEditor.UpdateFormCode();
2931 dataType = client._class;
2932 if(client && !strcmp(dataType.name, "CodeEditor"))
2934 CodeEditor codeEditor = (CodeEditor)client;
2935 SetPrivateModule(codeEditor.privateModule);
2936 SetCurrentContext(codeEditor.globalContext);
2937 SetTopContext(codeEditor.globalContext);
2938 SetGlobalContext(codeEditor.globalContext);
2940 SetDefines(&codeEditor.defines);
2941 SetImports(&codeEditor.imports);
2943 SetActiveDesigner(codeEditor.designer);
2945 sheet.codeEditor = codeEditor;
2946 toolBox.codeEditor = codeEditor;
2948 viewDesignerItem.parent = viewMenu;
2949 if(activeChild != codeEditor)
2951 viewCodeItem.parent = viewMenu;
2952 viewDesignerItem.accelerator = 0;
2953 viewCodeItem.accelerator = f8;
2957 viewCodeItem.parent = null;
2958 viewDesignerItem.accelerator = f8;
2961 else if(client && !strcmp(dataType.name, "Designer"))
2963 CodeEditor codeEditor = ((Designer)client).codeEditor;
2966 SetPrivateModule(codeEditor.privateModule);
2967 SetCurrentContext(codeEditor.globalContext);
2968 SetTopContext(codeEditor.globalContext);
2969 SetGlobalContext(codeEditor.globalContext);
2970 SetDefines(&codeEditor.defines);
2971 SetImports(&codeEditor.imports);
2975 SetPrivateModule(null);
2976 SetCurrentContext(null);
2977 SetTopContext(null);
2978 SetGlobalContext(null);
2983 SetActiveDesigner((Designer)client);
2985 sheet.codeEditor = codeEditor;
2986 toolBox.codeEditor = codeEditor;
2988 viewCodeItem.parent = viewMenu;
2989 if(activeChild != client)
2991 viewDesignerItem.parent = viewMenu;
2992 viewDesignerItem.accelerator = f8;
2993 viewCodeItem.accelerator = 0;
2997 viewDesignerItem.parent = null;
2998 viewCodeItem.accelerator = f8;
3003 if(!client && !projectView && sheet.visible)
3006 sheet.visible = false;
3007 toolBox.visible = false;
3010 sheet.codeEditor = null;
3011 toolBox.codeEditor = null;
3012 SetActiveDesigner(null);
3014 viewDesignerItem.parent = null;
3015 viewCodeItem.parent = null;
3018 SheetSelected(sheet.sheetSelected);
3021 projectCompileItem = null;
3026 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3028 CodeEditor codeEditor = (CodeEditor)client;
3029 EditBox editBox = codeEditor.editBox;
3031 statusBar.AddField(pos);
3033 caps = { width = 40, text = $"CAPS" };
3034 statusBar.AddField(caps);
3035 UpdateStateLight(caps, app.GetKeyState(capsState));
3037 ovr = { width = 36, text = $"OVR" };
3038 statusBar.AddField(ovr);
3039 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3041 num = { width = 36, text = $"NUM" };
3042 statusBar.AddField(num);
3043 UpdateStateLight(num, app.GetKeyState(numState));
3045 //statusBar.text = "Ready";
3047 if(projectView && projectView.project)
3049 bool isCObject = false;
3050 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3051 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3055 char nodeName[MAX_FILENAME];
3056 char name[MAX_FILENAME+96];
3058 ChangeExtension(node.name, "c", nodeName);
3059 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3060 projectCompileItem =
3062 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3064 bool NotifySelect(MenuItem selection, Modifiers mods)
3068 bool isCObject = false;
3069 bool isExcluded = false;
3070 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3074 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3077 List<ProjectNode> nodes { };
3079 projectView.Compile(node.project, nodes, normal, isCObject ? cObject : normal);
3087 projectMenu.AddDynamic(projectCompileItem, ide, false);
3093 caps = ovr = num = null;
3098 bool OnClose(bool parentClosing)
3100 //return !projectView.buildInProgress;
3101 if(projectView && projectView.buildInProgress)
3103 if(DontTerminateDebugSession($"Close IDE"))
3105 if(findInFilesDialog)
3106 findInFilesDialog.SearchStop();
3109 workspace.timer.Stop();
3112 ideMainFrame.Destroy(0);
3119 bool passThrough = false;
3120 bool debugWorkDir = false;
3121 char * passDebugWorkDir = null;
3122 bool openAsText = false;
3123 DynamicString passArgs { };
3126 for(c = 1; c<app.argc; c++)
3130 const char * arg = app.argv[c];
3131 char * buf = new char[strlen(arg)*2+1];
3133 passArgs.concat(" ");
3135 passArgs.concat(buf);
3138 else if(debugWorkDir)
3140 passDebugWorkDir = CopyString(app.argv[c]);
3141 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3142 debugWorkDir = false;
3144 else if(!strcmp(app.argv[c], "-t"))
3146 else if(!strcmp(app.argv[c], "-no-parsing"))
3147 ide.noParsing = true;
3148 else if(!strcmp(app.argv[c], "-debug-start"))
3149 ide.debugStart = true;
3150 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3151 debugWorkDir = true;
3152 else if(!strcmp(app.argv[c], "-@"))
3156 char fullPath[MAX_LOCATION];
3157 char parentPath[MAX_LOCATION];
3158 char ext[MAX_EXTENSION];
3160 FileAttribs dirAttribs;
3161 GetWorkingDir(fullPath, MAX_LOCATION);
3162 PathCat(fullPath, app.argv[c]);
3163 StripLastDirectory(fullPath, parentPath);
3164 GetExtension(app.argv[c], ext);
3165 isProject = !openAsText && !strcmpi(ext, "epj");
3167 if(isProject && c > 1 + (ide.debugStart ? 1 : 0)) continue;
3169 // Create directory for projects (only)
3170 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3172 if(isProject && !FileExists(fullPath))
3174 char name[MAX_LOCATION];
3175 NewProjectDialog newProjectDialog;
3179 projectView.visible = false;
3180 if(!projectView.Destroy(0))
3184 newProjectDialog = { master = this };
3186 strcpy(name, app.argv[c]);
3187 StripExtension(name);
3188 GetLastDirectory(name, name);
3189 newProjectDialog.projectName.contents = name;
3190 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3191 newProjectDialog.locationEditBox.path = parentPath;
3192 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3194 incref newProjectDialog;
3195 newProjectDialog.Modal();
3198 ideSettings.AddRecentProject(projectView.fileName);
3199 ide.UpdateRecentMenus();
3200 settingsContainer.Save();
3202 delete newProjectDialog;
3203 // Open only one project
3207 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3209 else if(strstr(fullPath, "http://") == fullPath)
3210 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3213 if(passThrough && projectView && projectView.project && workspace)
3214 workspace.commandLineArgs = passArgs;
3215 if(passDebugWorkDir && projectView && projectView.project && workspace)
3217 workspace.debugDir = passDebugWorkDir;
3218 delete passDebugWorkDir;
3221 UpdateToolBarActiveConfigs(false);
3222 UpdateToolBarActiveCompilers();
3229 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3232 projectView.visible = false;
3233 projectView.Destroy(0);
3236 #ifdef GDB_DEBUG_GUI
3237 gdbDialog.Destroy(0);
3242 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3246 char * oldPaths[128];
3247 String oldList = new char[maxPathLen];
3248 Array<String> newExePaths { };
3249 //Map<String, bool> exePathExists { };
3251 #if defined(__unix__) || defined(__APPLE__)
3252 Array<String> newLibPaths { };
3253 Map<String, bool> libPathExists { };
3258 for(prj : workspace.projects)
3260 DirExpression targetDirExp;
3262 // SKIP FIRST PROJECT...
3263 if(prj == workspace.projects.firstIterator.data) continue;
3265 // NOTE: Right now the additional project config dir will be
3266 // obtained when the debugger is started, so toggling it
3267 // while building will change which library gets used.
3268 // To go with the initial state, e.g. when F5 was pressed,
3269 // we nould need to keep a list of all project's active
3270 // config upon startup.
3271 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3273 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3277 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3278 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3282 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3283 if(cfg.targetType == sharedLibrary && cfg.debug)
3287 if(targetDirExp.dir)
3289 char buffer[MAX_LOCATION];
3290 #if defined(__WIN32__)
3291 Array<String> paths = newExePaths;
3293 Array<String> paths = newLibPaths;
3295 GetSystemPathBuffer(buffer, prj.topNode.path);
3296 PathCat(buffer, targetDirExp.dir);
3299 if(!fstrcmp(p, buffer))
3306 paths.Add(CopyString(buffer));
3308 delete targetDirExp;
3312 for(item : compiler.executableDirs)
3314 DirExpression dirExpr { };
3315 dirExpr.Evaluate(item, null, compiler, null, 0);
3318 for(p : newExePaths)
3320 if(!fstrcmp(p, dirExpr.dir))
3327 newExePaths.Add(CopySystemPath(dirExpr.dir));
3331 GetEnvironment("PATH", oldList, maxPathLen);
3333 printf("Old value of PATH: %s\n", oldList);
3335 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3336 for(c = 0; c < count; c++)
3339 for(p : newExePaths)
3341 if(!fstrcmp(p, oldPaths[c]))
3348 newExePaths.Add(CopySystemPath(oldPaths[c]));
3352 for(path : newExePaths)
3353 len += strlen(path) + 1;
3354 newList = new char[len + 1];
3356 for(path : newExePaths)
3358 strcat(newList, path);
3359 strcat(newList, pathListSep);
3361 newList[len - 1] = '\0';
3362 SetEnvironment("PATH", newList);
3364 printf("New value of PATH: %s\n", newList);
3371 #if defined(__unix__) || defined(__APPLE__)
3373 for(item : compiler.libraryDirs)
3375 if(!libPathExists[item]) // fstrcmp should be used
3377 String s = CopyString(item);
3379 libPathExists[s] = true;
3383 #if defined(__APPLE__)
3384 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3386 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3389 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3391 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3392 for(c = 0; c < count; c++)
3394 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3396 String s = CopyString(oldPaths[c]);
3398 libPathExists[s] = true;
3403 for(path : newLibPaths)
3404 len += strlen(path) + 1;
3405 newList = new char[len + 1];
3407 for(path : newLibPaths)
3409 strcat(newList, path);
3410 strcat(newList, pathListSep);
3412 newList[len - 1] = '\0';
3413 #if defined(__APPLE__)
3414 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3416 SetEnvironment("LD_LIBRARY_PATH", newList);
3419 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3425 delete libPathExists;
3428 if(compiler.distccEnabled && compiler.distccHosts)
3429 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3434 void DestroyTemporaryProjectDir()
3436 if(tmpPrjDir && tmpPrjDir[0])
3438 if(FileExists(tmpPrjDir).isDirectory)
3439 DestroyDir(tmpPrjDir);
3440 property::tmpPrjDir = null;
3446 // Graphics Driver Menu
3449 app.currentSkin.selectionColor = selectionColor;
3450 app.currentSkin.selectionText = selectionText;
3454 driverItems = new MenuItem[app.numDrivers];
3455 for(c = 0; c < app.numDrivers; c++)
3457 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3458 driverItems[c].id = c;
3459 driverItems[c].isRadio = true;
3462 driverItems = new MenuItem[2];
3463 #if defined(__unix__)
3464 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3465 driverItems[0].id = 0;
3466 driverItems[0].isRadio = true;
3468 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3469 driverItems[0].id = 0;
3470 driverItems[0].isRadio = true;
3472 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3473 driverItems[1].id = 1;
3474 driverItems[1].isRadio = true;
3476 /* skinItems = new MenuItem[app.numSkins];
3477 for(c = 0; c < app.numSkins; c++)
3479 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3480 skinItems[c].id = c;
3481 skinItems[c].isRadio = true;
3484 ideFileDialog.master = this;
3485 ideProjectFileDialog.master = this;
3487 //SetDriverAndSkin();
3491 void UpdateRecentMenus()
3494 Menu fileMenu = menu.FindMenu($"File");
3495 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3496 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3497 char * itemPath = new char[MAX_LOCATION];
3498 char * itemName = new char[MAX_LOCATION+4];
3500 recentFiles.Clear();
3503 for(recent : ideSettings.recentFiles)
3505 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3506 MakeSystemPath(itemPath);
3507 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3508 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3512 recentProjects.Clear();
3514 for(recent : ideSettings.recentProjects)
3516 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3517 MakeSystemPath(itemPath);
3518 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3519 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3531 delete languageItems;
3535 documentor.Puts("Quit\n");
3542 void DestroyDir(char * path)
3544 RecursiveDeleteFolderFSI fsi { };
3549 #if defined(__WIN32__)
3550 define sdkDirName = "Ecere SDK";
3552 define sdkDirName = "ecere";
3555 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3558 char * v = new char[maxPathLen];
3562 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3563 StripLastDirectory(path, path);
3564 PathCat(path, subDir);
3565 if(name) PathCat(path, name);
3566 if(FileExists(path) & attribs) found = true;
3568 #if defined(__WIN32__)
3571 for(s : [ "ECERE_SDK_SRC", "AppData", "ALLUSERSPROFILE", "USERPROFILE", "HOMEPATH", "ProgramData", "ProgramFiles", "ProgramFiles(x86)", "SystemDrive" ])
3573 GetEnvironment(s, v, maxPathLen);
3576 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3577 if(!strcmp(s, "SystemDrive"))
3578 PathCat(path, "Program Files");
3579 if(strcmp(s, "ECERE_SDK_SRC"))
3580 PathCat(path, sdkDirName);
3581 PathCat(path, subDir);
3582 if(name) PathCat(path, name);
3583 if(FileExists(path) & attribs)
3598 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3599 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3602 p = new char[MAX_LOCATION];
3604 strcat(p, "/usr/share");
3608 for(c=0; c<numTokens; c++)
3610 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3611 PathCat(path, sdkDirName);
3612 PathCat(path, subDir);
3614 PathCat(path, name);
3615 if(FileExists(path) & attribs)
3628 void FindAndShellOpenInstalledFolder(const char * name)
3630 char path[MAX_LOCATION];
3631 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3635 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3637 char path[MAX_LOCATION];
3638 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3642 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3644 bool preserveRootFolder;
3646 void OutFolder(const char * folderPath, bool isRoot)
3648 if(!(preserveRootFolder && isRoot))
3649 RemoveDir(folderPath);
3652 bool OnFile(const char * filePath)
3654 DeleteFile(filePath);
3659 class IDEApp : GuiApplication
3661 //driver = "Win32Console";
3662 // driver = "OpenGL";
3666 TempFile includeFile { };
3671 char ext[MAX_EXTENSION];
3672 SetLoggingMode(stdOut, null);
3673 //SetLoggingMode(debug, null);
3675 settingsContainer.Load();
3677 if(ideSettings.language)
3679 const String language = GetLanguageString();
3680 if(ideSettings.language.OnCompare(language))
3682 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3687 // First count files arg to decide whether to maximize
3689 bool passThrough = false, debugWorkDir = false;
3692 for(c = 1; c<app.argc; c++)
3695 else if(debugWorkDir)
3696 debugWorkDir = false;
3697 else if(!strcmp(app.argv[c], "-t"));
3698 else if(!strcmp(app.argv[c], "-no-parsing"));
3699 else if(!strcmp(app.argv[c], "-debug-start"));
3700 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3701 debugWorkDir = true;
3702 else if(!strcmp(app.argv[c], "-@"))
3709 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3711 app.driver = "OpenGL";
3712 ide.driverItems[1].checked = true;
3716 #if defined(__unix__) || defined(__APPLE__)
3717 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3719 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3721 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3725 char model[MAX_LOCATION];
3726 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3728 ide.duck.modelFile = model;
3729 ide.duck.parent = ideMainFrame;
3732 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3733 ide.debugRubberDuck.disabled = false;
3737 desktop.caption = titleECEREIDE;
3740 for(c = 1; c<app.argc; c++)
3742 char fullPath[MAX_LOCATION];
3743 GetWorkingDir(fullPath, MAX_LOCATION);
3744 PathCat(fullPath, app.argv[c]);
3745 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3749 // Default to language specified by environment if no language selected
3750 if(!ideSettings.language)
3752 ideSettings.language = GetLanguageString();
3753 settingsContainer.Save();
3756 // Default to home directory if no directory yet set up
3757 if(!ideSettings.ideProjectFileDialogLocation[0])
3760 char location[MAX_LOCATION];
3761 char * home = getenv("HOME");
3762 char * homeDrive = getenv("HOMEDRIVE");
3763 char * homePath = getenv("HOMEPATH");
3764 char * userProfile = getenv("USERPROFILE");
3765 char * systemDrive = getenv("SystemDrive");
3766 if(home && FileExists(home).isDirectory)
3768 strcpy(location, home);
3771 if(!found && homeDrive && homePath)
3773 strcpy(location, homeDrive);
3774 PathCat(location, homePath);
3775 if(FileExists(location).isDirectory)
3778 if(!found && FileExists(userProfile).isDirectory)
3780 strcpy(location, userProfile);
3783 if(!found && FileExists(systemDrive).isDirectory)
3785 strcpy(location, systemDrive);
3790 ideSettings.ideProjectFileDialogLocation = location;
3791 if(!ideSettings.ideFileDialogLocation[0])
3792 ideSettings.ideFileDialogLocation = location;
3796 if(!LoadIncludeFile())
3797 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3799 // Create language menu
3801 String language = ideSettings.language;
3805 ide.languageItems = new MenuItem[languages.count];
3808 ide.languageItems[i] =
3810 ide.languageMenu, l.name;
3811 bitmap = { l.bitmap };
3815 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3817 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3819 // Re-select previous selected language if aborted
3820 String language = ideSettings.language;
3824 if(((!language || !language[0]) && i == 0) ||
3825 (language && !strcmpi(l.code, language)))
3827 ide.languageItems[i].checked = true;
3839 // Try to find country-specific language first
3845 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3847 ide.languageItems[i].checked = true;
3855 // Try generalizing locale
3856 if(!found && language)
3859 char genericLocale[256];
3861 strncpy(genericLocale, language, sizeof(genericLocale));
3862 genericLocale[sizeof(genericLocale)-1] = 0;
3864 under = strchr(genericLocale, '_');
3867 if(!strcmpi(genericLocale, "zh"))
3868 strcpy(genericLocale, "zh_CN");
3869 if(strcmp(genericLocale, language))
3873 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3875 ide.languageItems[i].checked = true;
3885 ide.languageItems[0].checked = true;
3887 MenuDivider { ide.languageMenu };
3890 ide.languageMenu, "Help Translate";
3892 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3894 ShellOpen("http://translations.launchpad.net/ecere");
3900 ideMainFrame.Create();
3901 if(app.argFilesCount > 1)
3902 ide.MenuWindowTileVert(null, 0);
3906 bool Cycle(bool idle)
3910 if(ide.documentor.Peek())
3913 ide.documentor.GetLine(line, sizeof(line));
3914 if(!strcmpi(line, "Exited"))
3916 ide.documentor.CloseInput();
3917 ide.documentor.CloseOutput();
3918 ide.documentor.Wait();
3919 delete ide.documentor;
3922 if(ide.documentor && ide.documentor.eof)
3924 ide.documentor.CloseInput();
3925 ide.documentor.CloseOutput();
3926 ide.documentor.Wait();
3927 delete ide.documentor;
3933 bool LoadIncludeFile()
3935 bool result = false;
3936 File include = FileOpen(":crossplatform.mk", read);
3939 File f = includeFile;
3942 for(; !include.Eof(); )
3945 int count = include.Read(buffer, 1, 4096);
3946 f.Write(buffer, 1, count);
3956 IDEMainFrame ideMainFrame { };
3958 define app = ((IDEApp)__thisModule);
3960 define titleECEREIDE = $"Ecere IDE (Debug)";
3962 define titleECEREIDE = $"Ecere IDE";