2 public import static "ecere"
3 public import static "ec"
9 import "GlobalSettingsDialog"
10 import "NewProjectDialog"
11 import "FindInFilesDialog"
18 import "ProjectConfig"
20 import "NodeProperties"
21 import "ProjectSettings"
33 import "BreakpointsView"
34 import "CallStackView"
45 import "FileSystemIterator"
47 AVLTree<const String> binaryDocExt
49 "wav", "mp3", "flac", "ogg",
51 "avi", "mkv", "mpg", "mpeg",
52 "7z", "zip", "gz", "bz2", "xz", "rar", "z", "tar", "ear",
53 "pdf", "odp", "ods", "odt", "ppt", "doc", "xls", "pptx", "docx", "xlsx"
56 #if defined(__WIN32__)
57 define pathListSep = ";";
59 define pathListSep = ":";
62 define maxPathLen = 65 * MAX_LOCATION;
64 class PathBackup : struct
71 oldPath = new char[maxPathLen];
72 oldLDPath = new char[maxPathLen];
74 GetEnvironment("PATH", oldPath, maxPathLen);
75 #if defined(__APPLE__)
76 GetEnvironment("DYLD_LIBRARY_PATH", oldLDPath, maxPathLen);
78 GetEnvironment("LD_LIBRARY_PATH", oldLDPath, maxPathLen);
84 SetEnvironment("PATH", oldPath);
85 #if defined(__APPLE__)
86 SetEnvironment("DYLD_LIBRARY_PATH", oldLDPath);
88 SetEnvironment("LD_LIBRARY_PATH", oldLDPath);
95 enum OpenCreateIfFails { no, yes, something, whatever };
96 enum OpenMethod { normal, add };
98 static Array<FileFilter> fileFilters
100 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
101 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
102 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
103 { $"Text files (*.txt, *.text, *.nfo, *.info)", "txt, text, nfo, info" },
104 { $"Web files (*.html, *.htm, *.xhtml, *.css, *.php, *.js, *.jsi, *.rb, *.xml)", "html, htm, xhtml, css, php, js, jsi, rb, xml" },
105 { $"Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", "jpg, jpeg, bmp, pcx, png, gif" },
106 { $"3D Studio Model Files (*.3ds)", "3ds" },
107 { $"All files", null }
110 static Array<FileType> fileTypes
112 { $"Based on extension", null },
115 { $"3D Studio Model", "3ds" }
118 static Array<FileFilter> projectFilters
120 { $"Project Files (*.epj)", ProjectExtension }
123 static Array<FileType> projectTypes
125 { $"Project File", ProjectExtension }
128 static Array<FileFilter> findInFilesFileFilters
130 { $"eC Files (*.ec, *.eh)", "ec, eh" },
131 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
132 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
133 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
134 { $"Text files (*.txt)", "txt" },
135 { $"All files", null }
138 FileDialog ideFileDialog
140 type = multiOpen, text = $"Open";
141 types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType), filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter);
144 define openProjectFileDialogTitle = $"Open Project";
145 define addProjectFileDialogTitle = $"Open Additional Project";
146 FileDialog ideProjectFileDialog
149 types = projectTypes.array, sizeTypes = projectTypes.count * sizeof(FileType), filters = projectFilters.array, sizeFilters = projectFilters.count * sizeof(FileFilter);
152 GlobalSettingsDialog globalSettingsDialog
154 ideSettings = ideSettings;
155 settingsContainer = settingsContainer;
157 void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange)
159 switch(globalSettingsChange)
164 for(child = ide.firstChild; child; child = child.next)
166 if(child._class == class(CodeEditor))
168 CodeEditor codeEditor = (CodeEditor) child;
169 codeEditor.editBox.freeCaret = ideSettings.useFreeCaret;
170 // codeEditor.editBox.lineNumbers = ideSettings.showLineNumbers;
171 codeEditor.editBox.caretFollowsScrolling = ideSettings.caretFollowsScrolling;
172 codeEditor.OnPostCreate(); // Update editBox margin size
179 case compilerSettings:
181 ide.UpdateCompilerConfigs(true);
188 void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
193 lineY = (line - 1) * lineH;
194 if(lineY + lineH > scrollY && lineY + lineH < scrollY + boxH)
196 Bitmap bitmap = resource.bitmap;
198 surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
203 #define IDEItem(x) (&((IDEWorkSpace)0).x)
205 class IDEToolbar : ToolBar
209 ToolButton buttonNewFile { this, toolTip = $"New file", menuItemPtr = IDEItem(fileNewItem) };
211 ToolButton buttonOpenFile { this, toolTip = $"Open file", menuItemPtr = IDEItem(fileOpenItem) };
213 // ToolButton buttonCloseFile { this, toolTip = $"Close file", menuItemPtr = IDEItem(fileCloseItem) };
215 ToolButton buttonSaveFile { this, toolTip = $"Save file", menuItemPtr = IDEItem(fileSaveItem) };
217 ToolButton buttonSaveAllFile { this, toolTip = $"Save all", menuItemPtr = IDEItem(fileSaveAllItem) };
219 ToolSeparator separator1 { this };
228 // ToolSeparator separator2 { this };
232 ToolButton buttonNewProject { this, toolTip = $"New project", menuItemPtr = IDEItem(projectNewItem) };
234 ToolButton buttonOpenProject { this, toolTip = $"Open project", menuItemPtr = IDEItem(projectOpenItem) };
235 // Add project to workspace
236 ToolButton buttonAddProject { this, toolTip = $"Add project to workspace", menuItemPtr = IDEItem(projectAddItem), disabled = true; };
238 // ToolButton buttonCloseProject { this, toolTip = $"Close project", menuItemPtr = IDEItem(projectCloseItem), disabled = true; };
240 ToolSeparator separator3 { this };
242 // Build/Execution options
244 ToolButton buttonBuild { this, toolTip = $"Build project", menuItemPtr = IDEItem(projectBuildItem), disabled = true; };
246 ToolButton buttonReLink { this, toolTip = $"Relink project", menuItemPtr = IDEItem(projectLinkItem), disabled = true; };
248 ToolButton buttonRebuild { this, toolTip = $"Rebuild project", menuItemPtr = IDEItem(projectRebuildItem), disabled = true; };
250 ToolButton buttonClean { this, toolTip = $"Clean project", menuItemPtr = IDEItem(projectCleanItem), disabled = true; };
252 // ToolButton buttonRealClean { this, toolTip = $"Real clean project", menuItemPtr = IDEItem(projectRealCleanItem), disabled = true; };
253 // Regenerate Makefile
254 ToolButton buttonRegenerateMakefile { this, toolTip = $"Regenerate Makefile", menuItemPtr = IDEItem(projectRegenerateItem), disabled = true; };
255 // Compile actual file
257 ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem), disabled = true; };
258 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
259 ToolButton buttonInstall { this, toolTip = $"Install", menuItemPtr = IDEItem(projectInstallItem), disabled = true; };
262 ToolSeparator separator4 { this };
266 ToolButton buttonDebugStartResume { this, toolTip = $"Start", menuItemPtr = IDEItem(debugStartResumeItem), disabled = true; };
268 ToolButton buttonDebugRestart { this, toolTip = $"Restart", menuItemPtr = IDEItem(debugRestartItem), disabled = true; };
270 ToolButton buttonDebugPause { this, toolTip = $"Break", menuItemPtr = IDEItem(debugBreakItem), disabled = true; };
272 ToolButton buttonDebugStop { this, toolTip = $"Stop", menuItemPtr = IDEItem(debugStopItem), disabled = true; };
274 //ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem) };
276 ToolButton buttonDebugStepInto { this, toolTip = $"Step Into", menuItemPtr = IDEItem(debugStepIntoItem), disabled = true; };
278 ToolButton buttonDebugStepOver { this, toolTip = $"Step Over", menuItemPtr = IDEItem(debugStepOverItem), disabled = true; };
280 ToolButton buttonDebugStepOut { this, toolTip = $"Step Out", menuItemPtr = IDEItem(debugStepOutItem), disabled = true; };
282 ToolButton buttonDebugSkipStepOver { this, toolTip = $"Step Over Skipping Breakpoints", menuItemPtr = IDEItem(debugSkipStepOverItem), disabled = true; };
284 ToolSeparator separator5 { this };
286 Window spacer5 { this, size = { 4 } };
290 this, toolTip = $"Active Configuration(s)", size = { 160 }, disabled = true;
291 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
294 ide.workspace.SelectActiveConfig(row.string);
299 Window spacer6 { this, size = { 4 } };
301 DropBox activeCompiler
303 this, toolTip = $"Active Compiler", size = { 160 }, disabled = true;
304 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
306 if(ide.workspace && ide.projectView && row && strcmp(row.string, ide.workspace.activeCompiler))
308 bool silent = ide.projectView.buildInProgress == none ? false : true;
309 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(row.string);
310 ide.workspace.activeCompiler = row.string;
311 ide.projectView.ShowOutputBuildLog(!silent);
313 ide.projectView.DisplayCompiler(compiler, false);
314 for(prj : ide.workspace.projects)
315 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
317 ide.workspace.Save();
323 DropBox activeBitDepth
325 this, toolTip = $"Active Bit Length", size = { 60 }, disabled = true;
326 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
328 if(ide.workspace && ide.projectView && row)
330 bool silent = ide.projectView.buildInProgress == none ? false : true;
331 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler);
332 ide.workspace.bitDepth = (int)row.tag;
333 ide.projectView.ShowOutputBuildLog(!silent);
335 ide.projectView.DisplayCompiler(compiler, false);
336 for(prj : ide.workspace.projects)
337 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
339 ide.workspace.Save();
345 Window spacer7 { this, size = { 4 } };
350 row = activeBitDepth.AddString("Auto");
352 activeBitDepth.AddString("32 bit").tag = 32;
353 activeBitDepth.AddString("64 bit").tag = 64;
354 activeBitDepth.currentRow = row;
358 class IDEMainFrame : Window
360 background = formColor;
361 borderStyle = sizable;
365 minClientSize = { 600, 300 };
367 icon = { ":icon.png" };
368 text = titleECEREIDE;
372 anchor = { top = 0, right = 0, bottom = 0 };
375 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
382 isActiveClient = true;
384 direction = vertical;
385 background = formColor;
386 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
394 ((IDEWorkSpace)master).toolBar = null;
397 IDEWorkSpace ideWorkSpace { stack, this, toolBar = toolBar };
400 define ide = ideMainFrame.ideWorkSpace;
402 class IDEWorkSpace : Window
404 background = Color { 85, 85, 85 };
407 hasVertScroll = true;
408 hasHorzScroll = true;
410 isActiveClient = true;
411 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
415 MenuItem * driverItems, * skinItems, * languageItems;
416 StatusField pos { width = 150 };
417 StatusField ovr, caps, num;
420 BitmapResource back { ":ecereBack.jpg", window = this };
421 BitmapResource bmpBp { ":codeMarks/breakpoint.png", window = this };
422 BitmapResource bmpBpDisabled { ":codeMarks/breakpointDisabled.png", window = this };
423 BitmapResource bmpBpHalf { ":codeMarks/breakpointHalf.png", window = this };
424 BitmapResource bmpBpHalfDisabled { ":codeMarks/breakpointHalfDisabled.png", window = this };
425 BitmapResource bmpCursor { ":codeMarks/cursor.png", window = this };
426 BitmapResource bmpCursorError { ":codeMarks/cursorError.png", window = this };
427 BitmapResource bmpTopFrame { ":codeMarks/topFrame.png", window = this };
428 BitmapResource bmpTopFrameError { ":codeMarks/topFrameError.png", window = this };
429 BitmapResource bmpTopFrameHalf { ":codeMarks/topFrameHalf.png", window = this };
430 BitmapResource bmpTopFrameHalfError { ":codeMarks/topFrameHalfError.png", window = this };
432 BuildOutputMode rightClickMenuBuildOutputMode;
434 Debugger debugger { };
436 ProjectView projectView;
438 OutputView outputView
442 void OnGotoError(const char * line, bool noParsing)
444 CompilerConfig compiler = ide.workspace ? ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler) : null;
445 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
446 ide.GoToError(line, noParsing, objectFileExt);
450 void OnCodeLocationParseAndGoTo(const char * line)
452 CompilerConfig compiler = ide.workspace ? ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler) : null;
453 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
454 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir, objectFileExt);
458 bool OnKeyDown(Key key, unichar ch)
463 if(activeBox != findBox || !ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
464 ide.ShowCodeEditor();
468 OutputView::OnKeyDown(key, ch);
475 bool OnClose(bool parentClosing)
479 ide.RepositionWindows(false);
480 return parentClosing;
484 CallStackView callStackView
486 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
488 void OnSelectFrame(int frameIndex)
490 ide.debugger.GoToStackFrameLine(frameIndex, true, true);
492 ide.debugger.SelectFrame(frameIndex);
495 void OnToggleBreakpoint()
497 Debugger debugger = ide.debugger;
498 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
500 int line = debugger.activeFrame.line;
501 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line);
504 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
505 if(codeEditor) { codeEditor.Update(null); Activate(); }
510 bool OnKeyDown(Key key, unichar ch)
514 case escape: ide.ShowCodeEditor(); break;
519 bool OnClose(bool parentClosing)
523 ide.RepositionWindows(false);
524 return parentClosing;
527 void OnRedraw(Surface surface)
529 Debugger debugger = ide.debugger;
530 Frame activeFrame = debugger.activeFrame;
534 int lineCursor, lineTopFrame;
535 int lineH, scrollY, boxH;
537 Breakpoint bp = null;
540 scrollY = editBox.scroll.y;
541 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
542 //activeThread = debugger.activeThread;
543 //hitThread = debugger.hitThread;
544 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
546 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
547 if(activeFrame.absoluteFile)
549 for(i : ide.workspace.breakpoints; i.type == user)
551 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
552 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
553 activeFrame.line == i.line)
561 DrawLineMarginIcon(surface,
562 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
563 lineCursor /*1*/, lineH, scrollY, boxH);
565 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
566 DrawLineMarginIcon(surface,
567 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
568 1, lineH, scrollY, boxH);
570 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
571 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
572 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
574 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
575 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
577 if(editBox.horzScroll && editBox.horzScroll.visible)
579 surface.SetBackground(control);
580 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
585 WatchesView watchesView { parent = this };
586 ThreadsView threadsView
588 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
590 bool OnKeyDown(Key key, unichar ch)
594 case escape: ide.ShowCodeEditor(); break;
599 bool OnClose(bool parentClosing)
603 ide.RepositionWindows(false);
604 return parentClosing;
607 void OnSelectThread(int threadId)
610 ide.debugger.SelectThread(threadId);
613 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
616 Debugger debugger = ide.debugger;
617 *activeThread = debugger.activeThread;
618 *hitThread = debugger.hitThread;
619 *signalThread = debugger.signalThread;
624 BreakpointsView breakpointsView { parent = this };
626 ToolBox toolBox { parent = this, visible = false };
627 Sheet sheet { parent = this, visible = false };
630 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
632 Menu fileMenu { menu, $"File", f, hasMargin = true };
635 fileMenu, $"New", n, ctrlN;
636 bitmap = { ":actions/docNew.png" };
637 bool NotifySelect(MenuItem selection, Modifiers mods)
639 Window currentDoc = activeClient;
640 bool maximizeDoc = ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
641 Window document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, false);
642 RepositionWindows(false);
643 document.NotifySaved = DocumentSaved;
647 MenuItem fileOpenItem
649 fileMenu, $"Open...", o, ctrlO;
650 bitmap = { ":actions/docOpen.png" };
651 bool NotifySelect(MenuItem selection, Modifiers mods)
653 if(!projectView && ideSettings.ideFileDialogLocation)
654 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
657 if(ideFileDialog.Modal() == ok)
659 bool gotWhatWeWant = false;
661 int numSelections = ideFileDialog.numSelections;
662 const char * const * multiFilePaths = ideFileDialog.multiFilePaths;
664 for(c = 0; c < numSelections; c++)
666 if(OpenFile(multiFilePaths[c], false, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
667 gotWhatWeWant = true;
670 MessageBox { type = yesNo, master = this, text = $"Error opening file",
671 contents = $"Open a different file?" }.Modal() == no)
673 if(!projectView && gotWhatWeWant)
674 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
675 ide.RepositionWindows(false);
685 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
686 MenuDivider { fileMenu };
687 MenuItem fileSaveItem
689 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
691 // For the toolbar button; clients can still override that for the menu item
692 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
694 Window w = activeClient;
696 w.MenuFileSave(null, 0);
700 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
701 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
702 MenuDivider { fileMenu };
705 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
706 bool NotifySelect(MenuItem selection, Modifiers mods)
708 findInFilesDialog.replaceMode = false;
709 findInFilesDialog.Show();
713 MenuItem replaceInFiles
715 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
716 bool NotifySelect(MenuItem selection, Modifiers mods)
718 findInFilesDialog.replaceMode = true;
719 findInFilesDialog.Show();
723 MenuDivider { fileMenu };
724 MenuItem globalSettingsItem
726 fileMenu, $"Global Settings...", g;
727 bool NotifySelect(MenuItem selection, Modifiers mods)
729 // Reload configs here until we setup a configs directory monitor
730 ideConfig.compilers.Free();
731 ideConfig.compilers.read();
733 globalSettingsDialog.master = this;
734 if(ide.workspace && ide.workspace.activeCompiler)
735 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.activeCompiler;
736 else if(ideSettings.defaultCompiler)
737 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
738 globalSettingsDialog.Modal();
742 MenuDivider { fileMenu };
743 Menu recentFilesMenu { fileMenu, $"Recent Files", r };
744 Menu recentProjectsMenu { fileMenu, $"Recent Projects", p };
745 MenuDivider { fileMenu };
748 fileMenu, $"Exit", x, altF4;
750 bool NotifySelect(MenuItem selection, Modifiers mods)
752 ideMainFrame.Destroy(0);
757 bool FileRecentFile(MenuItem selection, Modifiers mods)
760 RecentPaths recentFiles = workspace ? workspace.recentFiles : ideConfig.recentFiles;
761 for(file : recentFiles)
763 if(id == selection.id)
766 char extension[MAX_EXTENSION] = "";
767 GetExtension(file, extension);
768 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
769 if(mods.ctrl && !mods.shift)
771 char * command = PrintString("ecere-ide ", isProjectFile ? "-t " : "", file);
777 OpenFile(file, false, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
778 ide.RepositionWindows(false);
787 bool FileRecentProject(MenuItem selection, Modifiers mods)
790 for(file : ideConfig.recentWorkspaces)
792 if(id == selection.id)
794 if(mods.ctrl && !mods.shift)
796 char * command = PrintString("ecere-ide ", file);
801 OpenFile(file, false, true, (mods.ctrl && mods.shift) ? "txt" : null, no, normal, mods.ctrl && mods.shift);
809 MenuPlacement editMenu { menu, $"Edit", e };
811 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
812 MenuItem projectNewItem
814 projectMenu, $"New...", n, Key { n, true, true };
815 bitmap = { ":actions/projNew.png" };
816 bool NotifySelect(MenuItem selection, Modifiers mods)
818 if(!DontTerminateDebugSession($"New Project"))
821 NewProjectDialog newProjectDialog { master = this };
822 incref newProjectDialog;
823 result = newProjectDialog.Modal();
828 newProjectDialog.CreateNewProject();
831 ideConfig.recentWorkspaces.addRecent(projectView.fileName);
832 ide.updateRecentProjectsMenu();
836 delete newProjectDialog;
841 MenuItem projectOpenItem
843 projectMenu, $"Open...", o, Key { o, true, true };
844 bitmap = { ":actions/projOpen.png" };
845 bool NotifySelect(MenuItem selection, Modifiers mods)
847 if(ideSettings.ideProjectFileDialogLocation)
848 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
850 ideProjectFileDialog.text = openProjectFileDialogTitle;
851 if(ideProjectFileDialog.Modal() == ok)
853 OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
854 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
859 MenuItem projectQuickItem
861 projectMenu, $"Quick...", q, f7, disabled = true;
862 bool NotifySelect(MenuItem selection, Modifiers mods)
865 QuickProjectDialog { this }.Modal();
869 MenuItem projectAddItem
871 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
872 bitmap = { ":actions/projAdd.png" };
874 bool NotifySelect(MenuItem selection, Modifiers mods)
876 if(ideSettings.ideProjectFileDialogLocation)
877 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
879 ideProjectFileDialog.text = addProjectFileDialogTitle;
882 if(ideProjectFileDialog.Modal() == ok)
884 if(OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
886 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
887 contents = $"Add a different project?" }.Modal() == no)
898 MenuItem projectCloseItem
900 projectMenu, $"Close", c, disabled = true;
901 bool NotifySelect(MenuItem selection, Modifiers mods)
905 if(!ide.DontTerminateDebugSession($"Project Close"))
911 MenuDivider { projectMenu };
912 MenuItem projectSettingsItem
914 projectMenu, $"Settings...", s, altF7, disabled = true;
915 bool NotifySelect(MenuItem selection, Modifiers mods)
917 projectView.MenuSettings(projectView.active ? selection : null, mods);
921 MenuDivider { projectMenu };
922 MenuItem projectBrowseFolderItem
924 projectMenu, $"Browse Project Folder", p, disabled = true;
925 bool NotifySelect(MenuItem selection, Modifiers mods)
928 projectView.MenuBrowseFolder(null, mods);
932 MenuDivider { projectMenu };
933 MenuItem projectRunItem
935 projectMenu, $"Run", r, ctrlF5, disabled = true;
936 bitmap = { ":actions/run.png" };
937 bool NotifySelect(MenuItem selection, Modifiers mods)
940 projectView.Run(null, mods);
944 MenuItem projectBuildItem
946 projectMenu, $"Build", b, f7, disabled = true;
947 bitmap = { ":actions/build.png" };
948 bool NotifySelect(MenuItem selection, Modifiers mods)
952 if(projectView.buildInProgress == none)
953 projectView.ProjectBuild(projectView.active ? selection : null, mods);
955 projectView.stopBuild = true;
960 MenuItem projectLinkItem
962 projectMenu, $"Relink", l, disabled = true;
963 bitmap = { ":actions/relink.png" };
964 bool NotifySelect(MenuItem selection, Modifiers mods)
967 projectView.ProjectLink(projectView.active ? selection : null, mods);
971 MenuItem projectRebuildItem
973 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
974 bitmap = { ":actions/rebuild.png" };
975 bool NotifySelect(MenuItem selection, Modifiers mods)
978 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
982 MenuItem projectCleanTargetItem
984 projectMenu, $"Clean Target", g, disabled = true;
985 bitmap = { ":actions/clean.png" };
986 bool NotifySelect(MenuItem selection, Modifiers mods)
991 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
996 MenuItem projectCleanItem
998 projectMenu, $"Clean", e, disabled = true;
999 bitmap = { ":actions/clean.png" };
1000 bool NotifySelect(MenuItem selection, Modifiers mods)
1005 projectView.ProjectClean(projectView.active ? selection : null, mods);
1010 MenuItem projectRealCleanItem
1012 projectMenu, $"Real Clean", disabled = true;
1013 bitmap = { ":actions/clean.png" };
1014 bool NotifySelect(MenuItem selection, Modifiers mods)
1019 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1024 MenuItem projectRegenerateItem
1026 projectMenu, $"Regenerate Makefile", m, disabled = true;
1027 bitmap = { ":actions/regMakefile.png" };
1028 bool NotifySelect(MenuItem selection, Modifiers mods)
1031 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1035 MenuItem projectInstallItem
1037 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
1038 projectMenu, $"Install", t, disabled = true;
1040 bitmap = { ":status/software-update-available.png" };
1041 bool NotifySelect(MenuItem selection, Modifiers mods)
1044 projectView.ProjectInstall(projectView.active ? selection : null, mods);
1048 MenuItem projectCompileItem;
1049 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1050 MenuItem debugStartResumeItem
1052 debugMenu, $"Start", s, f5, disabled = true;
1053 bitmap = { ":actions/debug.png" };
1054 NotifySelect = MenuDebugStart;
1056 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1060 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1061 if(!projectView.DebugStart())
1062 debugStartResumeItem.disabled = false; // same exception
1066 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1069 projectView.DebugResume();
1072 MenuItem debugRestartItem
1074 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1075 bitmap = { ":actions/restart.png" };
1076 bool NotifySelect(MenuItem selection, Modifiers mods)
1079 projectView.DebugRestart();
1083 MenuItem debugBreakItem
1085 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1086 bitmap = { ":actions/pause.png" };
1087 bool NotifySelect(MenuItem selection, Modifiers mods)
1089 if(projectView && projectView.buildInProgress != none)
1092 projectView.DebugBreak();
1096 MenuItem debugStopItem
1098 debugMenu, $"Stop", p, shiftF5, disabled = true;
1099 bitmap = { ":actions/stopDebug.png" };
1100 bool NotifySelect(MenuItem selection, Modifiers mods)
1103 projectView.DebugStop();
1107 MenuDivider { debugMenu };
1111 // nonClient = true,
1118 anchor = { right = 0, bottom = 0 },
1120 isActiveClient = false,
1122 clickThrough = true,
1123 size = { 500, 500 };
1125 bool OnLoadGraphics()
1127 ModelView::OnLoadGraphics();
1128 camera.position.z /= 1.3;
1129 camera.orientation = Euler { yaw = 280, pitch = 20 };
1135 bool OnRightButtonDown(int x, int y, Modifiers mods)
1137 if(!displaySystem.flags.flipping) return true;
1138 MenuWindowMove(null, 0);
1142 bool OnRightButtonUp(int x, int y, Modifiers mods)
1144 position = position;
1149 MenuItem debugRubberDuck
1151 debugMenu, $"Rubber Duck", checkable = true, disabled = true;
1152 bool NotifySelect(MenuItem selection, Modifiers mods)
1154 if(selection.checked)
1162 MenuDivider { debugMenu };
1163 MenuItem debugUseValgrindItem
1165 debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
1166 bool NotifySelect(MenuItem selection, Modifiers mods)
1170 ide.workspace.useValgrind = selection.checked;
1171 ide.workspace.Save();
1173 ide.AdjustValgrindMenus();
1177 Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
1178 MenuItem debugValgrindNoLeakCheckItem { debugValgrindLeakCheckItem, $"No" , f, id = ValgrindLeakCheck::no , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1179 MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; };
1180 MenuItem debugValgrindYesLeakCheckItem { debugValgrindLeakCheckItem, $"Yes" , f, id = ValgrindLeakCheck::yes , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1181 MenuItem debugValgrindFullLeakCheckItem { debugValgrindLeakCheckItem, $"Full" , f, id = ValgrindLeakCheck::full , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1182 bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
1186 if(selection.checked)
1188 ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
1190 debugValgrindNoLeakCheckItem.checked = debugValgrindNoLeakCheckItem.id == vgLeakCheck;
1191 debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
1192 debugValgrindYesLeakCheckItem.checked = debugValgrindYesLeakCheckItem.id == vgLeakCheck;
1193 debugValgrindFullLeakCheckItem.checked = debugValgrindFullLeakCheckItem.id == vgLeakCheck;
1195 ide.workspace.vgLeakCheck = vgLeakCheck;
1196 ide.workspace.Save();
1199 selection.checked = true;
1203 Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
1204 MenuItem debugValgrindRSDefaultItem { debugValgrindRedzoneSizeItem, $"Default", f, id = -1, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; };
1205 MenuItem debugValgrindRS0Item { debugValgrindRedzoneSizeItem, "0" , f, id = 0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1206 MenuItem debugValgrindRS16Item { debugValgrindRedzoneSizeItem, "16" , f, id = 16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1207 MenuItem debugValgrindRS32Item { debugValgrindRedzoneSizeItem, "32" , f, id = 32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1208 MenuItem debugValgrindRS64Item { debugValgrindRedzoneSizeItem, "64" , f, id = 64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1209 MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, "128" , f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1210 MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, "256" , f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1211 MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, "512" , f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1212 bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
1216 if(selection.checked)
1218 int vgRedzoneSize = (int)selection.id;
1220 debugValgrindRSDefaultItem.checked = debugValgrindRSDefaultItem.id == vgRedzoneSize;
1221 debugValgrindRS0Item.checked = debugValgrindRS0Item.id == vgRedzoneSize;
1222 debugValgrindRS16Item.checked = debugValgrindRS16Item.id == vgRedzoneSize;
1223 debugValgrindRS32Item.checked = debugValgrindRS32Item.id == vgRedzoneSize;
1224 debugValgrindRS64Item.checked = debugValgrindRS64Item.id == vgRedzoneSize;
1225 debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
1226 debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
1227 debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
1229 ide.workspace.vgRedzoneSize = vgRedzoneSize;
1230 ide.workspace.Save();
1233 selection.checked = true;
1237 MenuItem debugValgrindTrackOriginsItem
1239 debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
1240 bool NotifySelect(MenuItem selection, Modifiers mods)
1244 ide.workspace.vgTrackOrigins = selection.checked;
1245 ide.workspace.Save();
1251 MenuDivider { debugMenu };
1252 MenuItem debugStepIntoItem
1254 debugMenu, $"Step Into", i, f11, disabled = true;
1255 bitmap = { ":actions/stepInto.png" };
1256 bool NotifySelect(MenuItem selection, Modifiers mods)
1258 if(projectView) projectView.DebugStepInto();
1262 MenuItem debugStepOverItem
1264 debugMenu, $"Step Over", v, f10, disabled = true;
1265 bitmap = { ":actions/stepOver.png" };
1266 bool NotifySelect(MenuItem selection, Modifiers mods)
1268 if(projectView) projectView.DebugStepOver(false);
1272 MenuItem debugSkipStepOverItem
1274 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1275 bitmap = { ":actions/stepOverSkipBreak.png" };
1276 bool NotifySelect(MenuItem selection, Modifiers mods)
1278 if(projectView) projectView.DebugStepOver(true);
1282 MenuItem debugStepOutItem
1284 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1285 bitmap = { ":actions/stepOut.png" };
1286 bool NotifySelect(MenuItem selection, Modifiers mods)
1288 if(projectView) projectView.DebugStepOut(false);
1292 MenuItem debugSkipStepOutItem
1294 debugMenu, $"Step Out Skipping Breakpoints", n, Key { f11, ctrl = true, shift = true }, disabled = true;
1295 bitmap = { ":actions/skipBreaks.png" };
1296 bool NotifySelect(MenuItem selection, Modifiers mods)
1298 if(projectView) projectView.DebugStepOut(true);
1303 MenuItem debugStepUntilItem
1305 debugMenu, $"Step Over Until Next Line", x, disabled = true;
1306 bool NotifySelect(MenuItem selection, Modifiers mods)
1308 if(projectView) projectView.DebugStepUntil(false);
1312 MenuItem debugSkipStepUntilItem
1314 debugMenu, $"Step Over Until Next Line Skipping Breakpoints", e, Key { f10, shift = true, alt = true }, disabled = true;
1315 bool NotifySelect(MenuItem selection, Modifiers mods)
1317 if(projectView) projectView.DebugStepUntil(true);
1322 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1323 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1324 MenuPlacement debugRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level", l };
1325 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", g };
1327 MenuPlacement debugBpRunToCursorItem { debugMenu, $"BP Run To Cursor" };
1328 MenuPlacement debugBpSkipRunToCursorItem { debugMenu, $"BP Run To Cursor Skipping Breakpoints" };
1329 MenuPlacement debugBpRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level" };
1330 MenuPlacement debugBpSkipRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level Skipping Breakpoints" };
1332 //MenuDivider { debugMenu };
1333 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1334 MenuPlacement imageMenu { menu, $"Image", i };
1335 Menu viewMenu { menu, $"View", v };
1336 MenuItem viewProjectItem
1338 viewMenu, $"Project View", j, alt0, disabled = true;
1339 bool NotifySelect(MenuItem selection, Modifiers mods)
1343 projectView.visible = true;
1344 projectView.Activate();
1349 MenuPlacement { viewMenu, $"View Designer" };
1350 MenuPlacement { viewMenu, $"View Code" };
1351 MenuPlacement { viewMenu, $"View Properties" };
1352 MenuPlacement { viewMenu, $"View Methods" };
1353 MenuItem viewDesignerItem
1355 viewMenu, $"View Designer", d, f8;
1356 bool NotifySelect(MenuItem selection, Modifiers mods)
1358 Window client = activeClient;
1359 Class dataType = client._class;
1360 if(!strcmp(dataType.name, "Designer"))
1362 client.visible = true;
1366 ((CodeEditor)client).ViewDesigner();
1370 MenuItem viewCodeItem
1372 viewMenu, $"View Code", c, f8;
1373 bool NotifySelect(MenuItem selection, Modifiers mods)
1375 Window client = activeClient;
1376 Class dataType = client._class;
1377 if(!strcmp(dataType.name, "Designer"))
1378 client = ((Designer)client).codeEditor;
1381 // Do this after so the caret isn't moved yet...
1382 client.visible = true;
1386 MenuItem viewPropertiesItem
1388 viewMenu, $"View Properties", p, f4;
1389 bool NotifySelect(MenuItem selection, Modifiers mods)
1391 sheet.visible = true;
1392 sheet.sheetSelected = properties;
1397 MenuItem viewMethodsItem
1399 viewMenu, $"View Methods", m, f4;
1400 bool NotifySelect(MenuItem selection, Modifiers mods)
1402 sheet.visible = true;
1403 sheet.sheetSelected = methods;
1408 MenuItem viewToolBoxItem
1410 viewMenu, $"View Toolbox", x, f12;
1411 bool NotifySelect(MenuItem selection, Modifiers mods)
1413 toolBox.visible = true;
1418 MenuItem viewOutputItem
1420 viewMenu, $"Output", o, alt2;
1421 bool NotifySelect(MenuItem selection, Modifiers mods)
1427 MenuItem viewWatchesItem
1429 viewMenu, $"Watches", w, alt3;
1430 bool NotifySelect(MenuItem selection, Modifiers mods)
1436 MenuItem viewThreadsItem
1438 viewMenu, $"Threads", t, alt4;
1439 bool NotifySelect(MenuItem selection, Modifiers mods)
1445 MenuItem viewBreakpointsItem
1447 viewMenu, $"Breakpoints", b, alt5;
1448 bool NotifySelect(MenuItem selection, Modifiers mods)
1450 breakpointsView.Show();
1454 MenuItem viewCallStackItem
1456 viewMenu, $"Call Stack", s, alt7;
1457 bool NotifySelect(MenuItem selection, Modifiers mods)
1459 callStackView.Show();
1463 MenuItem viewAllDebugViews
1465 viewMenu, $"All Debug Views", a, alt9;
1466 bool NotifySelect(MenuItem selection, Modifiers mods)
1471 callStackView.Show();
1472 breakpointsView.Show();
1476 #ifdef GDB_DEBUG_GUI
1477 MenuDivider { viewMenu };
1478 MenuItem viewGDBItem
1480 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1481 bool NotifySelect(MenuItem selection, Modifiers mods)
1488 MenuDivider { viewMenu };
1489 MenuItem viewColorPicker
1491 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1492 bool NotifySelect(MenuItem selection, Modifiers mods)
1494 ColorPicker colorPicker { master = this };
1495 colorPicker.Modal();
1499 MenuDivider { viewMenu };
1503 viewMenu, "Full Screen", f, checkable = true;
1505 bool NotifySelect(MenuItem selection, Modifiers mods)
1507 app.fullScreen ^= true;
1509 anchor = { 0, 0, 0, 0 };
1514 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1516 MenuDivider { viewMenu };
1518 Menu languageMenu { viewMenu, "Language", l };
1520 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1521 Menu windowMenu { menu, $"Window", w };
1522 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1523 MenuDivider { windowMenu };
1524 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1525 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1526 MenuDivider { windowMenu };
1527 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1528 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1529 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1530 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1531 MenuDivider { windowMenu };
1532 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1533 Menu helpMenu { menu, $"Help", h };
1536 helpMenu, $"API Reference", r, f1;
1537 bool NotifySelect(MenuItem selection, Modifiers mods)
1541 char * p = new char[MAX_LOCATION];
1543 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1544 PathCat(p, "documentor");
1545 #if defined(__WIN32__)
1546 ChangeExtension(p, "exe", p);
1548 if(!FileExists(p).isFile)
1549 strcpy(p, "documentor");
1551 documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
1556 Process_ShowWindows(documentor.GetProcessID());
1557 // documentor.Puts("Activate\n");
1562 MenuDivider { helpMenu };
1565 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1566 bool NotifySelect(MenuItem selection, Modifiers mods)
1568 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1572 MenuDivider { helpMenu };
1575 helpMenu, $"Documentation Folder", d;
1576 bool NotifySelect(MenuItem selection, Modifiers mods)
1578 FindAndShellOpenInstalledFolder("doc");
1584 helpMenu, $"Samples Folder", s;
1585 bool NotifySelect(MenuItem selection, Modifiers mods)
1587 FindAndShellOpenInstalledFolder("samples");
1593 helpMenu, $"Extras Folder", x;
1594 bool NotifySelect(MenuItem selection, Modifiers mods)
1596 FindAndShellOpenInstalledFolder("extras");
1600 MenuDivider { helpMenu };
1603 helpMenu, $"Community Forums", f;
1604 bool NotifySelect(MenuItem selection, Modifiers mods)
1606 ShellOpen("http://ecere.com/forums");
1610 MenuDivider { helpMenu };
1613 helpMenu, $"About...", a;
1614 bool NotifySelect(MenuItem selection, Modifiers mods)
1616 AboutIDE { master = this }.Modal();
1621 property ToolBox toolBox
1623 get { return toolBox; }
1626 property Sheet sheet
1628 get { return sheet; }
1631 property Project project
1633 get { return projectView ? projectView.project : null; }
1636 property Workspace workspace
1638 get { return projectView ? projectView.workspace : null; }
1641 FindInFilesDialog findInFilesDialog
1644 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1651 #ifdef GDB_DEBUG_GUI
1654 master = this, parent = this;
1655 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1657 void OnCommand(const char * string)
1660 ide.debugger.SendGDBCommand(string);
1665 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1667 //app.driver = app.drivers[selection.id];
1668 #if defined(__unix__) || defined(__APPLE__)
1669 app.driver = selection.id ? "OpenGL" : "X";
1671 app.driver = selection.id ? "OpenGL" : "GDI";
1673 delete ideSettings.displayDriver;
1674 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1676 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1678 settingsContainer.Save();
1679 //SetDriverAndSkin();
1683 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1685 app.skin = app.skins[selection.id];
1690 void SetDriverAndSkin()
1693 for(c = 0; c < app.numSkins; c++)
1694 if(!strcmp(app.skins[c], app.skin))
1696 skinItems[c].checked = true;
1699 for(c = 0; c < app.numDrivers; c++)
1700 if(!strcmp(app.drivers[c], app.driver))
1702 driverItems[c].checked = true;
1707 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1709 Project project = workspace.projects.firstIterator.data;
1710 projectView = ProjectView
1713 fileName = fileName;
1715 void NotifyDestroyed(Window window, DialogResult result)
1718 text = titleECEREIDE;
1723 projectView.Create();
1724 RepositionWindows(false);
1726 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1727 projectView.workspace = workspace;
1728 projectView.project = project;
1729 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1732 updateRecentMenus();
1734 ide.breakpointsView.LoadFromWorkspace();
1735 ide.watchesView.LoadFromWorkspace();
1737 findInFilesDialog.projectNodeField.userData = projectView;
1740 char fileName[MAX_LOCATION];
1741 strcpy(fileName, project.topNode.path);
1742 PathCat(fileName, project.topNode.name);
1749 projectView.visible = false;
1750 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1752 if(findInFilesDialog)
1754 char workingDir[MAX_LOCATION];
1755 GetWorkingDir(workingDir, MAX_LOCATION);
1756 findInFilesDialog.SearchStop();
1757 findInFilesDialog.currentDirectory = workingDir;
1759 sheet.visible = false;
1760 toolBox.visible = false;
1761 outputView.visible = false;
1762 ideMainFrame.text = titleECEREIDE;
1764 ide.updateRecentMenus();
1770 void RepositionWindows(bool expand)
1775 bool callStackVisible = expand ? false : callStackView.visible;
1776 bool threadsVisible = expand ? false : threadsView.visible;
1777 bool watchesVisible = expand ? false : watchesView.visible;
1778 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1779 bool toolBoxVisible = toolBox.visible;
1780 bool outputVisible = expand ? false : outputView.visible;
1781 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1782 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1784 for(child = firstChild; child; child = child.next)
1786 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1787 child._class == class(Sheet) || child._class == class(ProjectView))
1789 Anchor anchor = child.anchor;
1790 anchor.top = topDistance;
1791 anchor.bottom = bottomDistance;
1792 if(child._class == class(CodeEditor) || child._class == class(Designer))
1794 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1795 anchor.right = toolBoxVisible ? 150 : 0;
1798 child.anchor = anchor;
1802 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1803 child._class == class(BreakpointsView))
1804 child.visible = false;
1807 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1809 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1813 bool ShowCodeEditor()
1816 activeClient.Activate();
1817 else if(projectView)
1819 projectView.visible = true;
1820 projectView.Activate();
1822 else if(sheet.visible)
1825 outputView.visible = false;
1829 void DocumentSaved(Window document, const char * fileName)
1831 ideConfig.recentFiles.addRecent(fileName);
1832 ide.updateRecentFilesMenu();
1833 ide.AdjustFileMenus();
1836 bool Window::OnFileModified(FileChange fileChange, const char * param)
1839 sprintf(temp, $"The document %s was modified by another application.\n"
1840 "Would you like to reload it and lose your changes?", this.fileName);
1841 if(MessageBox { creationActivation = flash, type = yesNo, master = this/*.parent*/,
1842 text = $"Document has been modified", contents = temp }.Modal() == yes)
1844 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1845 char * fileName = CopyString(this.fileName);
1846 WindowState state = this.state;
1847 Anchor anchor = this.anchor;
1848 Size size = this.size;
1850 this.modifiedDocument = false;
1852 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1855 this.anchor = anchor;
1857 this.SetState(state, true, 0);
1865 void UpdateMakefiles()
1869 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
1870 for(prj : workspace.projects)
1871 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1876 void UpdateCompilerConfigs(bool mute)
1878 UpdateToolBarActiveCompilers();
1881 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1882 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
1885 projectView.ShowOutputBuildLog(true);
1886 projectView.DisplayCompiler(compiler, false);
1888 for(prj : workspace.projects)
1889 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1894 void UpdateToolBarActiveCompilers()
1896 toolBar.activeCompiler.Clear();
1897 for(compiler : ideConfig.compilers)
1899 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1900 if(workspace && workspace.activeCompiler && !strcmp(compiler.name, workspace.activeCompiler))
1901 toolBar.activeCompiler.currentRow = row;
1903 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1904 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1905 toolBar.activeBitDepth.SelectRow(toolBar.activeBitDepth.FindRow(workspace ? workspace.bitDepth : 0));
1908 void UpdateToolBarActiveConfigs(bool selectionOnly)
1910 bool commonSelected = false;
1911 DataRow row = toolBar.activeConfig.currentRow;
1913 row = toolBar.activeConfig.FindRow(1);
1916 toolBar.activeConfig.Clear();
1917 row = toolBar.activeConfig.AddString($"(Mixed)");
1922 char * configName = null;
1925 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1926 for(prj : workspace.projects)
1928 for(cfg : prj.configurations)
1931 configs[cfg.name] = 1;
1936 toolBar.activeConfig.AddString(&name);
1940 if(projectView && projectView.project)
1942 for(prj : workspace.projects)
1944 if(prj.config && prj.config.name)
1946 configName = prj.config.name;
1952 commonSelected = true;
1953 for(prj : workspace.projects)
1955 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1957 commonSelected = false;
1965 commonSelected = false;
1966 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1968 if(!strcmp(row.string, configName))
1970 toolBar.activeConfig.currentRow = row;
1971 commonSelected = true;
1978 toolBar.activeConfig.Sort(null, 0);
1980 toolBar.activeConfig.currentRow = row;
1985 bool unavailable = !project;
1987 projectAddItem.disabled = unavailable;
1988 toolBar.buttonAddProject.disabled = unavailable;
1990 projectSettingsItem.disabled = unavailable;
1992 projectBrowseFolderItem.disabled = unavailable;
1994 viewProjectItem.disabled = unavailable;
1996 toolBar.activeConfig.disabled = unavailable;
1997 toolBar.activeCompiler.disabled = unavailable;
1998 toolBar.activeBitDepth.disabled = unavailable;
2001 debugUseValgrindItem.disabled = unavailable;
2002 AdjustValgrindMenus();
2011 void AdjustValgrindMenus()
2013 bool unavailable = !project || !debugUseValgrindItem.checked;
2014 debugValgrindNoLeakCheckItem.disabled = unavailable;
2015 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2016 debugValgrindYesLeakCheckItem.disabled = unavailable;
2017 debugValgrindFullLeakCheckItem.disabled = unavailable;
2019 debugValgrindTrackOriginsItem.disabled = unavailable;
2021 debugValgrindRSDefaultItem.disabled = unavailable;
2022 debugValgrindRS0Item.disabled = unavailable;
2023 debugValgrindRS16Item.disabled = unavailable;
2024 debugValgrindRS32Item.disabled = unavailable;
2025 debugValgrindRS64Item.disabled = unavailable;
2026 debugValgrindRS128Item.disabled = unavailable;
2027 debugValgrindRS256Item.disabled = unavailable;
2028 debugValgrindRS512Item.disabled = unavailable;
2032 property bool hasOpenedCodeEditors
2037 for(w = firstChild; w; w = w.next)
2038 if(w._class == class(CodeEditor) &&
2039 w.isDocument && !w.closing && w.visible && w.created &&
2040 w.fileName && w.fileName[0])
2046 void AdjustFileMenus()
2048 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2050 projectQuickItem.disabled = unavailable;
2053 void AdjustBuildMenus()
2055 bool unavailable = project && projectView.buildInProgress;
2056 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2057 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2059 projectNewItem.disabled = unavailable;
2060 toolBar.buttonNewProject.disabled = unavailable;
2061 projectOpenItem.disabled = unavailable;
2062 toolBar.buttonOpenProject.disabled = unavailable;
2064 unavailable = !project || projectView.buildInProgress;
2066 projectCloseItem.disabled = unavailable;
2067 // toolBar.buttonCloseProject.disabled = unavailable;
2069 projectRunItem.disabled = naForRun;
2070 toolBar.buttonRun.disabled = naForRun;
2072 projectBuildItem.disabled = false;
2073 projectBuildItem.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2074 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2076 projectLinkItem.disabled = unavailable;
2077 toolBar.buttonReLink.disabled = unavailable;
2078 projectRebuildItem.disabled = unavailable;
2079 toolBar.buttonRebuild.disabled = unavailable;
2080 projectCleanItem.disabled = unavailable;
2081 toolBar.buttonClean.disabled = unavailable;
2082 projectCleanTargetItem.disabled = unavailable;
2083 projectRealCleanItem.disabled = unavailable;
2084 // toolBar.buttonRealClean.disabled = unavailable;
2085 projectRegenerateItem.disabled = unavailable;
2086 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2087 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2088 projectInstallItem.disabled = unavailable;
2089 toolBar.buttonInstall.disabled = unavailable;
2091 projectCompileItem.disabled = unavailable;
2093 AdjustPopupBuildMenus();
2096 void AdjustPopupBuildMenus()
2098 bool unavailable = !project || projectView.buildInProgress;
2100 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2103 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2104 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, mode);
2107 menu.disabled = false;
2108 menu.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2109 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2112 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, mode); if(menu) menu.disabled = unavailable;
2113 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, mode); if(menu) menu.disabled = unavailable;
2114 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, mode); if(menu) menu.disabled = unavailable;
2115 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, mode); if(menu) menu.disabled = unavailable;
2116 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, mode); if(menu) menu.disabled = unavailable;
2117 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, mode); if(menu) menu.disabled = unavailable;
2118 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, mode); if(menu) menu.disabled = unavailable;
2119 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, mode); if(menu) menu.disabled = unavailable;
2120 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, mode); if(menu) menu.disabled = unavailable;
2121 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, mode); if(menu) menu.disabled = unavailable;
2122 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, mode); if(menu) menu.disabled = unavailable;
2123 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, mode); if(menu) menu.disabled = unavailable;
2124 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, mode); if(menu) menu.disabled = unavailable;
2125 projectView.popupMenu.Update(null);
2129 property bool areDebugMenusUnavailable { get {
2131 project.GetTargetType(project.config) != executable ||
2132 projectView.buildInProgress == buildingMainProject;
2135 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2136 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2137 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2139 void AdjustDebugMenus()
2141 bool unavailable = areDebugMenusUnavailable;
2142 bool running = isDebuggerRunning;
2143 bool stopped = isDebuggerStopped;
2144 bool active = debugger.isActive;
2146 bool isNotRunning = unavailable || !running;
2147 bool isNotNotRunning = unavailable || running;
2148 bool isNotStopped = unavailable || !stopped;
2149 bool isNotActive = unavailable || !active;
2151 debugStartResumeItem.disabled = isNotNotRunning;
2152 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2153 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2156 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2157 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2160 debugBreakItem.disabled = isNotRunning;
2161 debugStopItem.disabled = isNotActive;
2162 debugRestartItem.disabled = isNotActive;
2165 toolBar.buttonDebugPause.disabled = isNotRunning;
2166 toolBar.buttonDebugStop.disabled = isNotActive;
2167 toolBar.buttonDebugRestart.disabled = isNotActive;
2170 debugStepIntoItem.disabled = isNotNotRunning;
2171 debugStepOverItem.disabled = isNotNotRunning;
2172 debugSkipStepOverItem.disabled = isNotNotRunning;
2173 debugStepOutItem.disabled = isNotStopped;
2174 debugSkipStepOutItem.disabled = isNotStopped;
2176 debugStepUntilItem.disabled = isNotStopped;
2177 debugSkipStepUntilItem.disabled = isNotStopped;
2181 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2182 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2183 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2184 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2185 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2187 if((Designer)GetActiveDesigner())
2189 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2191 codeEditor.AdjustDebugMenus();
2195 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2197 char tempString[MAX_LOCATION];
2198 strcpy(tempString, directory);
2199 if(saveSettings && !projectView)
2201 ideSettings.ideFileDialogLocation = directory;
2202 settingsContainer.Save();
2205 ideFileDialog.currentDirectory = tempString;
2206 codeEditorFileDialog.currentDirectory = tempString;
2207 codeEditorFormFileDialog.currentDirectory = tempString;
2210 void ChangeProjectFileDialogDirectory(char * directory)
2212 ideSettings.ideProjectFileDialogLocation = directory;
2213 settingsContainer.Save();
2216 Window FindWindow(const char * filePath)
2218 Window document = null;
2220 // TOCHECK: Do we need to change slashes here?
2221 for(document = firstChild; document; document = document.next)
2223 const char * fileName = document.fileName;
2224 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2226 document.visible = true;
2227 document.Activate();
2234 bool DontTerminateDebugSession(const char * title)
2236 if(debugger.isActive)
2238 if(MessageBox { type = yesNo, master = ide,
2239 contents = $"Do you want to terminate the debugging session in progress?",
2240 text = title }.Modal() == no)
2243 MessageBox msg { type = yesNo, master = ide,
2244 contents = "Do you want to terminate the debugging session in progress?",
2246 if(msg.Modal() == no)
2258 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2260 char extension[MAX_EXTENSION] = "";
2261 Window document = null;
2262 bool isProject = false;
2263 bool needFileModified = true;
2264 char winFilePath[MAX_LOCATION];
2265 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2266 Window currentDoc = activeClient;
2267 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2270 GetExtension(filePath, extension);
2274 strcpy(extension, type);
2276 if(strcmp(extension, ProjectExtension))
2278 for(document = firstChild; document; document = document.next)
2280 const char * fileName = document.fileName;
2281 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2283 document.visible = true;
2285 document.Activate();
2291 if(createIfFails == whatever)
2293 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2295 needFileModified = false;
2296 if(openMethod == normal)
2298 if(DontTerminateDebugSession($"Open Project"))
2307 Workspace workspace = null;
2309 if(FileExists(filePath))
2311 if(!strcmp(extension, ProjectExtension))
2313 char workspaceFile[MAX_LOCATION];
2314 strcpy(workspaceFile, filePath);
2315 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2316 workspace = LoadWorkspace(workspaceFile, filePath);
2318 else if(!strcmp(extension, WorkspaceExtension))
2319 workspace = LoadWorkspace(filePath, null);
2326 CreateProjectView(workspace, filePath);
2327 document = projectView;
2329 toolBox.visible = true;
2330 sheet.visible = true;
2331 projectView.MakeActive();
2333 workspace.ParseLoadedBreakpoints();
2334 workspace.DropInvalidBreakpoints(null);
2337 ide.projectView.ShowOutputBuildLog(true);
2339 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler);
2340 ide.projectView.DisplayCompiler(compiler, false);
2343 UpdateCompilerConfigs(false);
2346 char newWorkingDir[MAX_LOCATION];
2347 StripLastDirectory(filePath, newWorkingDir);
2348 ChangeFileDialogsDirectory(newWorkingDir, false);
2351 document.fileName = filePath;
2353 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2355 // this crashes on starting ide with epj file, solution please?
2356 // app.UpdateDisplay();
2358 workspace.OpenPreviouslyOpenedFiles(noParsing);
2359 workspace.holdTracking = true;
2360 ide.RepositionWindows(false);
2361 workspace.holdTracking = false;
2363 workspace.timer.Start();
2365 #if !defined(__WIN32__)
2366 // Valgrind Debug menu updates
2367 debugUseValgrindItem.checked = workspace.useValgrind;
2369 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2370 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2371 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2372 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2374 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2375 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2376 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2377 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2378 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2379 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2380 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2381 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2383 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2386 findInFilesDialog.mode = FindInFilesMode::project;
2387 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2390 char location[MAX_LOCATION];
2391 StripLastDirectory(ide.project.topNode.path, location);
2392 ChangeProjectFileDialogDirectory(location);
2399 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2401 ideProjectFileDialog.text = openProjectFileDialogTitle;
2402 if(ideProjectFileDialog.Modal() == cancel)
2404 filePath = ideProjectFileDialog.filePath;
2405 GetExtension(filePath, extension);
2416 else if(openMethod == add)
2421 char slashFilePath[MAX_LOCATION];
2422 GetSlashPathBuffer(slashFilePath, filePath);
2423 for(p : workspace.projects)
2425 if(!fstrcmp(p.filePath, slashFilePath))
2433 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2434 contents = $"This project is already present in workspace." }.Modal();
2438 prj = LoadProject(filePath, null);
2441 const char * activeConfigName = null;
2442 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
2443 prj.StartMonitoring();
2444 workspace.AddProject(prj, null);
2445 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2446 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2447 activeConfigName = toolBar.activeConfig.currentRow.string;
2448 if(activeConfigName)
2450 for(cfg : prj.configurations)
2452 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2460 projectView.AddNode(prj.topNode, null);
2461 workspace.modified = true;
2463 findInFilesDialog.AddProjectItem(prj);
2464 projectView.ShowOutputBuildLog(true);
2465 projectView.DisplayCompiler(compiler, false);
2466 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2470 char location[MAX_LOCATION];
2471 StripLastDirectory(prj.topNode.path, location);
2472 ChangeProjectFileDialogDirectory(location);
2475 // projectView is associated with the main project and not with the one just added but
2476 return projectView; // just to let the caller know something was opened
2484 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2485 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2486 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2488 if(FileExists(filePath))
2489 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2490 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2491 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2494 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2497 else if(!strcmp(extension, "3ds"))
2499 if(FileExists(filePath))
2500 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2501 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2502 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2506 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2509 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2510 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2511 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2512 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2513 !strcmp(extension, "js"))
2515 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2516 editor.updatingCode = true;
2517 if(editor.LoadFile(filePath))
2520 editor.visible = true;
2524 needFileModified = false;
2528 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2529 if(editor.LoadFile(filePath))
2532 editor.visible = true;
2536 needFileModified = false;
2539 if(document && (document._class == class(PictureEdit) ||
2540 document._class == class(ModelView)))
2545 document.fileName = filePath;
2546 if(workspace && !workspace.holdTracking)
2547 workspace.UpdateOpenedFileInfo(filePath, opened, true);
2551 if(!document && createIfFails != no)
2553 if(createIfFails != yes && !needFileModified &&
2554 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2555 createIfFails = yes;
2556 if(createIfFails == yes || createIfFails == whatever)
2558 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2560 document.fileName = filePath;
2566 if(projectView && document._class == class(CodeEditor) && workspace)
2567 workspace.RestorePreviouslyOpenedFileState((CodeEditor)document);
2569 if(needFileModified)
2570 document.OnFileModified = OnFileModified;
2571 document.NotifySaved = DocumentSaved;
2572 if(maximizeDoc && document.hasMaximize)
2573 document.state = maximized;
2577 ideConfig.recentWorkspaces.addRecent(document.fileName);
2578 ide.updateRecentProjectsMenu();
2581 workspace.recentFiles.addRecent(document.fileName);
2583 ideConfig.recentFiles.addRecent(document.fileName);
2584 ide.updateRecentFilesMenu();
2585 ide.AdjustFileMenus();
2592 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2593 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2595 if(!parentClosing && ide.workspace)
2596 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2599 bool ModelView::ModelViewOnClose(bool parentClosing)
2601 if(!parentClosing && ide.workspace)
2602 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2605 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2607 if(!parentClosing && ide.workspace)
2608 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2613 void OnUnloadGraphics(Window window)
2615 display.ClearMaterials();
2616 display.ClearTextures();
2617 display.ClearMeshes();
2621 void UpdateStateLight(StatusField fld, bool on)
2623 fld.color = on ? lime : Color { 128,128,128 };
2624 fld.backColor = on ? dimGray : 0;
2628 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2630 UpdateStateLight(caps, app.GetKeyState(capsState));
2631 UpdateStateLight(num, app.GetKeyState(numState));
2635 bool OnKeyDown(Key key, unichar ch)
2639 case b: projectView.Update(null); break;
2640 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2641 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2646 bool OnKeyUp(Key key, unichar ch)
2650 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2651 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2656 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2659 projectView.GoToError(line, noParsing, objectFileExt);
2662 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2664 FileAttribs result { };
2665 FileAttribs fileAttribs;
2669 strcpy(selectedPath, prj.topNode.path);
2670 else if(dir && dir[0])
2671 strcpy(selectedPath, dir);
2673 selectedPath[0] = '\0';
2674 PathCat(selectedPath, filePath);
2676 if((fileAttribs = FileExists(selectedPath)).isFile)
2677 result = fileAttribs;
2681 for(p : workspace.projects)
2683 strcpy(selectedPath, p.topNode.path);
2684 PathCat(selectedPath, filePath);
2685 if((fileAttribs = FileExists(selectedPath)).isFile)
2688 result = fileAttribs;
2695 ProjectNode n = null;
2696 for(p : workspace.projects)
2698 if((n = p.topNode.Find(filePath, false)))
2700 n.GetFullFilePath(selectedPath, true);
2701 if((fileAttribs = FileExists(selectedPath)).isFile)
2704 result = fileAttribs;
2709 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2710 (fileAttribs = FileExists(selectedPath)).isFile)
2713 result = fileAttribs;
2721 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2724 const char *path = text;
2725 char *colon = strchr(text, ':');
2726 char filePath[MAX_LOCATION] = "";
2727 char completePath[MAX_LOCATION];
2728 int line = 0, col = 0;
2729 int len = strlen(text);
2731 FileAttribs fileAttribs;
2733 // support for valgrind output
2734 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2745 /*for(s=colon; *s; s++)
2754 //line = atoi(colon+1);
2756 // support for "Found n match(es) in "file/path";
2757 else if(len > 0 && path[len-1] == '\"' && strstr(path, $"Found %d match%s in \"%s\"%s\n\n"."Found") && strstr(path, $"match") && strstr(path, $"in") && (s = strstr(path, "\"")) && s != path+len-1)
2763 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2765 path = (colon - 1 > path) ? colon - 1 : path;
2766 colon = strstr(colon + 1, ":");
2768 if(*path == '*' && (s = strchr(path+1, '*')))
2770 while(isspace(*path)) path++;
2774 char * close = strchr(path, ')');
2778 strncpy(name, path+1, close - path - 1);
2779 name[close - path - 1] = '\0';
2780 for(p : ide.workspace.projects)
2782 if(!strcmp(p.name, name))
2792 prj = project ? project : (dir ? null : ide.project);
2795 strncpy(filePath, path, colon - path);
2796 filePath[colon - path] = '\0';
2797 line = atoi(colon + 1);
2798 colon = strstr(colon + 1, ":");
2800 col = atoi(colon + 1);
2802 else if(path - 1 >= text && *(path - 1) == '\"')
2804 colon = strchr(path, '\"');
2807 strncpy(filePath, path, colon - path);
2808 filePath[colon - path] = '\0';
2811 else if(path && !colon)
2813 strcpy(filePath, path);
2816 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2817 CodeLocationGoTo(completePath, fileAttribs, line, col);
2820 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2822 if(fileAttribs.isFile)
2824 char ext[MAX_EXTENSION];
2825 GetExtension(path, ext);
2827 if(binaryDocExt.Find(ext))
2829 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2830 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2832 char dirPath[MAX_LOCATION];
2833 StripLastDirectory(path, dirPath);
2838 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2839 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2841 EditBox editBox = codeEditor.editBox;
2842 editBox.GoToLineNum(line - 1);
2843 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2847 else if(fileAttribs.isDirectory)
2851 void OnRedraw(Surface surface)
2853 Bitmap bitmap = back.bitmap;
2855 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2858 void SheetSelected(SheetType sheetSelected)
2860 if(activeChild == sheet)
2862 if(sheetSelected == methods)
2864 viewPropertiesItem.accelerator = f4;
2865 viewPropertiesItem.parent = viewMenu;
2866 viewMethodsItem.parent = null;
2870 viewMethodsItem.accelerator = f4;
2871 viewMethodsItem.parent = viewMenu;
2872 viewPropertiesItem.parent = null;
2877 viewMethodsItem.parent = viewMenu;
2878 viewPropertiesItem.parent = viewMenu;
2879 if(sheetSelected == methods)
2881 viewMethodsItem.accelerator = f4;
2882 viewPropertiesItem.accelerator = 0;
2886 viewMethodsItem.accelerator = 0;
2887 viewPropertiesItem.accelerator = f4;
2892 void OnActivateClient(Window client, Window previous)
2894 //if(!client || client != previous)
2897 if(!client || client != previous)
2900 dataType = previous._class;
2901 if(previous && !strcmp(dataType.name, "CodeEditor"))
2903 ((CodeEditor)previous).UpdateFormCode();
2905 else if(previous && !strcmp(dataType.name, "Designer"))
2907 ((Designer)previous).codeEditor.UpdateFormCode();
2912 dataType = client._class;
2913 if(client && !strcmp(dataType.name, "CodeEditor"))
2915 CodeEditor codeEditor = (CodeEditor)client;
2916 SetPrivateModule(codeEditor.privateModule);
2917 SetCurrentContext(codeEditor.globalContext);
2918 SetTopContext(codeEditor.globalContext);
2919 SetGlobalContext(codeEditor.globalContext);
2921 SetDefines(&codeEditor.defines);
2922 SetImports(&codeEditor.imports);
2924 SetActiveDesigner(codeEditor.designer);
2926 sheet.codeEditor = codeEditor;
2927 toolBox.codeEditor = codeEditor;
2929 viewDesignerItem.parent = viewMenu;
2930 if(activeChild != codeEditor)
2932 viewCodeItem.parent = viewMenu;
2933 viewDesignerItem.accelerator = 0;
2934 viewCodeItem.accelerator = f8;
2938 viewCodeItem.parent = null;
2939 viewDesignerItem.accelerator = f8;
2942 else if(client && !strcmp(dataType.name, "Designer"))
2944 CodeEditor codeEditor = ((Designer)client).codeEditor;
2947 SetPrivateModule(codeEditor.privateModule);
2948 SetCurrentContext(codeEditor.globalContext);
2949 SetTopContext(codeEditor.globalContext);
2950 SetGlobalContext(codeEditor.globalContext);
2951 SetDefines(&codeEditor.defines);
2952 SetImports(&codeEditor.imports);
2956 SetPrivateModule(null);
2957 SetCurrentContext(null);
2958 SetTopContext(null);
2959 SetGlobalContext(null);
2964 SetActiveDesigner((Designer)client);
2966 sheet.codeEditor = codeEditor;
2967 toolBox.codeEditor = codeEditor;
2969 viewCodeItem.parent = viewMenu;
2970 if(activeChild != client)
2972 viewDesignerItem.parent = viewMenu;
2973 viewDesignerItem.accelerator = f8;
2974 viewCodeItem.accelerator = 0;
2978 viewDesignerItem.parent = null;
2979 viewCodeItem.accelerator = f8;
2984 if(!client && !projectView && sheet.visible)
2987 sheet.visible = false;
2988 toolBox.visible = false;
2991 sheet.codeEditor = null;
2992 toolBox.codeEditor = null;
2993 SetActiveDesigner(null);
2995 viewDesignerItem.parent = null;
2996 viewCodeItem.parent = null;
2999 SheetSelected(sheet.sheetSelected);
3002 projectCompileItem = null;
3007 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3009 CodeEditor codeEditor = (CodeEditor)client;
3010 EditBox editBox = codeEditor.editBox;
3012 statusBar.AddField(pos);
3014 caps = { width = 40, text = $"CAPS" };
3015 statusBar.AddField(caps);
3016 UpdateStateLight(caps, app.GetKeyState(capsState));
3018 ovr = { width = 36, text = $"OVR" };
3019 statusBar.AddField(ovr);
3020 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3022 num = { width = 36, text = $"NUM" };
3023 statusBar.AddField(num);
3024 UpdateStateLight(num, app.GetKeyState(numState));
3026 //statusBar.text = "Ready";
3028 if(projectView && projectView.project)
3030 bool isCObject = false;
3031 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3032 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3036 char nodeName[MAX_FILENAME];
3037 char name[MAX_FILENAME+96];
3039 ChangeExtension(node.name, "c", nodeName);
3040 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3041 projectCompileItem =
3043 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3045 bool NotifySelect(MenuItem selection, Modifiers mods)
3049 bool isCObject = false;
3050 bool isExcluded = false;
3051 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3055 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3058 List<ProjectNode> nodes { };
3060 projectView.Compile(node.project, nodes, normal, isCObject ? cObject : normal);
3068 projectMenu.AddDynamic(projectCompileItem, ide, false);
3074 caps = ovr = num = null;
3079 bool OnClose(bool parentClosing)
3081 //return !projectView.buildInProgress;
3082 if(projectView && projectView.buildInProgress)
3084 if(DontTerminateDebugSession($"Close IDE"))
3086 if(findInFilesDialog)
3087 findInFilesDialog.SearchStop();
3090 workspace.timer.Stop();
3093 ideMainFrame.Destroy(0);
3100 bool passThrough = false;
3101 bool debugWorkDir = false;
3102 char * passDebugWorkDir = null;
3103 bool openAsText = false;
3104 DynamicString passArgs { };
3107 for(c = 1; c<app.argc; c++)
3111 const char * arg = app.argv[c];
3112 char * buf = new char[strlen(arg)*2+1];
3114 passArgs.concat(" ");
3116 passArgs.concat(buf);
3119 else if(debugWorkDir)
3121 passDebugWorkDir = CopyString(app.argv[c]);
3122 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3123 debugWorkDir = false;
3125 else if(!strcmp(app.argv[c], "-t"))
3127 else if(!strcmp(app.argv[c], "-no-parsing"))
3128 ide.noParsing = true;
3129 else if(!strcmp(app.argv[c], "-debug-start"))
3130 ide.debugStart = true;
3131 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3132 debugWorkDir = true;
3133 else if(!strcmp(app.argv[c], "-@"))
3137 char fullPath[MAX_LOCATION];
3138 char parentPath[MAX_LOCATION];
3139 char ext[MAX_EXTENSION];
3141 FileAttribs dirAttribs;
3142 GetWorkingDir(fullPath, MAX_LOCATION);
3143 PathCat(fullPath, app.argv[c]);
3144 StripLastDirectory(fullPath, parentPath);
3145 GetExtension(app.argv[c], ext);
3146 isProject = !openAsText && !strcmpi(ext, "epj");
3148 if(isProject && c > 1 + (ide.debugStart ? 1 : 0)) continue;
3150 // Create directory for projects (only)
3151 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3153 if(isProject && !FileExists(fullPath))
3155 char name[MAX_LOCATION];
3156 NewProjectDialog newProjectDialog;
3160 projectView.visible = false;
3161 if(!projectView.Destroy(0))
3165 newProjectDialog = { master = this };
3167 strcpy(name, app.argv[c]);
3168 StripExtension(name);
3169 GetLastDirectory(name, name);
3170 newProjectDialog.projectName.contents = name;
3171 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3172 newProjectDialog.locationEditBox.path = parentPath;
3173 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3175 incref newProjectDialog;
3176 newProjectDialog.Modal();
3179 ideConfig.recentWorkspaces.addRecent(projectView.fileName);
3180 ide.updateRecentMenus();
3182 delete newProjectDialog;
3183 // Open only one project
3187 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3189 else if(strstr(fullPath, "http://") == fullPath)
3190 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3193 if(passThrough && projectView && projectView.project && workspace)
3194 workspace.commandLineArgs = passArgs;
3195 if(passDebugWorkDir && projectView && projectView.project && workspace)
3197 workspace.debugDir = passDebugWorkDir;
3198 delete passDebugWorkDir;
3201 UpdateToolBarActiveConfigs(false);
3202 UpdateToolBarActiveCompilers();
3209 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3212 projectView.visible = false;
3213 projectView.Destroy(0);
3216 #ifdef GDB_DEBUG_GUI
3217 gdbDialog.Destroy(0);
3222 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3226 char * oldPaths[128];
3227 String oldList = new char[maxPathLen];
3228 Array<String> newExePaths { };
3229 //Map<String, bool> exePathExists { };
3231 #if defined(__unix__) || defined(__APPLE__)
3232 Array<String> newLibPaths { };
3233 Map<String, bool> libPathExists { };
3238 for(prj : workspace.projects)
3240 DirExpression targetDirExp;
3242 // SKIP FIRST PROJECT...
3243 if(prj == workspace.projects.firstIterator.data) continue;
3245 // NOTE: Right now the additional project config dir will be
3246 // obtained when the debugger is started, so toggling it
3247 // while building will change which library gets used.
3248 // To go with the initial state, e.g. when F5 was pressed,
3249 // we nould need to keep a list of all project's active
3250 // config upon startup.
3251 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3253 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3257 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3258 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3262 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3263 if(cfg.targetType == sharedLibrary && cfg.debug)
3267 if(targetDirExp.dir)
3269 char buffer[MAX_LOCATION];
3270 #if defined(__WIN32__)
3271 Array<String> paths = newExePaths;
3273 Array<String> paths = newLibPaths;
3275 GetSystemPathBuffer(buffer, prj.topNode.path);
3276 PathCat(buffer, targetDirExp.dir);
3279 if(!fstrcmp(p, buffer))
3286 paths.Add(CopyString(buffer));
3288 delete targetDirExp;
3292 for(item : compiler.executableDirs)
3294 DirExpression dirExpr { };
3295 dirExpr.Evaluate(item, null, compiler, null, 0);
3298 for(p : newExePaths)
3300 if(!fstrcmp(p, dirExpr.dir))
3307 newExePaths.Add(CopySystemPath(dirExpr.dir));
3311 GetEnvironment("PATH", oldList, maxPathLen);
3313 printf("Old value of PATH: %s\n", oldList);
3315 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3316 for(c = 0; c < count; c++)
3319 for(p : newExePaths)
3321 if(!fstrcmp(p, oldPaths[c]))
3328 newExePaths.Add(CopySystemPath(oldPaths[c]));
3332 for(path : newExePaths)
3333 len += strlen(path) + 1;
3334 newList = new char[len + 1];
3336 for(path : newExePaths)
3338 strcat(newList, path);
3339 strcat(newList, pathListSep);
3341 newList[len - 1] = '\0';
3342 SetEnvironment("PATH", newList);
3344 printf("New value of PATH: %s\n", newList);
3351 #if defined(__unix__) || defined(__APPLE__)
3353 for(item : compiler.libraryDirs)
3355 if(!libPathExists[item]) // fstrcmp should be used
3357 String s = CopyString(item);
3359 libPathExists[s] = true;
3363 #if defined(__APPLE__)
3364 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3366 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3369 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3371 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3372 for(c = 0; c < count; c++)
3374 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3376 String s = CopyString(oldPaths[c]);
3378 libPathExists[s] = true;
3383 for(path : newLibPaths)
3384 len += strlen(path) + 1;
3385 newList = new char[len + 1];
3387 for(path : newLibPaths)
3389 strcat(newList, path);
3390 strcat(newList, pathListSep);
3392 newList[len - 1] = '\0';
3393 #if defined(__APPLE__)
3394 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3396 SetEnvironment("LD_LIBRARY_PATH", newList);
3399 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3405 delete libPathExists;
3408 if(compiler.distccEnabled && compiler.distccHosts)
3409 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3414 void DestroyTemporaryProjectDir()
3416 if(tmpPrjDir && tmpPrjDir[0])
3418 if(FileExists(tmpPrjDir).isDirectory)
3419 DestroyDir(tmpPrjDir);
3420 property::tmpPrjDir = null;
3426 // Graphics Driver Menu
3429 app.currentSkin.selectionColor = selectionColor;
3430 app.currentSkin.selectionText = selectionText;
3434 driverItems = new MenuItem[app.numDrivers];
3435 for(c = 0; c < app.numDrivers; c++)
3437 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3438 driverItems[c].id = c;
3439 driverItems[c].isRadio = true;
3442 driverItems = new MenuItem[2];
3443 #if defined(__unix__)
3444 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3445 driverItems[0].id = 0;
3446 driverItems[0].isRadio = true;
3448 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3449 driverItems[0].id = 0;
3450 driverItems[0].isRadio = true;
3452 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3453 driverItems[1].id = 1;
3454 driverItems[1].isRadio = true;
3456 /* skinItems = new MenuItem[app.numSkins];
3457 for(c = 0; c < app.numSkins; c++)
3459 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3460 skinItems[c].id = c;
3461 skinItems[c].isRadio = true;
3464 ideFileDialog.master = this;
3465 ideProjectFileDialog.master = this;
3467 //SetDriverAndSkin();
3471 void updateRecentMenus()
3473 updateRecentFilesMenu();
3474 updateRecentProjectsMenu();
3477 void updateRecentFilesMenu()
3480 char * itemPath = new char[MAX_LOCATION];
3481 char * itemName = new char[MAX_LOCATION+4];
3482 Workspace ws = workspace;
3483 RecentPaths recentFiles = ws ? ws.recentFiles : ideConfig.recentFiles;
3484 recentFilesMenu.Clear();
3485 for(recent : recentFiles)
3487 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3488 MakeSystemPath(itemPath);
3489 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3490 recentFilesMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3497 void updateRecentProjectsMenu()
3500 char * itemPath = new char[MAX_LOCATION];
3501 char * itemName = new char[MAX_LOCATION+4];
3502 recentProjectsMenu.Clear();
3503 for(recent : ideConfig.recentWorkspaces)
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 recentProjectsMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3519 delete languageItems;
3523 documentor.Puts("Quit\n");
3530 void DestroyDir(char * path)
3532 RecursiveDeleteFolderFSI fsi { };
3537 #if defined(__WIN32__)
3538 define sdkDirName = "Ecere SDK";
3540 define sdkDirName = "ecere";
3543 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3546 char * v = new char[maxPathLen];
3550 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3551 StripLastDirectory(path, path);
3552 PathCat(path, subDir);
3553 if(name) PathCat(path, name);
3554 if(FileExists(path) & attribs) found = true;
3556 #if defined(__WIN32__)
3559 for(s : [ "ECERE_SDK_SRC", "AppData", "ALLUSERSPROFILE", "USERPROFILE", "HOMEPATH", "ProgramData", "ProgramFiles", "ProgramFiles(x86)", "SystemDrive" ])
3561 GetEnvironment(s, v, maxPathLen);
3564 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3565 if(!strcmp(s, "SystemDrive"))
3566 PathCat(path, "Program Files");
3567 if(strcmp(s, "ECERE_SDK_SRC"))
3568 PathCat(path, sdkDirName);
3569 PathCat(path, subDir);
3570 if(name) PathCat(path, name);
3571 if(FileExists(path) & attribs)
3586 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3587 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3590 p = new char[MAX_LOCATION];
3592 strcat(p, "/usr/share");
3596 for(c=0; c<numTokens; c++)
3598 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3599 PathCat(path, sdkDirName);
3600 PathCat(path, subDir);
3602 PathCat(path, name);
3603 if(FileExists(path) & attribs)
3616 void FindAndShellOpenInstalledFolder(const char * name)
3618 char path[MAX_LOCATION];
3619 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3623 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3625 char path[MAX_LOCATION];
3626 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3630 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3632 bool preserveRootFolder;
3634 void OutFolder(const char * folderPath, bool isRoot)
3636 if(!(preserveRootFolder && isRoot))
3637 RemoveDir(folderPath);
3640 bool OnFile(const char * filePath)
3642 DeleteFile(filePath);
3647 class IDEApp : GuiApplication
3649 //driver = "Win32Console";
3650 // driver = "OpenGL";
3654 TempFile includeFile { };
3659 char ext[MAX_EXTENSION];
3660 SetLoggingMode(stdOut, null);
3661 //SetLoggingMode(debug, null);
3663 settingsContainer.Load();
3665 if(ideSettings.language)
3667 const String language = GetLanguageString();
3668 if(ideSettings.language.OnCompare(language))
3670 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3675 ideConfig.compilers.read();
3676 ideConfig.recentFiles.read();
3677 ideConfig.recentWorkspaces.read();
3679 // First count files arg to decide whether to maximize
3681 bool passThrough = false, debugWorkDir = false;
3684 for(c = 1; c<app.argc; c++)
3687 else if(debugWorkDir)
3688 debugWorkDir = false;
3689 else if(!strcmp(app.argv[c], "-t"));
3690 else if(!strcmp(app.argv[c], "-no-parsing"));
3691 else if(!strcmp(app.argv[c], "-debug-start"));
3692 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3693 debugWorkDir = true;
3694 else if(!strcmp(app.argv[c], "-@"))
3701 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3703 app.driver = "OpenGL";
3704 ide.driverItems[1].checked = true;
3708 #if defined(__unix__) || defined(__APPLE__)
3709 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3711 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3713 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3717 char model[MAX_LOCATION];
3718 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3720 ide.duck.modelFile = model;
3721 ide.duck.parent = ideMainFrame;
3724 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3725 ide.debugRubberDuck.disabled = false;
3729 desktop.caption = titleECEREIDE;
3732 for(c = 1; c<app.argc; c++)
3734 char fullPath[MAX_LOCATION];
3735 GetWorkingDir(fullPath, MAX_LOCATION);
3736 PathCat(fullPath, app.argv[c]);
3737 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3741 globalSettingsDialog.settingsContainer = settingsContainer;
3743 // Default to language specified by environment if no language selected
3744 if(!ideSettings.language)
3746 ideSettings.language = GetLanguageString();
3747 settingsContainer.Save();
3750 // Default to home directory if no directory yet set up
3751 if(!ideSettings.ideProjectFileDialogLocation[0])
3754 char location[MAX_LOCATION];
3755 char * home = getenv("HOME");
3756 char * homeDrive = getenv("HOMEDRIVE");
3757 char * homePath = getenv("HOMEPATH");
3758 char * userProfile = getenv("USERPROFILE");
3759 char * systemDrive = getenv("SystemDrive");
3760 if(home && FileExists(home).isDirectory)
3762 strcpy(location, home);
3765 if(!found && homeDrive && homePath)
3767 strcpy(location, homeDrive);
3768 PathCat(location, homePath);
3769 if(FileExists(location).isDirectory)
3772 if(!found && FileExists(userProfile).isDirectory)
3774 strcpy(location, userProfile);
3777 if(!found && FileExists(systemDrive).isDirectory)
3779 strcpy(location, systemDrive);
3784 ideSettings.ideProjectFileDialogLocation = location;
3785 if(!ideSettings.ideFileDialogLocation[0])
3786 ideSettings.ideFileDialogLocation = location;
3790 if(!LoadIncludeFile())
3791 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3793 // Create language menu
3795 String language = ideSettings.language;
3799 ide.languageItems = new MenuItem[languages.count];
3802 ide.languageItems[i] =
3804 ide.languageMenu, l.name;
3805 bitmap = { l.bitmap };
3809 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3811 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3813 // Re-select previous selected language if aborted
3814 String language = ideSettings.language;
3818 if(((!language || !language[0]) && i == 0) ||
3819 (language && !strcmpi(l.code, language)))
3821 ide.languageItems[i].checked = true;
3833 // Try to find country-specific language first
3839 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3841 ide.languageItems[i].checked = true;
3849 // Try generalizing locale
3850 if(!found && language)
3853 char genericLocale[256];
3855 strncpy(genericLocale, language, sizeof(genericLocale));
3856 genericLocale[sizeof(genericLocale)-1] = 0;
3858 under = strchr(genericLocale, '_');
3861 if(!strcmpi(genericLocale, "zh"))
3862 strcpy(genericLocale, "zh_CN");
3863 if(strcmp(genericLocale, language))
3867 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3869 ide.languageItems[i].checked = true;
3879 ide.languageItems[0].checked = true;
3881 MenuDivider { ide.languageMenu };
3884 ide.languageMenu, "Help Translate";
3886 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3888 ShellOpen("http://translations.launchpad.net/ecere");
3894 ideMainFrame.Create();
3895 if(app.argFilesCount > 1)
3896 ide.MenuWindowTileVert(null, 0);
3900 bool Cycle(bool idle)
3904 if(ide.documentor.Peek())
3907 ide.documentor.GetLine(line, sizeof(line));
3908 if(!strcmpi(line, "Exited"))
3910 ide.documentor.CloseInput();
3911 ide.documentor.CloseOutput();
3912 ide.documentor.Wait();
3913 delete ide.documentor;
3916 if(ide.documentor && ide.documentor.eof)
3918 ide.documentor.CloseInput();
3919 ide.documentor.CloseOutput();
3920 ide.documentor.Wait();
3921 delete ide.documentor;
3927 bool LoadIncludeFile()
3929 bool result = false;
3930 File include = FileOpen(":crossplatform.mk", read);
3933 File f = includeFile;
3936 for(; !include.Eof(); )
3939 int count = include.Read(buffer, 1, 4096);
3940 f.Write(buffer, 1, count);
3950 IDEMainFrame ideMainFrame { };
3952 define app = ((IDEApp)__thisModule);
3954 define titleECEREIDE = $"Ecere IDE (Debug)";
3956 define titleECEREIDE = $"Ecere IDE";