2 public import static "ecere"
3 public import static "ec"
9 import "GlobalSettingsDialog"
10 import "NewProjectDialog"
11 import "FindInFilesDialog"
18 import "ProjectConfig"
20 import "NodeProperties"
21 import "ProjectSettings"
33 import "BreakpointsView"
34 import "CallStackView"
45 import "FileSystemIterator"
47 AVLTree<const String> binaryDocExt
49 "wav", "mp3", "flac", "ogg",
51 "avi", "mkv", "mpg", "mpeg",
52 "7z", "zip", "gz", "bz2", "xz", "rar", "z", "tar", "ear",
53 "pdf", "odp", "ods", "odt", "ppt", "doc", "xls", "pptx", "docx", "xlsx"
56 #if defined(__WIN32__)
57 define pathListSep = ";";
59 define pathListSep = ":";
62 define maxPathLen = 65 * MAX_LOCATION;
64 class PathBackup : struct
71 oldPath = new char[maxPathLen];
72 oldLDPath = new char[maxPathLen];
74 GetEnvironment("PATH", oldPath, maxPathLen);
75 #if defined(__APPLE__)
76 GetEnvironment("DYLD_LIBRARY_PATH", oldLDPath, maxPathLen);
78 GetEnvironment("LD_LIBRARY_PATH", oldLDPath, maxPathLen);
84 SetEnvironment("PATH", oldPath);
85 #if defined(__APPLE__)
86 SetEnvironment("DYLD_LIBRARY_PATH", oldLDPath);
88 SetEnvironment("LD_LIBRARY_PATH", oldLDPath);
95 enum OpenCreateIfFails { no, yes, something, whatever };
96 enum OpenMethod { normal, add };
98 static Array<FileFilter> fileFilters
100 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
101 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
102 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
103 { $"Text files (*.txt, *.text, *.nfo, *.info)", "txt, text, nfo, info" },
104 { $"Web files (*.html, *.htm, *.xhtml, *.css, *.php, *.js, *.jsi, *.rb, *.xml)", "html, htm, xhtml, css, php, js, jsi, rb, xml" },
105 { $"Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", "jpg, jpeg, bmp, pcx, png, gif" },
106 { $"3D Studio Model Files (*.3ds)", "3ds" },
107 { $"All files", null }
110 static Array<FileType> fileTypes
112 { $"Based on extension", null },
115 { $"3D Studio Model", "3ds" }
118 static Array<FileFilter> projectFilters
120 { $"Project Files (*.epj)", ProjectExtension }
123 static Array<FileType> projectTypes
125 { $"Project File", ProjectExtension }
128 static Array<FileFilter> findInFilesFileFilters
130 { $"eC Files (*.ec, *.eh)", "ec, eh" },
131 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
132 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
133 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
134 { $"Text files (*.txt)", "txt" },
135 { $"All files", null }
138 FileDialog ideFileDialog
140 type = multiOpen, text = $"Open";
141 types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType), filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter);
144 define openProjectFileDialogTitle = $"Open Project";
145 define addProjectFileDialogTitle = $"Open Additional Project";
146 FileDialog ideProjectFileDialog
149 types = projectTypes.array, sizeTypes = projectTypes.count * sizeof(FileType), filters = projectFilters.array, sizeFilters = projectFilters.count * sizeof(FileFilter);
152 GlobalSettingsDialog globalSettingsDialog
154 ideSettings = ideSettings;
155 settingsContainer = settingsContainer;
157 void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange)
159 switch(globalSettingsChange)
164 for(child = ide.firstChild; child; child = child.next)
166 if(child._class == class(CodeEditor))
168 CodeEditor codeEditor = (CodeEditor) child;
169 codeEditor.editBox.freeCaret = ideSettings.useFreeCaret;
170 // codeEditor.editBox.lineNumbers = ideSettings.showLineNumbers;
171 codeEditor.editBox.caretFollowsScrolling = ideSettings.caretFollowsScrolling;
172 codeEditor.OnPostCreate(); // Update editBox margin size
179 case compilerSettings:
181 ide.UpdateCompilerConfigs(true);
188 void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
193 lineY = (line - 1) * lineH;
194 if(lineY + lineH > scrollY && lineY + lineH < scrollY + boxH)
196 Bitmap bitmap = resource.bitmap;
198 surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
203 #define IDEItem(x) (&((IDEWorkSpace)0).x)
205 class IDEToolbar : ToolBar
209 ToolButton buttonNewFile { this, toolTip = $"New file", menuItemPtr = IDEItem(fileNewItem) };
211 ToolButton buttonOpenFile { this, toolTip = $"Open file", menuItemPtr = IDEItem(fileOpenItem) };
213 // ToolButton buttonCloseFile { this, toolTip = $"Close file", menuItemPtr = IDEItem(fileCloseItem) };
215 ToolButton buttonSaveFile { this, toolTip = $"Save file", menuItemPtr = IDEItem(fileSaveItem) };
217 ToolButton buttonSaveAllFile { this, toolTip = $"Save all", menuItemPtr = IDEItem(fileSaveAllItem) };
219 ToolSeparator separator1 { this };
228 // ToolSeparator separator2 { this };
232 ToolButton buttonNewProject { this, toolTip = $"New project", menuItemPtr = IDEItem(projectNewItem) };
234 ToolButton buttonOpenProject { this, toolTip = $"Open project", menuItemPtr = IDEItem(projectOpenItem) };
235 // Add project to workspace
236 ToolButton buttonAddProject { this, toolTip = $"Add project to workspace", menuItemPtr = IDEItem(projectAddItem), disabled = true; };
238 // ToolButton buttonCloseProject { this, toolTip = $"Close project", menuItemPtr = IDEItem(projectCloseItem), disabled = true; };
240 ToolSeparator separator3 { this };
242 // Build/Execution options
244 ToolButton buttonBuild { this, toolTip = $"Build project", menuItemPtr = IDEItem(projectBuildItem), disabled = true; };
246 ToolButton buttonReLink { this, toolTip = $"Relink project", menuItemPtr = IDEItem(projectLinkItem), disabled = true; };
248 ToolButton buttonRebuild { this, toolTip = $"Rebuild project", menuItemPtr = IDEItem(projectRebuildItem), disabled = true; };
250 ToolButton buttonClean { this, toolTip = $"Clean project", menuItemPtr = IDEItem(projectCleanItem), disabled = true; };
252 // ToolButton buttonRealClean { this, toolTip = $"Real clean project", menuItemPtr = IDEItem(projectRealCleanItem), disabled = true; };
253 // Regenerate Makefile
254 ToolButton buttonRegenerateMakefile { this, toolTip = $"Regenerate Makefile", menuItemPtr = IDEItem(projectRegenerateItem), disabled = true; };
255 // Compile actual file
257 ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem), disabled = true; };
258 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
259 ToolButton buttonInstall { this, toolTip = $"Install", menuItemPtr = IDEItem(projectInstallItem), disabled = true; };
262 ToolSeparator separator4 { this };
266 ToolButton buttonDebugStartResume { this, toolTip = $"Start", menuItemPtr = IDEItem(debugStartResumeItem), disabled = true; };
268 ToolButton buttonDebugRestart { this, toolTip = $"Restart", menuItemPtr = IDEItem(debugRestartItem), disabled = true; };
270 ToolButton buttonDebugPause { this, toolTip = $"Break", menuItemPtr = IDEItem(debugBreakItem), disabled = true; };
272 ToolButton buttonDebugStop { this, toolTip = $"Stop", menuItemPtr = IDEItem(debugStopItem), disabled = true; };
274 //ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem) };
276 ToolButton buttonDebugStepInto { this, toolTip = $"Step Into", menuItemPtr = IDEItem(debugStepIntoItem), disabled = true; };
278 ToolButton buttonDebugStepOver { this, toolTip = $"Step Over", menuItemPtr = IDEItem(debugStepOverItem), disabled = true; };
280 ToolButton buttonDebugStepOut { this, toolTip = $"Step Out", menuItemPtr = IDEItem(debugStepOutItem), disabled = true; };
282 ToolButton buttonDebugSkipStepOver { this, toolTip = $"Step Over Skipping Breakpoints", menuItemPtr = IDEItem(debugSkipStepOverItem), disabled = true; };
284 ToolSeparator separator5 { this };
286 Window spacer5 { this, size = { 4 } };
290 this, toolTip = $"Active Configuration(s)", size = { 160 }, disabled = true;
291 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
294 ide.workspace.SelectActiveConfig(row.string);
299 Window spacer6 { this, size = { 4 } };
301 DropBox activeCompiler
303 this, toolTip = $"Active Compiler", size = { 160 }, disabled = true;
304 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
306 if(ide.workspace && ide.projectView && row && strcmp(row.string, ide.workspace.compiler))
308 bool silent = ide.projectView.buildInProgress == none ? false : true;
309 CompilerConfig compiler = ideSettings.GetCompilerConfig(row.string);
310 ide.workspace.compiler = row.string;
311 ide.projectView.ShowOutputBuildLog(!silent);
313 ide.projectView.DisplayCompiler(compiler, false);
314 for(prj : ide.workspace.projects)
315 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
317 ide.workspace.Save();
323 DropBox activeBitDepth
325 this, toolTip = $"Active Bit Length", size = { 60 }, disabled = true;
326 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
328 if(ide.workspace && ide.projectView && row)
330 bool silent = ide.projectView.buildInProgress == none ? false : true;
331 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
332 ide.workspace.bitDepth = (int)row.tag;
333 ide.projectView.ShowOutputBuildLog(!silent);
335 ide.projectView.DisplayCompiler(compiler, false);
336 for(prj : ide.workspace.projects)
337 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
339 ide.workspace.Save();
345 Window spacer7 { this, size = { 4 } };
350 row = activeBitDepth.AddString("Auto");
352 activeBitDepth.AddString("32 bit").tag = 32;
353 activeBitDepth.AddString("64 bit").tag = 64;
354 activeBitDepth.currentRow = row;
358 class IDEMainFrame : Window
360 background = formColor;
361 borderStyle = sizable;
365 minClientSize = { 600, 300 };
367 icon = { ":icon.png" };
368 text = titleECEREIDE;
372 anchor = { top = 0, right = 0, bottom = 0 };
375 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
382 isActiveClient = true;
384 direction = vertical;
385 background = formColor;
386 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
394 ((IDEWorkSpace)master).toolBar = null;
397 IDEWorkSpace ideWorkSpace { stack, this, toolBar = toolBar };
400 define ide = ideMainFrame.ideWorkSpace;
402 class IDEWorkSpace : Window
404 background = Color { 85, 85, 85 };
407 hasVertScroll = true;
408 hasHorzScroll = true;
410 isActiveClient = true;
411 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
415 MenuItem * driverItems, * skinItems, * languageItems;
416 StatusField pos { width = 150 };
417 StatusField ovr, caps, num;
420 BitmapResource back { ":ecereBack.jpg", window = this };
421 BitmapResource bmpBp { ":codeMarks/breakpoint.png", window = this };
422 BitmapResource bmpBpDisabled { ":codeMarks/breakpointDisabled.png", window = this };
423 BitmapResource bmpBpHalf { ":codeMarks/breakpointHalf.png", window = this };
424 BitmapResource bmpBpHalfDisabled { ":codeMarks/breakpointHalfDisabled.png", window = this };
425 BitmapResource bmpCursor { ":codeMarks/cursor.png", window = this };
426 BitmapResource bmpCursorError { ":codeMarks/cursorError.png", window = this };
427 BitmapResource bmpTopFrame { ":codeMarks/topFrame.png", window = this };
428 BitmapResource bmpTopFrameError { ":codeMarks/topFrameError.png", window = this };
429 BitmapResource bmpTopFrameHalf { ":codeMarks/topFrameHalf.png", window = this };
430 BitmapResource bmpTopFrameHalfError { ":codeMarks/topFrameHalfError.png", window = this };
432 Debugger debugger { };
434 ProjectView projectView;
436 OutputView outputView
440 void OnGotoError(const char * line, bool noParsing)
442 CompilerConfig compiler = ide.workspace ? ideSettings.GetCompilerConfig(ide.workspace.compiler) : null;
443 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
444 ide.GoToError(line, noParsing, objectFileExt);
447 void OnCodeLocationParseAndGoTo(const char * line)
449 CompilerConfig compiler = ide.workspace ? ideSettings.GetCompilerConfig(ide.workspace.compiler) : null;
450 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
451 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir, objectFileExt);
454 bool OnKeyDown(Key key, unichar ch)
459 if(activeBox != findBox || !ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
460 ide.ShowCodeEditor();
464 OutputView::OnKeyDown(key, ch);
471 bool OnClose(bool parentClosing)
475 ide.RepositionWindows(false);
476 return parentClosing;
480 CallStackView callStackView
482 parent = this, font = { panelFont.faceName, panelFont.size };
484 void OnSelectFrame(int frameIndex)
486 ide.debugger.GoToStackFrameLine(frameIndex, true, true);
488 ide.debugger.SelectFrame(frameIndex);
491 void OnToggleBreakpoint()
493 Debugger debugger = ide.debugger;
494 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
496 int line = debugger.activeFrame.line;
497 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line);
500 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
501 if(codeEditor) { codeEditor.Update(null); Activate(); }
506 bool OnKeyDown(Key key, unichar ch)
510 case escape: ide.ShowCodeEditor(); break;
515 bool OnClose(bool parentClosing)
519 ide.RepositionWindows(false);
520 return parentClosing;
523 void OnRedraw(Surface surface)
525 Debugger debugger = ide.debugger;
526 Frame activeFrame = debugger.activeFrame;
530 int lineCursor, lineTopFrame;
531 int lineH, scrollY, boxH;
533 Breakpoint bp = null;
536 scrollY = editBox.scroll.y;
537 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
538 //activeThread = debugger.activeThread;
539 //hitThread = debugger.hitThread;
540 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
542 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
543 if(activeFrame.absoluteFile)
545 for(i : ide.workspace.breakpoints; i.type == user)
547 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
548 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
549 activeFrame.line == i.line)
557 DrawLineMarginIcon(surface,
558 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
559 lineCursor /*1*/, lineH, scrollY, boxH);
561 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
562 DrawLineMarginIcon(surface,
563 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
564 1, lineH, scrollY, boxH);
566 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
567 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
568 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
570 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
571 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
573 if(editBox.horzScroll && editBox.horzScroll.visible)
575 surface.SetBackground(control);
576 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
581 WatchesView watchesView { parent = this };
582 ThreadsView threadsView
584 parent = this, font = { panelFont.faceName, panelFont.size };
586 bool OnKeyDown(Key key, unichar ch)
590 case escape: ide.ShowCodeEditor(); break;
595 bool OnClose(bool parentClosing)
599 ide.RepositionWindows(false);
600 return parentClosing;
603 void OnSelectThread(int threadId)
606 ide.debugger.SelectThread(threadId);
609 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
612 Debugger debugger = ide.debugger;
613 *activeThread = debugger.activeThread;
614 *hitThread = debugger.hitThread;
615 *signalThread = debugger.signalThread;
620 BreakpointsView breakpointsView { parent = this };
622 ToolBox toolBox { parent = this, visible = false };
623 Sheet sheet { parent = this, visible = false };
626 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
628 Menu fileMenu { menu, $"File", f, hasMargin = true };
631 fileMenu, $"New", n, ctrlN;
632 bitmap = { ":actions/docNew.png" };
633 bool NotifySelect(MenuItem selection, Modifiers mods)
635 Window currentDoc = activeClient;
636 bool maximizeDoc = ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
637 Window document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, false);
638 RepositionWindows(false);
639 document.NotifySaved = DocumentSaved;
643 MenuItem fileOpenItem
645 fileMenu, $"Open...", o, ctrlO;
646 bitmap = { ":actions/docOpen.png" };
647 bool NotifySelect(MenuItem selection, Modifiers mods)
649 if(!projectView && ideSettings.ideFileDialogLocation)
650 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
653 if(ideFileDialog.Modal() == ok)
655 bool gotWhatWeWant = false;
657 int numSelections = ideFileDialog.numSelections;
658 const char * const * multiFilePaths = ideFileDialog.multiFilePaths;
660 for(c = 0; c < numSelections; c++)
662 if(OpenFile(multiFilePaths[c], false, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
663 gotWhatWeWant = true;
666 MessageBox { type = yesNo, master = this, text = $"Error opening file",
667 contents = $"Open a different file?" }.Modal() == no)
669 if(!projectView && gotWhatWeWant)
670 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
671 ide.RepositionWindows(false);
681 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
682 MenuDivider { fileMenu };
683 MenuItem fileSaveItem
685 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
687 // For the toolbar button; clients can still override that for the menu item
688 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
690 Window w = activeClient;
692 w.MenuFileSave(null, 0);
696 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
697 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
698 MenuDivider { fileMenu };
701 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
702 bool NotifySelect(MenuItem selection, Modifiers mods)
704 findInFilesDialog.replaceMode = false;
705 findInFilesDialog.Show();
709 MenuItem replaceInFiles
711 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
712 bool NotifySelect(MenuItem selection, Modifiers mods)
714 findInFilesDialog.replaceMode = true;
715 findInFilesDialog.Show();
719 MenuDivider { fileMenu };
720 MenuItem globalSettingsItem
722 fileMenu, $"Global Settings...", g;
723 bool NotifySelect(MenuItem selection, Modifiers mods)
725 globalSettingsDialog.master = this;
726 if(ide.workspace && ide.workspace.compiler)
727 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.compiler;
728 else if(ideSettings.defaultCompiler)
729 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
730 globalSettingsDialog.Modal();
734 MenuDivider { fileMenu };
735 Menu recentFiles { fileMenu, $"Recent Files", r };
736 Menu recentProjects { fileMenu, $"Recent Projects", p };
737 MenuDivider { fileMenu };
740 fileMenu, $"Exit", x, altF4;
742 bool NotifySelect(MenuItem selection, Modifiers mods)
744 ideMainFrame.Destroy(0);
749 bool FileRecentFile(MenuItem selection, Modifiers mods)
752 for(file : ideSettings.recentFiles)
754 if(id == selection.id)
757 char extension[MAX_EXTENSION] = "";
758 GetExtension(file, extension);
759 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
762 char * command = PrintString("ide ", isProjectFile ? "-t " : "", file);
768 OpenFile(file, false, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
769 ide.RepositionWindows(false);
778 bool FileRecentProject(MenuItem selection, Modifiers mods)
781 for(file : ideSettings.recentProjects)
783 if(id == selection.id)
787 char * command = PrintString("ide ", file);
792 OpenFile(file, false, true, null, no, normal, mods.ctrl && mods.shift);
800 MenuPlacement editMenu { menu, $"Edit", e };
802 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
803 MenuItem projectNewItem
805 projectMenu, $"New...", n, Key { n, true, true };
806 bitmap = { ":actions/projNew.png" };
807 bool NotifySelect(MenuItem selection, Modifiers mods)
809 if(!DontTerminateDebugSession($"New Project"))
812 NewProjectDialog newProjectDialog { master = this };
813 incref newProjectDialog;
814 result = newProjectDialog.Modal();
819 newProjectDialog.CreateNewProject();
822 ideSettings.AddRecentProject(projectView.fileName);
823 ide.UpdateRecentMenus();
824 settingsContainer.Save();
828 delete newProjectDialog;
833 MenuItem projectOpenItem
835 projectMenu, $"Open...", o, Key { o, true, true };
836 bitmap = { ":actions/projOpen.png" };
837 bool NotifySelect(MenuItem selection, Modifiers mods)
839 if(ideSettings.ideProjectFileDialogLocation)
840 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
842 ideProjectFileDialog.text = openProjectFileDialogTitle;
843 if(ideProjectFileDialog.Modal() == ok)
845 OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
846 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
851 MenuItem projectQuickItem
853 projectMenu, $"Quick...", q, f7, disabled = true;
854 bool NotifySelect(MenuItem selection, Modifiers mods)
857 QuickProjectDialog { this }.Modal();
861 MenuItem projectAddItem
863 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
864 bitmap = { ":actions/projAdd.png" };
866 bool NotifySelect(MenuItem selection, Modifiers mods)
868 if(ideSettings.ideProjectFileDialogLocation)
869 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
871 ideProjectFileDialog.text = addProjectFileDialogTitle;
874 if(ideProjectFileDialog.Modal() == ok)
876 if(OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
878 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
879 contents = $"Add a different project?" }.Modal() == no)
890 MenuItem projectCloseItem
892 projectMenu, $"Close", c, disabled = true;
893 bool NotifySelect(MenuItem selection, Modifiers mods)
897 if(!ide.DontTerminateDebugSession($"Project Close"))
903 MenuDivider { projectMenu };
904 MenuItem projectSettingsItem
906 projectMenu, $"Settings...", s, altF7, disabled = true;
907 bool NotifySelect(MenuItem selection, Modifiers mods)
909 projectView.MenuSettings(projectView.active ? selection : null, mods);
913 MenuDivider { projectMenu };
914 MenuItem projectBrowseFolderItem
916 projectMenu, $"Browse Project Folder", p, disabled = true;
917 bool NotifySelect(MenuItem selection, Modifiers mods)
920 projectView.MenuBrowseFolder(null, mods);
924 MenuDivider { projectMenu };
925 MenuItem projectRunItem
927 projectMenu, $"Run", r, ctrlF5, disabled = true;
928 bitmap = { ":actions/run.png" };
929 bool NotifySelect(MenuItem selection, Modifiers mods)
932 projectView.Run(null, mods);
936 MenuItem projectBuildItem
938 projectMenu, $"Build", b, f7, disabled = true;
939 bitmap = { ":actions/build.png" };
940 bool NotifySelect(MenuItem selection, Modifiers mods)
944 if(projectView.buildInProgress == none)
945 projectView.ProjectBuild(projectView.active ? selection : null, mods);
947 projectView.stopBuild = true;
952 MenuItem projectLinkItem
954 projectMenu, $"Relink", l, disabled = true;
955 bitmap = { ":actions/relink.png" };
956 bool NotifySelect(MenuItem selection, Modifiers mods)
959 projectView.ProjectLink(projectView.active ? selection : null, mods);
963 MenuItem projectRebuildItem
965 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
966 bitmap = { ":actions/rebuild.png" };
967 bool NotifySelect(MenuItem selection, Modifiers mods)
970 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
974 MenuItem projectCleanTargetItem
976 projectMenu, $"Clean Target", g, disabled = true;
977 bitmap = { ":actions/clean.png" };
978 bool NotifySelect(MenuItem selection, Modifiers mods)
983 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
988 MenuItem projectCleanItem
990 projectMenu, $"Clean", e, disabled = true;
991 bitmap = { ":actions/clean.png" };
992 bool NotifySelect(MenuItem selection, Modifiers mods)
997 projectView.ProjectClean(projectView.active ? selection : null, mods);
1002 MenuItem projectRealCleanItem
1004 projectMenu, $"Real Clean", disabled = true;
1005 bitmap = { ":actions/clean.png" };
1006 bool NotifySelect(MenuItem selection, Modifiers mods)
1011 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1016 MenuItem projectRegenerateItem
1018 projectMenu, $"Regenerate Makefile", m, disabled = true;
1019 bitmap = { ":actions/regMakefile.png" };
1020 bool NotifySelect(MenuItem selection, Modifiers mods)
1023 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1027 MenuItem projectInstallItem
1029 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
1030 projectMenu, $"Install", t, disabled = true;
1032 bitmap = { ":status/software-update-available.png" };
1033 bool NotifySelect(MenuItem selection, Modifiers mods)
1036 projectView.ProjectInstall(projectView.active ? selection : null, mods);
1040 MenuItem projectCompileItem;
1041 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1042 MenuItem debugStartResumeItem
1044 debugMenu, $"Start", s, f5, disabled = true;
1045 bitmap = { ":actions/debug.png" };
1046 NotifySelect = MenuDebugStart;
1048 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1052 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1053 if(!projectView.DebugStart())
1054 debugStartResumeItem.disabled = false; // same exception
1058 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1061 projectView.DebugResume();
1064 MenuItem debugRestartItem
1066 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1067 bitmap = { ":actions/restart.png" };
1068 bool NotifySelect(MenuItem selection, Modifiers mods)
1071 projectView.DebugRestart();
1075 MenuItem debugBreakItem
1077 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1078 bitmap = { ":actions/pause.png" };
1079 bool NotifySelect(MenuItem selection, Modifiers mods)
1081 if(projectView && projectView.buildInProgress != none)
1084 projectView.DebugBreak();
1088 MenuItem debugStopItem
1090 debugMenu, $"Stop", p, shiftF5, disabled = true;
1091 bitmap = { ":actions/stopDebug.png" };
1092 bool NotifySelect(MenuItem selection, Modifiers mods)
1095 projectView.DebugStop();
1099 MenuDivider { debugMenu };
1103 // nonClient = true,
1110 anchor = { right = 0, bottom = 0 },
1112 isActiveClient = false,
1114 clickThrough = true,
1115 size = { 500, 500 };
1117 bool OnLoadGraphics()
1119 ModelView::OnLoadGraphics();
1120 camera.position.z /= 1.3;
1121 camera.orientation = Euler { yaw = 280, pitch = 20 };
1127 bool OnRightButtonDown(int x, int y, Modifiers mods)
1129 if(!displaySystem.flags.flipping) return true;
1130 MenuWindowMove(null, 0);
1134 bool OnRightButtonUp(int x, int y, Modifiers mods)
1136 position = position;
1141 MenuItem debugRubberDuck
1143 debugMenu, $"Rubber Duck", checkable = true, disabled = true;
1144 bool NotifySelect(MenuItem selection, Modifiers mods)
1146 if(selection.checked)
1154 MenuDivider { debugMenu };
1155 MenuItem debugUseValgrindItem
1157 debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
1158 bool NotifySelect(MenuItem selection, Modifiers mods)
1162 ide.workspace.useValgrind = selection.checked;
1163 ide.workspace.Save();
1165 ide.AdjustValgrindMenus();
1169 Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
1170 MenuItem debugValgrindNoLeakCheckItem { debugValgrindLeakCheckItem, $"No" , f, id = ValgrindLeakCheck::no , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1171 MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; };
1172 MenuItem debugValgrindYesLeakCheckItem { debugValgrindLeakCheckItem, $"Yes" , f, id = ValgrindLeakCheck::yes , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1173 MenuItem debugValgrindFullLeakCheckItem { debugValgrindLeakCheckItem, $"Full" , f, id = ValgrindLeakCheck::full , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1174 bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
1178 if(selection.checked)
1180 ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
1182 debugValgrindNoLeakCheckItem.checked = debugValgrindNoLeakCheckItem.id == vgLeakCheck;
1183 debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
1184 debugValgrindYesLeakCheckItem.checked = debugValgrindYesLeakCheckItem.id == vgLeakCheck;
1185 debugValgrindFullLeakCheckItem.checked = debugValgrindFullLeakCheckItem.id == vgLeakCheck;
1187 ide.workspace.vgLeakCheck = vgLeakCheck;
1188 ide.workspace.Save();
1191 selection.checked = true;
1195 Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
1196 MenuItem debugValgrindRSDefaultItem { debugValgrindRedzoneSizeItem, $"Default", f, id = -1, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; };
1197 MenuItem debugValgrindRS0Item { debugValgrindRedzoneSizeItem, "0" , f, id = 0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1198 MenuItem debugValgrindRS16Item { debugValgrindRedzoneSizeItem, "16" , f, id = 16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1199 MenuItem debugValgrindRS32Item { debugValgrindRedzoneSizeItem, "32" , f, id = 32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1200 MenuItem debugValgrindRS64Item { debugValgrindRedzoneSizeItem, "64" , f, id = 64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1201 MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, "128" , f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1202 MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, "256" , f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1203 MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, "512" , f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1204 bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
1208 if(selection.checked)
1210 int vgRedzoneSize = (int)selection.id;
1212 debugValgrindRSDefaultItem.checked = debugValgrindRSDefaultItem.id == vgRedzoneSize;
1213 debugValgrindRS0Item.checked = debugValgrindRS0Item.id == vgRedzoneSize;
1214 debugValgrindRS16Item.checked = debugValgrindRS16Item.id == vgRedzoneSize;
1215 debugValgrindRS32Item.checked = debugValgrindRS32Item.id == vgRedzoneSize;
1216 debugValgrindRS64Item.checked = debugValgrindRS64Item.id == vgRedzoneSize;
1217 debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
1218 debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
1219 debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
1221 ide.workspace.vgRedzoneSize = vgRedzoneSize;
1222 ide.workspace.Save();
1225 selection.checked = true;
1229 MenuItem debugValgrindTrackOriginsItem
1231 debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
1232 bool NotifySelect(MenuItem selection, Modifiers mods)
1236 ide.workspace.vgTrackOrigins = selection.checked;
1237 ide.workspace.Save();
1243 MenuDivider { debugMenu };
1244 MenuItem debugStepIntoItem
1246 debugMenu, $"Step Into", i, f11, disabled = true;
1247 bitmap = { ":actions/stepInto.png" };
1248 bool NotifySelect(MenuItem selection, Modifiers mods)
1250 if(projectView) projectView.DebugStepInto();
1254 MenuItem debugStepOverItem
1256 debugMenu, $"Step Over", v, f10, disabled = true;
1257 bitmap = { ":actions/stepOver.png" };
1258 bool NotifySelect(MenuItem selection, Modifiers mods)
1260 if(projectView) projectView.DebugStepOver(false);
1264 MenuItem debugSkipStepOverItem
1266 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1267 bitmap = { ":actions/stepOverSkipBreak.png" };
1268 bool NotifySelect(MenuItem selection, Modifiers mods)
1270 if(projectView) projectView.DebugStepOver(true);
1274 MenuItem debugStepOutItem
1276 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1277 bitmap = { ":actions/stepOut.png" };
1278 bool NotifySelect(MenuItem selection, Modifiers mods)
1280 if(projectView) projectView.DebugStepOut(false);
1284 MenuItem debugSkipStepOutItem
1286 debugMenu, $"Step Out Skipping Breakpoints", n, Key { f11, ctrl = true, shift = true }, disabled = true;
1287 bitmap = { ":actions/skipBreaks.png" };
1288 bool NotifySelect(MenuItem selection, Modifiers mods)
1290 if(projectView) projectView.DebugStepOut(true);
1295 MenuItem debugStepUntilItem
1297 debugMenu, $"Step Over Until Next Line", x, disabled = true;
1298 bool NotifySelect(MenuItem selection, Modifiers mods)
1300 if(projectView) projectView.DebugStepUntil(false);
1304 MenuItem debugSkipStepUntilItem
1306 debugMenu, $"Step Over Until Next Line Skipping Breakpoints", e, Key { f10, shift = true, alt = true }, disabled = true;
1307 bool NotifySelect(MenuItem selection, Modifiers mods)
1309 if(projectView) projectView.DebugStepUntil(true);
1314 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1315 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1316 MenuPlacement debugRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level", l };
1317 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", g };
1319 MenuPlacement debugBpRunToCursorItem { debugMenu, $"BP Run To Cursor" };
1320 MenuPlacement debugBpSkipRunToCursorItem { debugMenu, $"BP Run To Cursor Skipping Breakpoints" };
1321 MenuPlacement debugBpRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level" };
1322 MenuPlacement debugBpSkipRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level Skipping Breakpoints" };
1324 //MenuDivider { debugMenu };
1325 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1326 MenuPlacement imageMenu { menu, $"Image", i };
1327 Menu viewMenu { menu, $"View", v };
1328 MenuItem viewProjectItem
1330 viewMenu, $"Project View", j, alt0, disabled = true;
1331 bool NotifySelect(MenuItem selection, Modifiers mods)
1335 projectView.visible = true;
1336 projectView.Activate();
1341 MenuPlacement { viewMenu, $"View Designer" };
1342 MenuPlacement { viewMenu, $"View Code" };
1343 MenuPlacement { viewMenu, $"View Properties" };
1344 MenuPlacement { viewMenu, $"View Methods" };
1345 MenuItem viewDesignerItem
1347 viewMenu, $"View Designer", d, f8;
1348 bool NotifySelect(MenuItem selection, Modifiers mods)
1350 Window client = activeClient;
1351 Class dataType = client._class;
1352 if(!strcmp(dataType.name, "Designer"))
1354 client.visible = true;
1358 ((CodeEditor)client).ViewDesigner();
1362 MenuItem viewCodeItem
1364 viewMenu, $"View Code", c, f8;
1365 bool NotifySelect(MenuItem selection, Modifiers mods)
1367 Window client = activeClient;
1368 Class dataType = client._class;
1369 if(!strcmp(dataType.name, "Designer"))
1370 client = ((Designer)client).codeEditor;
1373 // Do this after so the caret isn't moved yet...
1374 client.visible = true;
1378 MenuItem viewPropertiesItem
1380 viewMenu, $"View Properties", p, f4;
1381 bool NotifySelect(MenuItem selection, Modifiers mods)
1383 sheet.visible = true;
1384 sheet.sheetSelected = properties;
1389 MenuItem viewMethodsItem
1391 viewMenu, $"View Methods", m, f4;
1392 bool NotifySelect(MenuItem selection, Modifiers mods)
1394 sheet.visible = true;
1395 sheet.sheetSelected = methods;
1400 MenuItem viewToolBoxItem
1402 viewMenu, $"View Toolbox", x, f12;
1403 bool NotifySelect(MenuItem selection, Modifiers mods)
1405 toolBox.visible = true;
1410 MenuItem viewOutputItem
1412 viewMenu, $"Output", o, alt2;
1413 bool NotifySelect(MenuItem selection, Modifiers mods)
1419 MenuItem viewWatchesItem
1421 viewMenu, $"Watches", w, alt3;
1422 bool NotifySelect(MenuItem selection, Modifiers mods)
1428 MenuItem viewThreadsItem
1430 viewMenu, $"Threads", t, alt4;
1431 bool NotifySelect(MenuItem selection, Modifiers mods)
1437 MenuItem viewBreakpointsItem
1439 viewMenu, $"Breakpoints", b, alt5;
1440 bool NotifySelect(MenuItem selection, Modifiers mods)
1442 breakpointsView.Show();
1446 MenuItem viewCallStackItem
1448 viewMenu, $"Call Stack", s, alt7;
1449 bool NotifySelect(MenuItem selection, Modifiers mods)
1451 callStackView.Show();
1455 MenuItem viewAllDebugViews
1457 viewMenu, $"All Debug Views", a, alt9;
1458 bool NotifySelect(MenuItem selection, Modifiers mods)
1463 callStackView.Show();
1464 breakpointsView.Show();
1468 #ifdef GDB_DEBUG_GUI
1469 MenuDivider { viewMenu };
1470 MenuItem viewGDBItem
1472 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1473 bool NotifySelect(MenuItem selection, Modifiers mods)
1480 MenuDivider { viewMenu };
1481 MenuItem viewColorPicker
1483 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1484 bool NotifySelect(MenuItem selection, Modifiers mods)
1486 ColorPicker colorPicker { master = this };
1487 colorPicker.Modal();
1491 MenuDivider { viewMenu };
1495 viewMenu, "Full Screen", f, checkable = true;
1497 bool NotifySelect(MenuItem selection, Modifiers mods)
1499 app.fullScreen ^= true;
1501 anchor = { 0, 0, 0, 0 };
1506 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1508 MenuDivider { viewMenu };
1510 Menu languageMenu { viewMenu, "Language", l };
1512 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1513 Menu windowMenu { menu, $"Window", w };
1514 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1515 MenuDivider { windowMenu };
1516 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1517 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1518 MenuDivider { windowMenu };
1519 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1520 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1521 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1522 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1523 MenuDivider { windowMenu };
1524 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1525 Menu helpMenu { menu, $"Help", h };
1528 helpMenu, $"API Reference", r, f1;
1529 bool NotifySelect(MenuItem selection, Modifiers mods)
1533 char * p = new char[MAX_LOCATION];
1535 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1536 PathCat(p, "documentor");
1537 #if defined(__WIN32__)
1538 ChangeExtension(p, "exe", p);
1540 if(!FileExists(p).isFile)
1541 strcpy(p, "documentor");
1543 documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
1548 Process_ShowWindows(documentor.GetProcessID());
1549 // documentor.Puts("Activate\n");
1554 MenuDivider { helpMenu };
1557 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1558 bool NotifySelect(MenuItem selection, Modifiers mods)
1560 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1564 MenuDivider { helpMenu };
1567 helpMenu, $"Documentation Folder", d;
1568 bool NotifySelect(MenuItem selection, Modifiers mods)
1570 FindAndShellOpenInstalledFolder("doc");
1576 helpMenu, $"Samples Folder", s;
1577 bool NotifySelect(MenuItem selection, Modifiers mods)
1579 FindAndShellOpenInstalledFolder("samples");
1585 helpMenu, $"Extras Folder", x;
1586 bool NotifySelect(MenuItem selection, Modifiers mods)
1588 FindAndShellOpenInstalledFolder("extras");
1592 MenuDivider { helpMenu };
1595 helpMenu, $"Community Forums", f;
1596 bool NotifySelect(MenuItem selection, Modifiers mods)
1598 ShellOpen("http://ecere.com/forums");
1602 MenuDivider { helpMenu };
1605 helpMenu, $"About...", a;
1606 bool NotifySelect(MenuItem selection, Modifiers mods)
1608 AboutIDE { master = this }.Modal();
1613 property ToolBox toolBox
1615 get { return toolBox; }
1618 property Sheet sheet
1620 get { return sheet; }
1623 property Project project
1625 get { return projectView ? projectView.project : null; }
1628 property Workspace workspace
1630 get { return projectView ? projectView.workspace : null; }
1633 FindInFilesDialog findInFilesDialog
1636 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1642 #ifdef GDB_DEBUG_GUI
1645 master = this, parent = this;
1646 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1648 void OnCommand(const char * string)
1651 ide.debugger.SendGDBCommand(string);
1656 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1658 //app.driver = app.drivers[selection.id];
1659 #if defined(__unix__) || defined(__APPLE__)
1660 app.driver = selection.id ? "OpenGL" : "X";
1662 app.driver = selection.id ? "OpenGL" : "GDI";
1664 delete ideSettings.displayDriver;
1665 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1667 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1669 settingsContainer.Save();
1670 //SetDriverAndSkin();
1674 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1676 app.skin = app.skins[selection.id];
1681 void SetDriverAndSkin()
1684 for(c = 0; c < app.numSkins; c++)
1685 if(!strcmp(app.skins[c], app.skin))
1687 skinItems[c].checked = true;
1690 for(c = 0; c < app.numDrivers; c++)
1691 if(!strcmp(app.drivers[c], app.driver))
1693 driverItems[c].checked = true;
1698 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1700 Project project = workspace.projects.firstIterator.data;
1701 projectView = ProjectView
1704 fileName = fileName;
1706 void NotifyDestroyed(Window window, DialogResult result)
1709 text = titleECEREIDE;
1714 projectView.Create();
1715 RepositionWindows(false);
1717 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1718 projectView.workspace = workspace;
1719 projectView.project = project;
1720 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1724 ide.breakpointsView.LoadFromWorkspace();
1725 ide.watchesView.LoadFromWorkspace();
1727 findInFilesDialog.projectNodeField.userData = projectView;
1730 char fileName[MAX_LOCATION];
1731 strcpy(fileName, project.topNode.path);
1732 PathCat(fileName, project.topNode.name);
1739 projectView.visible = false;
1740 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1742 if(findInFilesDialog)
1744 char workingDir[MAX_LOCATION];
1745 GetWorkingDir(workingDir, MAX_LOCATION);
1746 findInFilesDialog.SearchStop();
1747 findInFilesDialog.currentDirectory = workingDir;
1749 sheet.visible = false;
1750 toolBox.visible = false;
1751 outputView.visible = false;
1752 ideMainFrame.text = titleECEREIDE;
1759 void RepositionWindows(bool expand)
1764 bool callStackVisible = expand ? false : callStackView.visible;
1765 bool threadsVisible = expand ? false : threadsView.visible;
1766 bool watchesVisible = expand ? false : watchesView.visible;
1767 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1768 bool toolBoxVisible = toolBox.visible;
1769 bool outputVisible = expand ? false : outputView.visible;
1770 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1771 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1773 for(child = firstChild; child; child = child.next)
1775 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1776 child._class == class(Sheet) || child._class == class(ProjectView))
1778 Anchor anchor = child.anchor;
1779 anchor.top = topDistance;
1780 anchor.bottom = bottomDistance;
1781 if(child._class == class(CodeEditor) || child._class == class(Designer))
1783 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1784 anchor.right = toolBoxVisible ? 150 : 0;
1787 child.anchor = anchor;
1791 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1792 child._class == class(BreakpointsView))
1793 child.visible = false;
1796 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1798 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1802 bool ShowCodeEditor()
1805 activeClient.Activate();
1806 else if(projectView)
1808 projectView.visible = true;
1809 projectView.Activate();
1811 else if(sheet.visible)
1814 outputView.visible = false;
1818 void DocumentSaved(Window document, const char * fileName)
1820 ideSettings.AddRecentFile(fileName);
1821 ide.UpdateRecentMenus();
1822 ide.AdjustFileMenus();
1823 settingsContainer.Save();
1826 bool Window::OnFileModified(FileChange fileChange, const char * param)
1829 sprintf(temp, $"The document %s was modified by another application.\n"
1830 "Would you like to reload it and lose your changes?", this.fileName);
1831 if(MessageBox { type = yesNo, master = this/*.parent*/,
1832 text = $"Document has been modified", contents = temp }.Modal() == yes)
1834 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1835 char * fileName = CopyString(this.fileName);
1836 WindowState state = this.state;
1837 Anchor anchor = this.anchor;
1838 Size size = this.size;
1840 this.modifiedDocument = false;
1842 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1845 this.anchor = anchor;
1847 this.SetState(state, true, 0);
1855 void UpdateMakefiles()
1859 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1860 for(prj : workspace.projects)
1861 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1866 void UpdateCompilerConfigs(bool mute)
1868 UpdateToolBarActiveCompilers();
1871 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1872 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1875 projectView.ShowOutputBuildLog(true);
1876 projectView.DisplayCompiler(compiler, false);
1878 for(prj : workspace.projects)
1879 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1884 void UpdateToolBarActiveCompilers()
1886 toolBar.activeCompiler.Clear();
1887 for(compiler : ideSettings.compilerConfigs)
1889 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1890 if(workspace && workspace.compiler && !strcmp(compiler.name, workspace.compiler))
1891 toolBar.activeCompiler.currentRow = row;
1893 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1894 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1897 void UpdateToolBarActiveConfigs(bool selectionOnly)
1899 bool commonSelected = false;
1900 DataRow row = toolBar.activeConfig.currentRow;
1902 row = toolBar.activeConfig.FindRow(1);
1905 toolBar.activeConfig.Clear();
1906 row = toolBar.activeConfig.AddString($"(Mixed)");
1911 char * configName = null;
1914 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1915 for(prj : workspace.projects)
1917 for(cfg : prj.configurations)
1920 configs[cfg.name] = 1;
1925 toolBar.activeConfig.AddString(&name);
1929 if(projectView && projectView.project)
1931 for(prj : workspace.projects)
1933 if(prj.config && prj.config.name)
1935 configName = prj.config.name;
1941 commonSelected = true;
1942 for(prj : workspace.projects)
1944 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1946 commonSelected = false;
1954 commonSelected = false;
1955 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1957 if(!strcmp(row.string, configName))
1959 toolBar.activeConfig.currentRow = row;
1960 commonSelected = true;
1967 toolBar.activeConfig.Sort(null, 0);
1969 toolBar.activeConfig.currentRow = row;
1974 bool unavailable = !project;
1976 projectAddItem.disabled = unavailable;
1977 toolBar.buttonAddProject.disabled = unavailable;
1979 projectSettingsItem.disabled = unavailable;
1981 projectBrowseFolderItem.disabled = unavailable;
1983 viewProjectItem.disabled = unavailable;
1985 toolBar.activeConfig.disabled = unavailable;
1986 toolBar.activeCompiler.disabled = unavailable;
1987 toolBar.activeBitDepth.disabled = unavailable;
1990 debugUseValgrindItem.disabled = unavailable;
1991 AdjustValgrindMenus();
2000 void AdjustValgrindMenus()
2002 bool unavailable = !project || !debugUseValgrindItem.checked;
2003 debugValgrindNoLeakCheckItem.disabled = unavailable;
2004 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2005 debugValgrindYesLeakCheckItem.disabled = unavailable;
2006 debugValgrindFullLeakCheckItem.disabled = unavailable;
2008 debugValgrindTrackOriginsItem.disabled = unavailable;
2010 debugValgrindRSDefaultItem.disabled = unavailable;
2011 debugValgrindRS0Item.disabled = unavailable;
2012 debugValgrindRS16Item.disabled = unavailable;
2013 debugValgrindRS32Item.disabled = unavailable;
2014 debugValgrindRS64Item.disabled = unavailable;
2015 debugValgrindRS128Item.disabled = unavailable;
2016 debugValgrindRS256Item.disabled = unavailable;
2017 debugValgrindRS512Item.disabled = unavailable;
2021 property bool hasOpenedCodeEditors
2026 for(w = firstChild; w; w = w.next)
2027 if(w._class == class(CodeEditor) &&
2028 w.isDocument && !w.closing && w.visible && w.created &&
2029 w.fileName && w.fileName[0])
2035 void AdjustFileMenus()
2037 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2039 projectQuickItem.disabled = unavailable;
2042 void AdjustBuildMenus()
2044 bool unavailable = project && projectView.buildInProgress;
2045 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2047 projectNewItem.disabled = unavailable;
2048 toolBar.buttonNewProject.disabled = unavailable;
2049 projectOpenItem.disabled = unavailable;
2050 toolBar.buttonOpenProject.disabled = unavailable;
2052 unavailable = !project || projectView.buildInProgress;
2054 projectCloseItem.disabled = unavailable;
2055 // toolBar.buttonCloseProject.disabled = unavailable;
2057 projectRunItem.disabled = naForRun;
2058 toolBar.buttonRun.disabled = naForRun;
2060 projectBuildItem.disabled = false;
2061 projectBuildItem.text = unavailable ? $"Stop Build" : $"Build";
2062 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2064 projectLinkItem.disabled = unavailable;
2065 toolBar.buttonReLink.disabled = unavailable;
2066 projectRebuildItem.disabled = unavailable;
2067 toolBar.buttonRebuild.disabled = unavailable;
2068 projectCleanItem.disabled = unavailable;
2069 toolBar.buttonClean.disabled = unavailable;
2070 projectCleanTargetItem.disabled = unavailable;
2071 projectRealCleanItem.disabled = unavailable;
2072 // toolBar.buttonRealClean.disabled = unavailable;
2073 projectRegenerateItem.disabled = unavailable;
2074 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2075 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2076 projectInstallItem.disabled = unavailable;
2077 toolBar.buttonInstall.disabled = unavailable;
2079 projectCompileItem.disabled = unavailable;
2081 AdjustPopupBuildMenus();
2084 void AdjustPopupBuildMenus()
2086 bool unavailable = !project || projectView.buildInProgress;
2088 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2091 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
2094 menu.disabled = false;
2095 menu.text = unavailable ? $"Stop Build" : $"Build";
2096 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2099 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0); if(menu) menu.disabled = unavailable;
2100 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0); if(menu) menu.disabled = unavailable;
2101 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0); if(menu) menu.disabled = unavailable;
2102 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0); if(menu) menu.disabled = unavailable;
2103 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0); if(menu) menu.disabled = unavailable;
2104 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
2105 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, 0); if(menu) menu.disabled = unavailable;
2106 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0); if(menu) menu.disabled = unavailable;
2107 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0); if(menu) menu.disabled = unavailable;
2108 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0); if(menu) menu.disabled = unavailable;
2109 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0); if(menu) menu.disabled = unavailable;
2110 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0); if(menu) menu.disabled = unavailable;
2111 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
2112 projectView.popupMenu.Update(null);
2116 property bool areDebugMenusUnavailable { get {
2118 project.GetTargetType(project.config) != executable ||
2119 projectView.buildInProgress == buildingMainProject;
2122 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2123 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2124 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2126 void AdjustDebugMenus()
2128 bool unavailable = areDebugMenusUnavailable;
2129 bool running = isDebuggerRunning;
2130 bool stopped = isDebuggerStopped;
2131 bool active = debugger.isActive;
2133 bool isNotRunning = unavailable || !running;
2134 bool isNotNotRunning = unavailable || running;
2135 bool isNotStopped = unavailable || !stopped;
2136 bool isNotActive = unavailable || !active;
2138 debugStartResumeItem.disabled = isNotNotRunning;
2139 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2140 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2143 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2144 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2147 debugBreakItem.disabled = isNotRunning;
2148 debugStopItem.disabled = isNotActive;
2149 debugRestartItem.disabled = isNotActive;
2152 toolBar.buttonDebugPause.disabled = isNotRunning;
2153 toolBar.buttonDebugStop.disabled = isNotActive;
2154 toolBar.buttonDebugRestart.disabled = isNotActive;
2157 debugStepIntoItem.disabled = isNotNotRunning;
2158 debugStepOverItem.disabled = isNotNotRunning;
2159 debugSkipStepOverItem.disabled = isNotNotRunning;
2160 debugStepOutItem.disabled = isNotStopped;
2161 debugSkipStepOutItem.disabled = isNotStopped;
2163 debugStepUntilItem.disabled = isNotStopped;
2164 debugSkipStepUntilItem.disabled = isNotStopped;
2168 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2169 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2170 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2171 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2172 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2174 if((Designer)GetActiveDesigner())
2176 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2178 codeEditor.AdjustDebugMenus();
2182 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2184 char tempString[MAX_LOCATION];
2185 strcpy(tempString, directory);
2186 if(saveSettings && !projectView)
2188 ideSettings.ideFileDialogLocation = directory;
2189 settingsContainer.Save();
2192 ideFileDialog.currentDirectory = tempString;
2193 codeEditorFileDialog.currentDirectory = tempString;
2194 codeEditorFormFileDialog.currentDirectory = tempString;
2197 void ChangeProjectFileDialogDirectory(char * directory)
2199 ideSettings.ideProjectFileDialogLocation = directory;
2200 settingsContainer.Save();
2203 Window FindWindow(const char * filePath)
2205 Window document = null;
2207 // TOCHECK: Do we need to change slashes here?
2208 for(document = firstChild; document; document = document.next)
2210 const char * fileName = document.fileName;
2211 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2213 document.visible = true;
2214 document.Activate();
2221 bool DontTerminateDebugSession(const char * title)
2223 if(debugger.isActive)
2225 if(MessageBox { type = yesNo, master = ide,
2226 contents = $"Do you want to terminate the debugging session in progress?",
2227 text = title }.Modal() == no)
2230 MessageBox msg { type = yesNo, master = ide,
2231 contents = "Do you want to terminate the debugging session in progress?",
2233 if(msg.Modal() == no)
2245 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2247 char extension[MAX_EXTENSION] = "";
2248 Window document = null;
2249 bool isProject = false;
2250 bool needFileModified = true;
2251 char winFilePath[MAX_LOCATION];
2252 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2253 Window currentDoc = activeClient;
2254 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2257 GetExtension(filePath, extension);
2261 strcpy(extension, type);
2263 if(strcmp(extension, ProjectExtension))
2265 for(document = firstChild; document; document = document.next)
2267 const char * fileName = document.fileName;
2268 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2270 document.visible = true;
2272 document.Activate();
2278 if(createIfFails == whatever)
2280 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2282 needFileModified = false;
2283 if(openMethod == normal)
2285 if(DontTerminateDebugSession($"Open Project"))
2294 Workspace workspace = null;
2296 if(FileExists(filePath))
2298 if(!strcmp(extension, ProjectExtension))
2300 char workspaceFile[MAX_LOCATION];
2301 strcpy(workspaceFile, filePath);
2302 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2303 workspace = LoadWorkspace(workspaceFile, filePath);
2305 else if(!strcmp(extension, WorkspaceExtension))
2306 workspace = LoadWorkspace(filePath, null);
2313 CreateProjectView(workspace, filePath);
2314 document = projectView;
2316 toolBox.visible = true;
2317 sheet.visible = true;
2318 projectView.MakeActive();
2320 workspace.ParseLoadedBreakpoints();
2321 workspace.DropInvalidBreakpoints(null);
2324 ide.projectView.ShowOutputBuildLog(true);
2326 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2327 ide.projectView.DisplayCompiler(compiler, false);
2330 UpdateCompilerConfigs(false);
2333 char newWorkingDir[MAX_LOCATION];
2334 StripLastDirectory(filePath, newWorkingDir);
2335 ChangeFileDialogsDirectory(newWorkingDir, false);
2338 document.fileName = filePath;
2340 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2342 // this crashes on starting ide with epj file, solution please?
2343 // app.UpdateDisplay();
2345 workspace.holdTracking = true;
2346 for(ofi : workspace.openedFiles)
2348 if(ofi.state != closed)
2350 Window file = OpenFile(ofi.path, false, true, null, no, normal, noParsing);
2353 char fileName[MAX_LOCATION];
2355 GetLastDirectory(ofi.path, fileName);
2356 node = projectView.project.topNode.Find(fileName, true);
2358 node.EnsureVisible();
2362 ide.RepositionWindows(false);
2363 workspace.holdTracking = false;
2365 workspace.timer.Start();
2367 #if !defined(__WIN32__)
2368 // Valgrind Debug menu updates
2369 debugUseValgrindItem.checked = workspace.useValgrind;
2371 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2372 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2373 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2374 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2376 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2377 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2378 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2379 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2380 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2381 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2382 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2383 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2385 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2388 findInFilesDialog.mode = FindInFilesMode::project;
2389 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2392 char location[MAX_LOCATION];
2393 StripLastDirectory(ide.project.topNode.path, location);
2394 ChangeProjectFileDialogDirectory(location);
2401 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2403 ideProjectFileDialog.text = openProjectFileDialogTitle;
2404 if(ideProjectFileDialog.Modal() == cancel)
2406 filePath = ideProjectFileDialog.filePath;
2407 GetExtension(filePath, extension);
2418 else if(openMethod == add)
2423 char slashFilePath[MAX_LOCATION];
2424 GetSlashPathBuffer(slashFilePath, filePath);
2425 for(p : workspace.projects)
2427 if(!fstrcmp(p.filePath, slashFilePath))
2435 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2436 contents = $"This project is already present in workspace." }.Modal();
2440 prj = LoadProject(filePath, null);
2443 const char * activeConfigName = null;
2444 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2445 prj.StartMonitoring();
2446 workspace.projects.Add(prj);
2447 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2448 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2449 activeConfigName = toolBar.activeConfig.currentRow.string;
2450 if(activeConfigName)
2452 for(cfg : prj.configurations)
2454 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2462 projectView.AddNode(prj.topNode, null);
2463 workspace.modified = true;
2465 findInFilesDialog.AddProjectItem(prj);
2466 projectView.ShowOutputBuildLog(true);
2467 projectView.DisplayCompiler(compiler, false);
2468 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2472 char location[MAX_LOCATION];
2473 StripLastDirectory(prj.topNode.path, location);
2474 ChangeProjectFileDialogDirectory(location);
2477 // projectView is associated with the main project and not with the one just added but
2478 return projectView; // just to let the caller know something was opened
2486 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2487 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2488 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2490 if(FileExists(filePath))
2491 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2492 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2493 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2496 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2499 else if(!strcmp(extension, "3ds"))
2501 if(FileExists(filePath))
2502 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2503 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2504 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2508 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2511 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2512 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2513 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2514 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2515 !strcmp(extension, "js"))
2517 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2518 editor.updatingCode = true;
2519 if(editor.LoadFile(filePath))
2522 editor.visible = true;
2526 needFileModified = false;
2530 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2531 if(editor.LoadFile(filePath))
2534 editor.visible = true;
2538 needFileModified = false;
2541 if(document && (document._class == class(PictureEdit) ||
2542 document._class == class(ModelView)))
2547 document.fileName = filePath;
2548 if(workspace && !workspace.holdTracking)
2549 workspace.UpdateOpenedFileInfo(filePath, opened);
2553 if(!document && createIfFails != no)
2555 if(createIfFails != yes && !needFileModified &&
2556 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2557 createIfFails = yes;
2558 if(createIfFails == yes || createIfFails == whatever)
2560 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2562 document.fileName = filePath;
2568 if(projectView && document._class == class(CodeEditor) && workspace)
2570 int lineNumber, position;
2572 CodeEditor editor = (CodeEditor)document;
2573 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2574 editor.openedFileInfo.holdTracking = true;
2575 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2576 position = Max(editor.openedFileInfo.position - 1, 0);
2577 if(editor.editBox.GoToLineNum(lineNumber))
2578 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2579 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2580 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2581 editor.editBox.scroll = scroll;
2582 editor.openedFileInfo.holdTracking = false;
2585 if(needFileModified)
2586 document.OnFileModified = OnFileModified;
2587 document.NotifySaved = DocumentSaved;
2588 if(maximizeDoc && document.hasMaximize)
2589 document.state = maximized;
2592 ideSettings.AddRecentProject(document.fileName);
2594 ideSettings.AddRecentFile(document.fileName);
2595 ide.UpdateRecentMenus();
2596 ide.AdjustFileMenus();
2597 settingsContainer.Save();
2605 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2606 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2608 if(!parentClosing && ide.workspace)
2609 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2612 bool ModelView::ModelViewOnClose(bool parentClosing)
2614 if(!parentClosing && ide.workspace)
2615 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2618 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2620 if(!parentClosing && ide.workspace)
2621 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2626 void OnUnloadGraphics(Window window)
2628 display.ClearMaterials();
2629 display.ClearTextures();
2630 display.ClearMeshes();
2634 void UpdateStateLight(StatusField fld, bool on)
2636 fld.color = on ? lime : Color { 128,128,128 };
2637 fld.backColor = on ? dimGray : 0;
2641 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2643 UpdateStateLight(caps, app.GetKeyState(capsState));
2644 UpdateStateLight(num, app.GetKeyState(numState));
2648 bool OnKeyDown(Key key, unichar ch)
2652 case b: projectView.Update(null); break;
2653 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2654 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2659 bool OnKeyUp(Key key, unichar ch)
2663 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2664 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2669 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2672 projectView.GoToError(line, noParsing, objectFileExt);
2675 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2677 FileAttribs result { };
2678 FileAttribs fileAttribs;
2682 strcpy(selectedPath, prj.topNode.path);
2683 else if(dir && dir[0])
2684 strcpy(selectedPath, dir);
2686 selectedPath[0] = '\0';
2687 PathCat(selectedPath, filePath);
2689 if((fileAttribs = FileExists(selectedPath)).isFile)
2690 result = fileAttribs;
2694 for(p : workspace.projects)
2696 strcpy(selectedPath, p.topNode.path);
2697 PathCat(selectedPath, filePath);
2698 if((fileAttribs = FileExists(selectedPath)).isFile)
2701 result = fileAttribs;
2708 ProjectNode n = null;
2709 for(p : workspace.projects)
2711 if((n = p.topNode.Find(filePath, false)))
2713 n.GetFullFilePath(selectedPath);
2714 if((fileAttribs = FileExists(selectedPath)).isFile)
2717 result = fileAttribs;
2722 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2723 (fileAttribs = FileExists(selectedPath)).isFile)
2726 result = fileAttribs;
2734 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2737 const char *path = text;
2738 char *colon = strchr(text, ':');
2739 char filePath[MAX_LOCATION] = "";
2740 char completePath[MAX_LOCATION];
2741 int line = 0, col = 0;
2742 int len = strlen(text);
2744 FileAttribs fileAttribs;
2746 // support for valgrind output
2747 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2758 /*for(s=colon; *s; s++)
2767 //line = atoi(colon+1);
2769 // support for "Found n match(es) in "file/path";
2770 else if(path[len-1] == '\"' && strstr(path, $"Found %d match%s in \"%s\"%s\n\n"."Found") && strstr(path, $"match") && strstr(path, $"in") && (s = strstr(path, "\"")) && s != path+len-1)
2776 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2778 path = (colon - 1 > path) ? colon - 1 : path;
2779 colon = strstr(colon + 1, ":");
2781 if(*path == '*' && (s = strchr(path+1, '*')))
2783 while(isspace(*path)) path++;
2787 char * close = strchr(path, ')');
2791 strncpy(name, path+1, close - path - 1);
2792 name[close - path - 1] = '\0';
2793 for(p : ide.workspace.projects)
2795 if(!strcmp(p.name, name))
2805 prj = project ? project : (dir ? null : ide.project);
2808 strncpy(filePath, path, colon - path);
2809 filePath[colon - path] = '\0';
2810 line = atoi(colon + 1);
2811 colon = strstr(colon + 1, ":");
2813 col = atoi(colon + 1);
2815 else if(path - 1 >= text && *(path - 1) == '\"')
2817 colon = strchr(path, '\"');
2820 strncpy(filePath, path, colon - path);
2821 filePath[colon - path] = '\0';
2824 else if(path && !colon)
2826 strcpy(filePath, path);
2829 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2830 CodeLocationGoTo(completePath, fileAttribs, line, col);
2833 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2835 if(fileAttribs.isFile)
2837 char ext[MAX_EXTENSION];
2838 GetExtension(path, ext);
2840 if(binaryDocExt.Find(ext))
2842 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2843 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2845 char dirPath[MAX_LOCATION];
2846 StripLastDirectory(path, dirPath);
2851 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2852 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2854 EditBox editBox = codeEditor.editBox;
2855 editBox.GoToLineNum(line - 1);
2856 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2860 else if(fileAttribs.isDirectory)
2864 void OnRedraw(Surface surface)
2866 Bitmap bitmap = back.bitmap;
2868 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2871 void SheetSelected(SheetType sheetSelected)
2873 if(activeChild == sheet)
2875 if(sheetSelected == methods)
2877 viewPropertiesItem.accelerator = f4;
2878 viewPropertiesItem.parent = viewMenu;
2879 viewMethodsItem.parent = null;
2883 viewMethodsItem.accelerator = f4;
2884 viewMethodsItem.parent = viewMenu;
2885 viewPropertiesItem.parent = null;
2890 viewMethodsItem.parent = viewMenu;
2891 viewPropertiesItem.parent = viewMenu;
2892 if(sheetSelected == methods)
2894 viewMethodsItem.accelerator = f4;
2895 viewPropertiesItem.accelerator = 0;
2899 viewMethodsItem.accelerator = 0;
2900 viewPropertiesItem.accelerator = f4;
2905 void OnActivateClient(Window client, Window previous)
2907 //if(!client || client != previous)
2910 if(!client || client != previous)
2913 dataType = previous._class;
2914 if(previous && !strcmp(dataType.name, "CodeEditor"))
2916 ((CodeEditor)previous).UpdateFormCode();
2918 else if(previous && !strcmp(dataType.name, "Designer"))
2920 ((Designer)previous).codeEditor.UpdateFormCode();
2925 dataType = client._class;
2926 if(client && !strcmp(dataType.name, "CodeEditor"))
2928 CodeEditor codeEditor = (CodeEditor)client;
2929 SetPrivateModule(codeEditor.privateModule);
2930 SetCurrentContext(codeEditor.globalContext);
2931 SetTopContext(codeEditor.globalContext);
2932 SetGlobalContext(codeEditor.globalContext);
2934 SetDefines(&codeEditor.defines);
2935 SetImports(&codeEditor.imports);
2937 SetActiveDesigner(codeEditor.designer);
2939 sheet.codeEditor = codeEditor;
2940 toolBox.codeEditor = codeEditor;
2942 viewDesignerItem.parent = viewMenu;
2943 if(activeChild != codeEditor)
2945 viewCodeItem.parent = viewMenu;
2946 viewDesignerItem.accelerator = 0;
2947 viewCodeItem.accelerator = f8;
2951 viewCodeItem.parent = null;
2952 viewDesignerItem.accelerator = f8;
2955 else if(client && !strcmp(dataType.name, "Designer"))
2957 CodeEditor codeEditor = ((Designer)client).codeEditor;
2960 SetPrivateModule(codeEditor.privateModule);
2961 SetCurrentContext(codeEditor.globalContext);
2962 SetTopContext(codeEditor.globalContext);
2963 SetGlobalContext(codeEditor.globalContext);
2964 SetDefines(&codeEditor.defines);
2965 SetImports(&codeEditor.imports);
2969 SetPrivateModule(null);
2970 SetCurrentContext(null);
2971 SetTopContext(null);
2972 SetGlobalContext(null);
2977 SetActiveDesigner((Designer)client);
2979 sheet.codeEditor = codeEditor;
2980 toolBox.codeEditor = codeEditor;
2982 viewCodeItem.parent = viewMenu;
2983 if(activeChild != client)
2985 viewDesignerItem.parent = viewMenu;
2986 viewDesignerItem.accelerator = f8;
2987 viewCodeItem.accelerator = 0;
2991 viewDesignerItem.parent = null;
2992 viewCodeItem.accelerator = f8;
2997 if(!client && !projectView && sheet.visible)
3000 sheet.visible = false;
3001 toolBox.visible = false;
3004 sheet.codeEditor = null;
3005 toolBox.codeEditor = null;
3006 SetActiveDesigner(null);
3008 viewDesignerItem.parent = null;
3009 viewCodeItem.parent = null;
3012 SheetSelected(sheet.sheetSelected);
3015 projectCompileItem = null;
3020 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3022 CodeEditor codeEditor = (CodeEditor)client;
3023 EditBox editBox = codeEditor.editBox;
3025 statusBar.AddField(pos);
3027 caps = { width = 40, text = $"CAPS" };
3028 statusBar.AddField(caps);
3029 UpdateStateLight(caps, app.GetKeyState(capsState));
3031 ovr = { width = 36, text = $"OVR" };
3032 statusBar.AddField(ovr);
3033 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3035 num = { width = 36, text = $"NUM" };
3036 statusBar.AddField(num);
3037 UpdateStateLight(num, app.GetKeyState(numState));
3039 //statusBar.text = "Ready";
3041 if(projectView && projectView.project)
3043 bool isCObject = false;
3044 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3045 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3049 char nodeName[MAX_FILENAME];
3050 char name[MAX_FILENAME+96];
3052 ChangeExtension(node.name, "c", nodeName);
3053 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3054 projectCompileItem =
3056 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3058 bool NotifySelect(MenuItem selection, Modifiers mods)
3062 bool isCObject = false;
3063 bool isExcluded = false;
3064 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3068 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3071 List<ProjectNode> nodes { };
3073 projectView.Compile(node.project, nodes, false, false, isCObject ? cObject : normal);
3081 projectMenu.AddDynamic(projectCompileItem, ide, false);
3087 caps = ovr = num = null;
3092 bool OnClose(bool parentClosing)
3094 //return !projectView.buildInProgress;
3095 if(projectView && projectView.buildInProgress)
3097 if(DontTerminateDebugSession($"Close IDE"))
3099 if(findInFilesDialog)
3100 findInFilesDialog.SearchStop();
3103 workspace.timer.Stop();
3106 ideMainFrame.Destroy(0);
3113 bool passThrough = false;
3114 bool debugStart = false;
3115 bool debugWorkDir = false;
3116 char * passDebugWorkDir = null;
3117 bool openAsText = false;
3118 DynamicString passArgs { };
3121 for(c = 1; c<app.argc; c++)
3125 const char * arg = app.argv[c];
3126 char * buf = new char[strlen(arg)*2+1];
3128 passArgs.concat(" ");
3130 passArgs.concat(buf);
3133 else if(debugWorkDir)
3135 passDebugWorkDir = CopyString(app.argv[c]);
3136 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3137 debugWorkDir = false;
3139 else if(!strcmp(app.argv[c], "-t"))
3141 else if(!strcmp(app.argv[c], "-no-parsing"))
3142 ide.noParsing = true;
3143 else if(!strcmp(app.argv[c], "-debug-start"))
3145 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3146 debugWorkDir = true;
3147 else if(!strcmp(app.argv[c], "-@"))
3151 char fullPath[MAX_LOCATION];
3152 char parentPath[MAX_LOCATION];
3153 char ext[MAX_EXTENSION];
3155 FileAttribs dirAttribs;
3156 GetWorkingDir(fullPath, MAX_LOCATION);
3157 PathCat(fullPath, app.argv[c]);
3158 StripLastDirectory(fullPath, parentPath);
3159 GetExtension(app.argv[c], ext);
3160 isProject = !openAsText && !strcmpi(ext, "epj");
3162 if(isProject && c > (debugStart ? 2 : 1)) continue;
3164 // Create directory for projects (only)
3165 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3167 if(isProject && !FileExists(fullPath))
3169 char name[MAX_LOCATION];
3170 NewProjectDialog newProjectDialog;
3174 projectView.visible = false;
3175 if(!projectView.Destroy(0))
3179 newProjectDialog = { master = this };
3181 strcpy(name, app.argv[c]);
3182 StripExtension(name);
3183 GetLastDirectory(name, name);
3184 newProjectDialog.projectName.contents = name;
3185 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3186 newProjectDialog.locationEditBox.path = parentPath;
3187 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3189 incref newProjectDialog;
3190 newProjectDialog.Modal();
3193 ideSettings.AddRecentProject(projectView.fileName);
3194 ide.UpdateRecentMenus();
3195 settingsContainer.Save();
3197 delete newProjectDialog;
3198 // Open only one project
3202 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3204 else if(strstr(fullPath, "http://") == fullPath)
3205 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3208 if(passThrough && projectView && projectView.project && workspace)
3209 workspace.commandLineArgs = passArgs;
3210 if(passDebugWorkDir && projectView && projectView.project && workspace)
3212 workspace.debugDir = passDebugWorkDir;
3213 delete passDebugWorkDir;
3216 ;//MenuDebugStart(debugStartResumeItem, 0); // <-- how TODO this without getting into the app.Wait lock
3218 UpdateToolBarActiveConfigs(false);
3219 UpdateToolBarActiveCompilers();
3226 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3229 projectView.visible = false;
3230 projectView.Destroy(0);
3233 #ifdef GDB_DEBUG_GUI
3234 gdbDialog.Destroy(0);
3239 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3243 char * oldPaths[128];
3244 String oldList = new char[maxPathLen];
3245 Array<String> newExePaths { };
3246 //Map<String, bool> exePathExists { };
3248 #if defined(__unix__) || defined(__APPLE__)
3249 Array<String> newLibPaths { };
3250 Map<String, bool> libPathExists { };
3255 for(prj : workspace.projects)
3257 DirExpression targetDirExp;
3259 // SKIP FIRST PROJECT...
3260 if(prj == workspace.projects.firstIterator.data) continue;
3262 // NOTE: Right now the additional project config dir will be
3263 // obtained when the debugger is started, so toggling it
3264 // while building will change which library gets used.
3265 // To go with the initial state, e.g. when F5 was pressed,
3266 // we nould need to keep a list of all project's active
3267 // config upon startup.
3268 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3270 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3274 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3275 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3279 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3280 if(cfg.targetType == sharedLibrary && cfg.debug)
3284 if(targetDirExp.dir)
3286 char buffer[MAX_LOCATION];
3287 #if defined(__WIN32__)
3288 Array<String> paths = newExePaths;
3290 Array<String> paths = newLibPaths;
3292 GetSystemPathBuffer(buffer, prj.topNode.path);
3293 PathCat(buffer, targetDirExp.dir);
3296 if(!fstrcmp(p, buffer))
3303 paths.Add(CopyString(buffer));
3305 delete targetDirExp;
3309 for(item : compiler.executableDirs)
3311 DirExpression dirExpr { };
3312 dirExpr.Evaluate(item, null, compiler, null, 0);
3315 for(p : newExePaths)
3317 if(!fstrcmp(p, dirExpr.dir))
3324 newExePaths.Add(CopySystemPath(dirExpr.dir));
3328 GetEnvironment("PATH", oldList, maxPathLen);
3330 printf("Old value of PATH: %s\n", oldList);
3332 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3333 for(c = 0; c < count; c++)
3336 for(p : newExePaths)
3338 if(!fstrcmp(p, oldPaths[c]))
3345 newExePaths.Add(CopySystemPath(oldPaths[c]));
3349 for(path : newExePaths)
3350 len += strlen(path) + 1;
3351 newList = new char[len + 1];
3353 for(path : newExePaths)
3355 strcat(newList, path);
3356 strcat(newList, pathListSep);
3358 newList[len - 1] = '\0';
3359 SetEnvironment("PATH", newList);
3361 printf("New value of PATH: %s\n", newList);
3368 #if defined(__unix__) || defined(__APPLE__)
3370 for(item : compiler.libraryDirs)
3372 if(!libPathExists[item]) // fstrcmp should be used
3374 String s = CopyString(item);
3376 libPathExists[s] = true;
3380 #if defined(__APPLE__)
3381 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3383 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3386 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3388 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3389 for(c = 0; c < count; c++)
3391 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3393 String s = CopyString(oldPaths[c]);
3395 libPathExists[s] = true;
3400 for(path : newLibPaths)
3401 len += strlen(path) + 1;
3402 newList = new char[len + 1];
3404 for(path : newLibPaths)
3406 strcat(newList, path);
3407 strcat(newList, pathListSep);
3409 newList[len - 1] = '\0';
3410 #if defined(__APPLE__)
3411 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3413 SetEnvironment("LD_LIBRARY_PATH", newList);
3416 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3422 delete libPathExists;
3425 if(compiler.distccEnabled && compiler.distccHosts)
3426 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3431 void DestroyTemporaryProjectDir()
3433 if(tmpPrjDir && tmpPrjDir[0])
3435 if(FileExists(tmpPrjDir).isDirectory)
3436 DestroyDir(tmpPrjDir);
3437 property::tmpPrjDir = null;
3443 // Graphics Driver Menu
3446 app.currentSkin.selectionColor = selectionColor;
3447 app.currentSkin.selectionText = selectionText;
3451 driverItems = new MenuItem[app.numDrivers];
3452 for(c = 0; c < app.numDrivers; c++)
3454 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3455 driverItems[c].id = c;
3456 driverItems[c].isRadio = true;
3459 driverItems = new MenuItem[2];
3460 #if defined(__unix__)
3461 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3462 driverItems[0].id = 0;
3463 driverItems[0].isRadio = true;
3465 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3466 driverItems[0].id = 0;
3467 driverItems[0].isRadio = true;
3469 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3470 driverItems[1].id = 1;
3471 driverItems[1].isRadio = true;
3473 /* skinItems = new MenuItem[app.numSkins];
3474 for(c = 0; c < app.numSkins; c++)
3476 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3477 skinItems[c].id = c;
3478 skinItems[c].isRadio = true;
3481 ideFileDialog.master = this;
3482 ideProjectFileDialog.master = this;
3484 //SetDriverAndSkin();
3488 void UpdateRecentMenus()
3491 Menu fileMenu = menu.FindMenu($"File");
3492 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3493 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3494 char * itemPath = new char[MAX_LOCATION];
3495 char * itemName = new char[MAX_LOCATION+4];
3497 recentFiles.Clear();
3500 for(recent : ideSettings.recentFiles)
3502 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3503 MakeSystemPath(itemPath);
3504 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3505 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3509 recentProjects.Clear();
3511 for(recent : ideSettings.recentProjects)
3513 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3514 MakeSystemPath(itemPath);
3515 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3516 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3528 delete languageItems;
3532 documentor.Puts("Quit\n");
3539 void DestroyDir(char * path)
3541 RecursiveDeleteFolderFSI fsi { };
3546 #if defined(__WIN32__)
3547 define sdkDirName = "Ecere SDK";
3549 define sdkDirName = "ecere";
3552 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3555 char * v = new char[maxPathLen];
3559 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3560 StripLastDirectory(path, path);
3561 PathCat(path, subDir);
3562 if(name) PathCat(path, name);
3563 if(FileExists(path) & attribs) found = true;
3565 #if defined(__WIN32__)
3568 GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3571 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3572 PathCat(path, subDir);
3573 if(name) PathCat(path, name);
3574 if(FileExists(path) & attribs) found = true;
3579 GetEnvironment("AppData", v, maxPathLen);
3582 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3583 PathCat(path, sdkDirName);
3584 PathCat(path, subDir);
3585 if(name) PathCat(path, name);
3586 if(FileExists(path) & attribs) found = true;
3591 GetEnvironment("ProgramData", v, maxPathLen);
3594 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3595 PathCat(path, sdkDirName);
3596 PathCat(path, subDir);
3597 if(name) PathCat(path, name);
3598 if(FileExists(path) & attribs) found = true;
3603 GetEnvironment("ProgramFiles", v, maxPathLen);
3606 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3607 PathCat(path, sdkDirName);
3608 PathCat(path, subDir);
3609 if(name) PathCat(path, name);
3610 if(FileExists(path) & attribs) found = true;
3615 GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3618 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3619 PathCat(path, sdkDirName);
3620 PathCat(path, subDir);
3621 if(name) PathCat(path, name);
3622 if(FileExists(path) & attribs) found = true;
3627 GetEnvironment("SystemDrive", v, maxPathLen);
3630 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3631 PathCat(path, "Program Files");
3632 PathCat(path, sdkDirName);
3633 PathCat(path, subDir);
3634 if(name) PathCat(path, name);
3635 if(FileExists(path) & attribs) found = true;
3644 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3645 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3646 for(c=0; c<numTokens; c++)
3648 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3649 PathCat(path, sdkDirName);
3650 PathCat(path, subDir);
3651 if(name) PathCat(path, name);
3652 if(FileExists(path) & attribs) found = true;
3660 void FindAndShellOpenInstalledFolder(const char * name)
3662 char path[MAX_LOCATION];
3663 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3667 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3669 char path[MAX_LOCATION];
3670 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3674 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3676 bool preserveRootFolder;
3678 void OutFolder(const char * folderPath, bool isRoot)
3680 if(!(preserveRootFolder && isRoot))
3681 RemoveDir(folderPath);
3684 bool OnFile(const char * filePath)
3686 DeleteFile(filePath);
3691 class IDEApp : GuiApplication
3693 //driver = "Win32Console";
3694 // driver = "OpenGL";
3698 TempFile includeFile { };
3703 char ext[MAX_EXTENSION];
3704 SetLoggingMode(stdOut, null);
3705 //SetLoggingMode(debug, null);
3707 settingsContainer.Load();
3709 if(ideSettings.language)
3711 const String language = GetLanguageString();
3712 if(ideSettings.language.OnCompare(language))
3714 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3719 // First count files arg to decide whether to maximize
3721 bool passThrough = false, debugWorkDir = false;
3724 for(c = 1; c<app.argc; c++)
3727 else if(debugWorkDir)
3728 debugWorkDir = false;
3729 else if(!strcmp(app.argv[c], "-t"));
3730 else if(!strcmp(app.argv[c], "-no-parsing"));
3731 else if(!strcmp(app.argv[c], "-debug-start"));
3732 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3733 debugWorkDir = true;
3734 else if(!strcmp(app.argv[c], "-@"))
3741 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3743 app.driver = "OpenGL";
3744 ide.driverItems[1].checked = true;
3748 #if defined(__unix__) || defined(__APPLE__)
3749 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3751 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3753 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3757 char model[MAX_LOCATION];
3758 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3760 ide.duck.modelFile = model;
3761 ide.duck.parent = ideMainFrame;
3764 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3765 ide.debugRubberDuck.disabled = false;
3769 desktop.caption = titleECEREIDE;
3772 for(c = 1; c<app.argc; c++)
3774 char fullPath[MAX_LOCATION];
3775 GetWorkingDir(fullPath, MAX_LOCATION);
3776 PathCat(fullPath, app.argv[c]);
3777 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3781 // Default to language specified by environment if no language selected
3782 if(!ideSettings.language)
3784 ideSettings.language = GetLanguageString();
3785 settingsContainer.Save();
3788 // Default to home directory if no directory yet set up
3789 if(!ideSettings.ideProjectFileDialogLocation[0])
3792 char location[MAX_LOCATION];
3793 char * home = getenv("HOME");
3794 char * homeDrive = getenv("HOMEDRIVE");
3795 char * homePath = getenv("HOMEPATH");
3796 char * userProfile = getenv("USERPROFILE");
3797 char * systemDrive = getenv("SystemDrive");
3798 if(home && FileExists(home).isDirectory)
3800 strcpy(location, home);
3803 if(!found && homeDrive && homePath)
3805 strcpy(location, homeDrive);
3806 PathCat(location, homePath);
3807 if(FileExists(location).isDirectory)
3810 if(!found && FileExists(userProfile).isDirectory)
3812 strcpy(location, userProfile);
3815 if(!found && FileExists(systemDrive).isDirectory)
3817 strcpy(location, systemDrive);
3822 ideSettings.ideProjectFileDialogLocation = location;
3823 if(!ideSettings.ideFileDialogLocation[0])
3824 ideSettings.ideFileDialogLocation = location;
3828 if(!LoadIncludeFile())
3829 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3831 // Create language menu
3833 String language = ideSettings.language;
3837 ide.languageItems = new MenuItem[languages.count];
3840 ide.languageItems[i] =
3842 ide.languageMenu, l.name;
3843 bitmap = { l.bitmap };
3847 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3849 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3851 // Re-select previous selected language if aborted
3852 String language = ideSettings.language;
3856 if(((!language || !language[0]) && i == 0) ||
3857 (language && !strcmpi(l.code, language)))
3859 ide.languageItems[i].checked = true;
3871 // Try to find country-specific language first
3877 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3879 ide.languageItems[i].checked = true;
3887 // Try generalizing locale
3888 if(!found && language)
3891 char genericLocale[256];
3893 strncpy(genericLocale, language, sizeof(genericLocale));
3894 genericLocale[sizeof(genericLocale)-1] = 0;
3896 under = strchr(genericLocale, '_');
3899 if(!strcmpi(genericLocale, "zh"))
3900 strcpy(genericLocale, "zh_CN");
3901 if(strcmp(genericLocale, language))
3905 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3907 ide.languageItems[i].checked = true;
3917 ide.languageItems[0].checked = true;
3919 MenuDivider { ide.languageMenu };
3922 ide.languageMenu, "Help Translate";
3924 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3926 ShellOpen("http://translations.launchpad.net/ecere");
3932 ideMainFrame.Create();
3933 if(app.argFilesCount > 1)
3934 ide.MenuWindowTileVert(null, 0);
3938 bool Cycle(bool idle)
3942 if(ide.documentor.Peek())
3945 ide.documentor.GetLine(line, sizeof(line));
3946 if(!strcmpi(line, "Exited"))
3948 ide.documentor.CloseInput();
3949 ide.documentor.CloseOutput();
3950 ide.documentor.Wait();
3951 delete ide.documentor;
3954 if(ide.documentor && ide.documentor.eof)
3956 ide.documentor.CloseInput();
3957 ide.documentor.CloseOutput();
3958 ide.documentor.Wait();
3959 delete ide.documentor;
3965 bool LoadIncludeFile()
3967 bool result = false;
3968 File include = FileOpen(":crossplatform.mk", read);
3971 File f = includeFile;
3974 for(; !include.Eof(); )
3977 int count = include.Read(buffer, 1, 4096);
3978 f.Write(buffer, 1, count);
3988 IDEMainFrame ideMainFrame { };
3990 define app = ((IDEApp)__thisModule);
3992 define titleECEREIDE = $"Ecere IDE (Debug)";
3994 define titleECEREIDE = $"Ecere IDE";