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);
1643 #ifdef GDB_DEBUG_GUI
1646 master = this, parent = this;
1647 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1649 void OnCommand(const char * string)
1652 ide.debugger.SendGDBCommand(string);
1657 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1659 //app.driver = app.drivers[selection.id];
1660 #if defined(__unix__) || defined(__APPLE__)
1661 app.driver = selection.id ? "OpenGL" : "X";
1663 app.driver = selection.id ? "OpenGL" : "GDI";
1665 delete ideSettings.displayDriver;
1666 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1668 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1670 settingsContainer.Save();
1671 //SetDriverAndSkin();
1675 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1677 app.skin = app.skins[selection.id];
1682 void SetDriverAndSkin()
1685 for(c = 0; c < app.numSkins; c++)
1686 if(!strcmp(app.skins[c], app.skin))
1688 skinItems[c].checked = true;
1691 for(c = 0; c < app.numDrivers; c++)
1692 if(!strcmp(app.drivers[c], app.driver))
1694 driverItems[c].checked = true;
1699 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1701 Project project = workspace.projects.firstIterator.data;
1702 projectView = ProjectView
1705 fileName = fileName;
1707 void NotifyDestroyed(Window window, DialogResult result)
1710 text = titleECEREIDE;
1715 projectView.Create();
1716 RepositionWindows(false);
1718 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1719 projectView.workspace = workspace;
1720 projectView.project = project;
1721 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1725 ide.breakpointsView.LoadFromWorkspace();
1726 ide.watchesView.LoadFromWorkspace();
1728 findInFilesDialog.projectNodeField.userData = projectView;
1731 char fileName[MAX_LOCATION];
1732 strcpy(fileName, project.topNode.path);
1733 PathCat(fileName, project.topNode.name);
1740 projectView.visible = false;
1741 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1743 if(findInFilesDialog)
1745 char workingDir[MAX_LOCATION];
1746 GetWorkingDir(workingDir, MAX_LOCATION);
1747 findInFilesDialog.SearchStop();
1748 findInFilesDialog.currentDirectory = workingDir;
1750 sheet.visible = false;
1751 toolBox.visible = false;
1752 outputView.visible = false;
1753 ideMainFrame.text = titleECEREIDE;
1760 void RepositionWindows(bool expand)
1765 bool callStackVisible = expand ? false : callStackView.visible;
1766 bool threadsVisible = expand ? false : threadsView.visible;
1767 bool watchesVisible = expand ? false : watchesView.visible;
1768 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1769 bool toolBoxVisible = toolBox.visible;
1770 bool outputVisible = expand ? false : outputView.visible;
1771 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1772 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1774 for(child = firstChild; child; child = child.next)
1776 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1777 child._class == class(Sheet) || child._class == class(ProjectView))
1779 Anchor anchor = child.anchor;
1780 anchor.top = topDistance;
1781 anchor.bottom = bottomDistance;
1782 if(child._class == class(CodeEditor) || child._class == class(Designer))
1784 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1785 anchor.right = toolBoxVisible ? 150 : 0;
1788 child.anchor = anchor;
1792 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1793 child._class == class(BreakpointsView))
1794 child.visible = false;
1797 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1799 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1803 bool ShowCodeEditor()
1806 activeClient.Activate();
1807 else if(projectView)
1809 projectView.visible = true;
1810 projectView.Activate();
1812 else if(sheet.visible)
1815 outputView.visible = false;
1819 void DocumentSaved(Window document, const char * fileName)
1821 ideSettings.AddRecentFile(fileName);
1822 ide.UpdateRecentMenus();
1823 ide.AdjustFileMenus();
1824 settingsContainer.Save();
1827 bool Window::OnFileModified(FileChange fileChange, const char * param)
1830 sprintf(temp, $"The document %s was modified by another application.\n"
1831 "Would you like to reload it and lose your changes?", this.fileName);
1832 if(MessageBox { type = yesNo, master = this/*.parent*/,
1833 text = $"Document has been modified", contents = temp }.Modal() == yes)
1835 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1836 char * fileName = CopyString(this.fileName);
1837 WindowState state = this.state;
1838 Anchor anchor = this.anchor;
1839 Size size = this.size;
1841 this.modifiedDocument = false;
1843 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1846 this.anchor = anchor;
1848 this.SetState(state, true, 0);
1856 void UpdateMakefiles()
1860 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1861 for(prj : workspace.projects)
1862 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1867 void UpdateCompilerConfigs(bool mute)
1869 UpdateToolBarActiveCompilers();
1872 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1873 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1876 projectView.ShowOutputBuildLog(true);
1877 projectView.DisplayCompiler(compiler, false);
1879 for(prj : workspace.projects)
1880 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1885 void UpdateToolBarActiveCompilers()
1887 toolBar.activeCompiler.Clear();
1888 for(compiler : ideSettings.compilerConfigs)
1890 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1891 if(workspace && workspace.compiler && !strcmp(compiler.name, workspace.compiler))
1892 toolBar.activeCompiler.currentRow = row;
1894 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1895 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1898 void UpdateToolBarActiveConfigs(bool selectionOnly)
1900 bool commonSelected = false;
1901 DataRow row = toolBar.activeConfig.currentRow;
1903 row = toolBar.activeConfig.FindRow(1);
1906 toolBar.activeConfig.Clear();
1907 row = toolBar.activeConfig.AddString($"(Mixed)");
1912 char * configName = null;
1915 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1916 for(prj : workspace.projects)
1918 for(cfg : prj.configurations)
1921 configs[cfg.name] = 1;
1926 toolBar.activeConfig.AddString(&name);
1930 if(projectView && projectView.project)
1932 for(prj : workspace.projects)
1934 if(prj.config && prj.config.name)
1936 configName = prj.config.name;
1942 commonSelected = true;
1943 for(prj : workspace.projects)
1945 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1947 commonSelected = false;
1955 commonSelected = false;
1956 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1958 if(!strcmp(row.string, configName))
1960 toolBar.activeConfig.currentRow = row;
1961 commonSelected = true;
1968 toolBar.activeConfig.Sort(null, 0);
1970 toolBar.activeConfig.currentRow = row;
1975 bool unavailable = !project;
1977 projectAddItem.disabled = unavailable;
1978 toolBar.buttonAddProject.disabled = unavailable;
1980 projectSettingsItem.disabled = unavailable;
1982 projectBrowseFolderItem.disabled = unavailable;
1984 viewProjectItem.disabled = unavailable;
1986 toolBar.activeConfig.disabled = unavailable;
1987 toolBar.activeCompiler.disabled = unavailable;
1988 toolBar.activeBitDepth.disabled = unavailable;
1991 debugUseValgrindItem.disabled = unavailable;
1992 AdjustValgrindMenus();
2001 void AdjustValgrindMenus()
2003 bool unavailable = !project || !debugUseValgrindItem.checked;
2004 debugValgrindNoLeakCheckItem.disabled = unavailable;
2005 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2006 debugValgrindYesLeakCheckItem.disabled = unavailable;
2007 debugValgrindFullLeakCheckItem.disabled = unavailable;
2009 debugValgrindTrackOriginsItem.disabled = unavailable;
2011 debugValgrindRSDefaultItem.disabled = unavailable;
2012 debugValgrindRS0Item.disabled = unavailable;
2013 debugValgrindRS16Item.disabled = unavailable;
2014 debugValgrindRS32Item.disabled = unavailable;
2015 debugValgrindRS64Item.disabled = unavailable;
2016 debugValgrindRS128Item.disabled = unavailable;
2017 debugValgrindRS256Item.disabled = unavailable;
2018 debugValgrindRS512Item.disabled = unavailable;
2022 property bool hasOpenedCodeEditors
2027 for(w = firstChild; w; w = w.next)
2028 if(w._class == class(CodeEditor) &&
2029 w.isDocument && !w.closing && w.visible && w.created &&
2030 w.fileName && w.fileName[0])
2036 void AdjustFileMenus()
2038 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2040 projectQuickItem.disabled = unavailable;
2043 void AdjustBuildMenus()
2045 bool unavailable = project && projectView.buildInProgress;
2046 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2048 projectNewItem.disabled = unavailable;
2049 toolBar.buttonNewProject.disabled = unavailable;
2050 projectOpenItem.disabled = unavailable;
2051 toolBar.buttonOpenProject.disabled = unavailable;
2053 unavailable = !project || projectView.buildInProgress;
2055 projectCloseItem.disabled = unavailable;
2056 // toolBar.buttonCloseProject.disabled = unavailable;
2058 projectRunItem.disabled = naForRun;
2059 toolBar.buttonRun.disabled = naForRun;
2061 projectBuildItem.disabled = false;
2062 projectBuildItem.text = unavailable ? $"Stop Build" : $"Build";
2063 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2065 projectLinkItem.disabled = unavailable;
2066 toolBar.buttonReLink.disabled = unavailable;
2067 projectRebuildItem.disabled = unavailable;
2068 toolBar.buttonRebuild.disabled = unavailable;
2069 projectCleanItem.disabled = unavailable;
2070 toolBar.buttonClean.disabled = unavailable;
2071 projectCleanTargetItem.disabled = unavailable;
2072 projectRealCleanItem.disabled = unavailable;
2073 // toolBar.buttonRealClean.disabled = unavailable;
2074 projectRegenerateItem.disabled = unavailable;
2075 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2076 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2077 projectInstallItem.disabled = unavailable;
2078 toolBar.buttonInstall.disabled = unavailable;
2080 projectCompileItem.disabled = unavailable;
2082 AdjustPopupBuildMenus();
2085 void AdjustPopupBuildMenus()
2087 bool unavailable = !project || projectView.buildInProgress;
2089 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2092 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
2095 menu.disabled = false;
2096 menu.text = unavailable ? $"Stop Build" : $"Build";
2097 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2100 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0); if(menu) menu.disabled = unavailable;
2101 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0); if(menu) menu.disabled = unavailable;
2102 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0); if(menu) menu.disabled = unavailable;
2103 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0); if(menu) menu.disabled = unavailable;
2104 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0); if(menu) menu.disabled = unavailable;
2105 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
2106 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, 0); if(menu) menu.disabled = unavailable;
2107 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0); if(menu) menu.disabled = unavailable;
2108 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0); if(menu) menu.disabled = unavailable;
2109 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0); if(menu) menu.disabled = unavailable;
2110 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0); if(menu) menu.disabled = unavailable;
2111 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0); if(menu) menu.disabled = unavailable;
2112 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
2113 projectView.popupMenu.Update(null);
2117 property bool areDebugMenusUnavailable { get {
2119 project.GetTargetType(project.config) != executable ||
2120 projectView.buildInProgress == buildingMainProject;
2123 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2124 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2125 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2127 void AdjustDebugMenus()
2129 bool unavailable = areDebugMenusUnavailable;
2130 bool running = isDebuggerRunning;
2131 bool stopped = isDebuggerStopped;
2132 bool active = debugger.isActive;
2134 bool isNotRunning = unavailable || !running;
2135 bool isNotNotRunning = unavailable || running;
2136 bool isNotStopped = unavailable || !stopped;
2137 bool isNotActive = unavailable || !active;
2139 debugStartResumeItem.disabled = isNotNotRunning;
2140 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2141 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2144 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2145 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2148 debugBreakItem.disabled = isNotRunning;
2149 debugStopItem.disabled = isNotActive;
2150 debugRestartItem.disabled = isNotActive;
2153 toolBar.buttonDebugPause.disabled = isNotRunning;
2154 toolBar.buttonDebugStop.disabled = isNotActive;
2155 toolBar.buttonDebugRestart.disabled = isNotActive;
2158 debugStepIntoItem.disabled = isNotNotRunning;
2159 debugStepOverItem.disabled = isNotNotRunning;
2160 debugSkipStepOverItem.disabled = isNotNotRunning;
2161 debugStepOutItem.disabled = isNotStopped;
2162 debugSkipStepOutItem.disabled = isNotStopped;
2164 debugStepUntilItem.disabled = isNotStopped;
2165 debugSkipStepUntilItem.disabled = isNotStopped;
2169 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2170 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2171 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2172 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2173 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2175 if((Designer)GetActiveDesigner())
2177 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2179 codeEditor.AdjustDebugMenus();
2183 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2185 char tempString[MAX_LOCATION];
2186 strcpy(tempString, directory);
2187 if(saveSettings && !projectView)
2189 ideSettings.ideFileDialogLocation = directory;
2190 settingsContainer.Save();
2193 ideFileDialog.currentDirectory = tempString;
2194 codeEditorFileDialog.currentDirectory = tempString;
2195 codeEditorFormFileDialog.currentDirectory = tempString;
2198 void ChangeProjectFileDialogDirectory(char * directory)
2200 ideSettings.ideProjectFileDialogLocation = directory;
2201 settingsContainer.Save();
2204 Window FindWindow(const char * filePath)
2206 Window document = null;
2208 // TOCHECK: Do we need to change slashes here?
2209 for(document = firstChild; document; document = document.next)
2211 const char * fileName = document.fileName;
2212 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2214 document.visible = true;
2215 document.Activate();
2222 bool DontTerminateDebugSession(const char * title)
2224 if(debugger.isActive)
2226 if(MessageBox { type = yesNo, master = ide,
2227 contents = $"Do you want to terminate the debugging session in progress?",
2228 text = title }.Modal() == no)
2231 MessageBox msg { type = yesNo, master = ide,
2232 contents = "Do you want to terminate the debugging session in progress?",
2234 if(msg.Modal() == no)
2246 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2248 char extension[MAX_EXTENSION] = "";
2249 Window document = null;
2250 bool isProject = false;
2251 bool needFileModified = true;
2252 char winFilePath[MAX_LOCATION];
2253 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2254 Window currentDoc = activeClient;
2255 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2258 GetExtension(filePath, extension);
2262 strcpy(extension, type);
2264 if(strcmp(extension, ProjectExtension))
2266 for(document = firstChild; document; document = document.next)
2268 const char * fileName = document.fileName;
2269 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2271 document.visible = true;
2273 document.Activate();
2279 if(createIfFails == whatever)
2281 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2283 needFileModified = false;
2284 if(openMethod == normal)
2286 if(DontTerminateDebugSession($"Open Project"))
2295 Workspace workspace = null;
2297 if(FileExists(filePath))
2299 if(!strcmp(extension, ProjectExtension))
2301 char workspaceFile[MAX_LOCATION];
2302 strcpy(workspaceFile, filePath);
2303 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2304 workspace = LoadWorkspace(workspaceFile, filePath);
2306 else if(!strcmp(extension, WorkspaceExtension))
2307 workspace = LoadWorkspace(filePath, null);
2314 CreateProjectView(workspace, filePath);
2315 document = projectView;
2317 toolBox.visible = true;
2318 sheet.visible = true;
2319 projectView.MakeActive();
2321 workspace.ParseLoadedBreakpoints();
2322 workspace.DropInvalidBreakpoints(null);
2325 ide.projectView.ShowOutputBuildLog(true);
2327 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2328 ide.projectView.DisplayCompiler(compiler, false);
2331 UpdateCompilerConfigs(false);
2334 char newWorkingDir[MAX_LOCATION];
2335 StripLastDirectory(filePath, newWorkingDir);
2336 ChangeFileDialogsDirectory(newWorkingDir, false);
2339 document.fileName = filePath;
2341 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2343 // this crashes on starting ide with epj file, solution please?
2344 // app.UpdateDisplay();
2346 workspace.holdTracking = true;
2347 for(ofi : workspace.openedFiles)
2349 if(ofi.state != closed)
2351 Window file = OpenFile(ofi.path, false, true, null, no, normal, noParsing);
2354 char fileName[MAX_LOCATION];
2356 GetLastDirectory(ofi.path, fileName);
2357 node = projectView.project.topNode.Find(fileName, true);
2359 node.EnsureVisible();
2363 ide.RepositionWindows(false);
2364 workspace.holdTracking = false;
2366 workspace.timer.Start();
2368 #if !defined(__WIN32__)
2369 // Valgrind Debug menu updates
2370 debugUseValgrindItem.checked = workspace.useValgrind;
2372 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2373 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2374 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2375 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2377 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2378 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2379 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2380 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2381 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2382 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2383 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2384 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2386 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2389 findInFilesDialog.mode = FindInFilesMode::project;
2390 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2393 char location[MAX_LOCATION];
2394 StripLastDirectory(ide.project.topNode.path, location);
2395 ChangeProjectFileDialogDirectory(location);
2402 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2404 ideProjectFileDialog.text = openProjectFileDialogTitle;
2405 if(ideProjectFileDialog.Modal() == cancel)
2407 filePath = ideProjectFileDialog.filePath;
2408 GetExtension(filePath, extension);
2419 else if(openMethod == add)
2424 char slashFilePath[MAX_LOCATION];
2425 GetSlashPathBuffer(slashFilePath, filePath);
2426 for(p : workspace.projects)
2428 if(!fstrcmp(p.filePath, slashFilePath))
2436 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2437 contents = $"This project is already present in workspace." }.Modal();
2441 prj = LoadProject(filePath, null);
2444 const char * activeConfigName = null;
2445 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2446 prj.StartMonitoring();
2447 workspace.projects.Add(prj);
2448 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2449 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2450 activeConfigName = toolBar.activeConfig.currentRow.string;
2451 if(activeConfigName)
2453 for(cfg : prj.configurations)
2455 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2463 projectView.AddNode(prj.topNode, null);
2464 workspace.modified = true;
2466 findInFilesDialog.AddProjectItem(prj);
2467 projectView.ShowOutputBuildLog(true);
2468 projectView.DisplayCompiler(compiler, false);
2469 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2473 char location[MAX_LOCATION];
2474 StripLastDirectory(prj.topNode.path, location);
2475 ChangeProjectFileDialogDirectory(location);
2478 // projectView is associated with the main project and not with the one just added but
2479 return projectView; // just to let the caller know something was opened
2487 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2488 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2489 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2491 if(FileExists(filePath))
2492 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2493 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2494 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2497 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2500 else if(!strcmp(extension, "3ds"))
2502 if(FileExists(filePath))
2503 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2504 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2505 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2509 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2512 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2513 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2514 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2515 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2516 !strcmp(extension, "js"))
2518 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2519 editor.updatingCode = true;
2520 if(editor.LoadFile(filePath))
2523 editor.visible = true;
2527 needFileModified = false;
2531 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2532 if(editor.LoadFile(filePath))
2535 editor.visible = true;
2539 needFileModified = false;
2542 if(document && (document._class == class(PictureEdit) ||
2543 document._class == class(ModelView)))
2548 document.fileName = filePath;
2549 if(workspace && !workspace.holdTracking)
2550 workspace.UpdateOpenedFileInfo(filePath, opened);
2554 if(!document && createIfFails != no)
2556 if(createIfFails != yes && !needFileModified &&
2557 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2558 createIfFails = yes;
2559 if(createIfFails == yes || createIfFails == whatever)
2561 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2563 document.fileName = filePath;
2569 if(projectView && document._class == class(CodeEditor) && workspace)
2571 int lineNumber, position;
2573 CodeEditor editor = (CodeEditor)document;
2574 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2575 editor.openedFileInfo.holdTracking = true;
2576 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2577 position = Max(editor.openedFileInfo.position - 1, 0);
2578 if(editor.editBox.GoToLineNum(lineNumber))
2579 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2580 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2581 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2582 editor.editBox.scroll = scroll;
2583 editor.openedFileInfo.holdTracking = false;
2586 if(needFileModified)
2587 document.OnFileModified = OnFileModified;
2588 document.NotifySaved = DocumentSaved;
2589 if(maximizeDoc && document.hasMaximize)
2590 document.state = maximized;
2593 ideSettings.AddRecentProject(document.fileName);
2595 ideSettings.AddRecentFile(document.fileName);
2596 ide.UpdateRecentMenus();
2597 ide.AdjustFileMenus();
2598 settingsContainer.Save();
2606 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2607 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2609 if(!parentClosing && ide.workspace)
2610 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2613 bool ModelView::ModelViewOnClose(bool parentClosing)
2615 if(!parentClosing && ide.workspace)
2616 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2619 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2621 if(!parentClosing && ide.workspace)
2622 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2627 void OnUnloadGraphics(Window window)
2629 display.ClearMaterials();
2630 display.ClearTextures();
2631 display.ClearMeshes();
2635 void UpdateStateLight(StatusField fld, bool on)
2637 fld.color = on ? lime : Color { 128,128,128 };
2638 fld.backColor = on ? dimGray : 0;
2642 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2644 UpdateStateLight(caps, app.GetKeyState(capsState));
2645 UpdateStateLight(num, app.GetKeyState(numState));
2649 bool OnKeyDown(Key key, unichar ch)
2653 case b: projectView.Update(null); break;
2654 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2655 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2660 bool OnKeyUp(Key key, unichar ch)
2664 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2665 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2670 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2673 projectView.GoToError(line, noParsing, objectFileExt);
2676 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2678 FileAttribs result { };
2679 FileAttribs fileAttribs;
2683 strcpy(selectedPath, prj.topNode.path);
2684 else if(dir && dir[0])
2685 strcpy(selectedPath, dir);
2687 selectedPath[0] = '\0';
2688 PathCat(selectedPath, filePath);
2690 if((fileAttribs = FileExists(selectedPath)).isFile)
2691 result = fileAttribs;
2695 for(p : workspace.projects)
2697 strcpy(selectedPath, p.topNode.path);
2698 PathCat(selectedPath, filePath);
2699 if((fileAttribs = FileExists(selectedPath)).isFile)
2702 result = fileAttribs;
2709 ProjectNode n = null;
2710 for(p : workspace.projects)
2712 if((n = p.topNode.Find(filePath, false)))
2714 n.GetFullFilePath(selectedPath);
2715 if((fileAttribs = FileExists(selectedPath)).isFile)
2718 result = fileAttribs;
2723 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2724 (fileAttribs = FileExists(selectedPath)).isFile)
2727 result = fileAttribs;
2735 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2738 const char *path = text;
2739 char *colon = strchr(text, ':');
2740 char filePath[MAX_LOCATION] = "";
2741 char completePath[MAX_LOCATION];
2742 int line = 0, col = 0;
2743 int len = strlen(text);
2745 FileAttribs fileAttribs;
2747 // support for valgrind output
2748 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2759 /*for(s=colon; *s; s++)
2768 //line = atoi(colon+1);
2770 // support for "Found n match(es) in "file/path";
2771 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)
2777 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2779 path = (colon - 1 > path) ? colon - 1 : path;
2780 colon = strstr(colon + 1, ":");
2782 if(*path == '*' && (s = strchr(path+1, '*')))
2784 while(isspace(*path)) path++;
2788 char * close = strchr(path, ')');
2792 strncpy(name, path+1, close - path - 1);
2793 name[close - path - 1] = '\0';
2794 for(p : ide.workspace.projects)
2796 if(!strcmp(p.name, name))
2806 prj = project ? project : (dir ? null : ide.project);
2809 strncpy(filePath, path, colon - path);
2810 filePath[colon - path] = '\0';
2811 line = atoi(colon + 1);
2812 colon = strstr(colon + 1, ":");
2814 col = atoi(colon + 1);
2816 else if(path - 1 >= text && *(path - 1) == '\"')
2818 colon = strchr(path, '\"');
2821 strncpy(filePath, path, colon - path);
2822 filePath[colon - path] = '\0';
2825 else if(path && !colon)
2827 strcpy(filePath, path);
2830 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2831 CodeLocationGoTo(completePath, fileAttribs, line, col);
2834 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2836 if(fileAttribs.isFile)
2838 char ext[MAX_EXTENSION];
2839 GetExtension(path, ext);
2841 if(binaryDocExt.Find(ext))
2843 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2844 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2846 char dirPath[MAX_LOCATION];
2847 StripLastDirectory(path, dirPath);
2852 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2853 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2855 EditBox editBox = codeEditor.editBox;
2856 editBox.GoToLineNum(line - 1);
2857 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2861 else if(fileAttribs.isDirectory)
2865 void OnRedraw(Surface surface)
2867 Bitmap bitmap = back.bitmap;
2869 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2872 void SheetSelected(SheetType sheetSelected)
2874 if(activeChild == sheet)
2876 if(sheetSelected == methods)
2878 viewPropertiesItem.accelerator = f4;
2879 viewPropertiesItem.parent = viewMenu;
2880 viewMethodsItem.parent = null;
2884 viewMethodsItem.accelerator = f4;
2885 viewMethodsItem.parent = viewMenu;
2886 viewPropertiesItem.parent = null;
2891 viewMethodsItem.parent = viewMenu;
2892 viewPropertiesItem.parent = viewMenu;
2893 if(sheetSelected == methods)
2895 viewMethodsItem.accelerator = f4;
2896 viewPropertiesItem.accelerator = 0;
2900 viewMethodsItem.accelerator = 0;
2901 viewPropertiesItem.accelerator = f4;
2906 void OnActivateClient(Window client, Window previous)
2908 //if(!client || client != previous)
2911 if(!client || client != previous)
2914 dataType = previous._class;
2915 if(previous && !strcmp(dataType.name, "CodeEditor"))
2917 ((CodeEditor)previous).UpdateFormCode();
2919 else if(previous && !strcmp(dataType.name, "Designer"))
2921 ((Designer)previous).codeEditor.UpdateFormCode();
2926 dataType = client._class;
2927 if(client && !strcmp(dataType.name, "CodeEditor"))
2929 CodeEditor codeEditor = (CodeEditor)client;
2930 SetPrivateModule(codeEditor.privateModule);
2931 SetCurrentContext(codeEditor.globalContext);
2932 SetTopContext(codeEditor.globalContext);
2933 SetGlobalContext(codeEditor.globalContext);
2935 SetDefines(&codeEditor.defines);
2936 SetImports(&codeEditor.imports);
2938 SetActiveDesigner(codeEditor.designer);
2940 sheet.codeEditor = codeEditor;
2941 toolBox.codeEditor = codeEditor;
2943 viewDesignerItem.parent = viewMenu;
2944 if(activeChild != codeEditor)
2946 viewCodeItem.parent = viewMenu;
2947 viewDesignerItem.accelerator = 0;
2948 viewCodeItem.accelerator = f8;
2952 viewCodeItem.parent = null;
2953 viewDesignerItem.accelerator = f8;
2956 else if(client && !strcmp(dataType.name, "Designer"))
2958 CodeEditor codeEditor = ((Designer)client).codeEditor;
2961 SetPrivateModule(codeEditor.privateModule);
2962 SetCurrentContext(codeEditor.globalContext);
2963 SetTopContext(codeEditor.globalContext);
2964 SetGlobalContext(codeEditor.globalContext);
2965 SetDefines(&codeEditor.defines);
2966 SetImports(&codeEditor.imports);
2970 SetPrivateModule(null);
2971 SetCurrentContext(null);
2972 SetTopContext(null);
2973 SetGlobalContext(null);
2978 SetActiveDesigner((Designer)client);
2980 sheet.codeEditor = codeEditor;
2981 toolBox.codeEditor = codeEditor;
2983 viewCodeItem.parent = viewMenu;
2984 if(activeChild != client)
2986 viewDesignerItem.parent = viewMenu;
2987 viewDesignerItem.accelerator = f8;
2988 viewCodeItem.accelerator = 0;
2992 viewDesignerItem.parent = null;
2993 viewCodeItem.accelerator = f8;
2998 if(!client && !projectView && sheet.visible)
3001 sheet.visible = false;
3002 toolBox.visible = false;
3005 sheet.codeEditor = null;
3006 toolBox.codeEditor = null;
3007 SetActiveDesigner(null);
3009 viewDesignerItem.parent = null;
3010 viewCodeItem.parent = null;
3013 SheetSelected(sheet.sheetSelected);
3016 projectCompileItem = null;
3021 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3023 CodeEditor codeEditor = (CodeEditor)client;
3024 EditBox editBox = codeEditor.editBox;
3026 statusBar.AddField(pos);
3028 caps = { width = 40, text = $"CAPS" };
3029 statusBar.AddField(caps);
3030 UpdateStateLight(caps, app.GetKeyState(capsState));
3032 ovr = { width = 36, text = $"OVR" };
3033 statusBar.AddField(ovr);
3034 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3036 num = { width = 36, text = $"NUM" };
3037 statusBar.AddField(num);
3038 UpdateStateLight(num, app.GetKeyState(numState));
3040 //statusBar.text = "Ready";
3042 if(projectView && projectView.project)
3044 bool isCObject = false;
3045 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3046 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3050 char nodeName[MAX_FILENAME];
3051 char name[MAX_FILENAME+96];
3053 ChangeExtension(node.name, "c", nodeName);
3054 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3055 projectCompileItem =
3057 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3059 bool NotifySelect(MenuItem selection, Modifiers mods)
3063 bool isCObject = false;
3064 bool isExcluded = false;
3065 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3069 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3072 List<ProjectNode> nodes { };
3074 projectView.Compile(node.project, nodes, false, false, isCObject ? cObject : normal);
3082 projectMenu.AddDynamic(projectCompileItem, ide, false);
3088 caps = ovr = num = null;
3093 bool OnClose(bool parentClosing)
3095 //return !projectView.buildInProgress;
3096 if(projectView && projectView.buildInProgress)
3098 if(DontTerminateDebugSession($"Close IDE"))
3100 if(findInFilesDialog)
3101 findInFilesDialog.SearchStop();
3104 workspace.timer.Stop();
3107 ideMainFrame.Destroy(0);
3114 bool passThrough = 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"))
3144 ide.debugStart = true;
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 > 1 + (ide.debugStart ? 1 : 0)) 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 UpdateToolBarActiveConfigs(false);
3217 UpdateToolBarActiveCompilers();
3224 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3227 projectView.visible = false;
3228 projectView.Destroy(0);
3231 #ifdef GDB_DEBUG_GUI
3232 gdbDialog.Destroy(0);
3237 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3241 char * oldPaths[128];
3242 String oldList = new char[maxPathLen];
3243 Array<String> newExePaths { };
3244 //Map<String, bool> exePathExists { };
3246 #if defined(__unix__) || defined(__APPLE__)
3247 Array<String> newLibPaths { };
3248 Map<String, bool> libPathExists { };
3253 for(prj : workspace.projects)
3255 DirExpression targetDirExp;
3257 // SKIP FIRST PROJECT...
3258 if(prj == workspace.projects.firstIterator.data) continue;
3260 // NOTE: Right now the additional project config dir will be
3261 // obtained when the debugger is started, so toggling it
3262 // while building will change which library gets used.
3263 // To go with the initial state, e.g. when F5 was pressed,
3264 // we nould need to keep a list of all project's active
3265 // config upon startup.
3266 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3268 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3272 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3273 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3277 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3278 if(cfg.targetType == sharedLibrary && cfg.debug)
3282 if(targetDirExp.dir)
3284 char buffer[MAX_LOCATION];
3285 #if defined(__WIN32__)
3286 Array<String> paths = newExePaths;
3288 Array<String> paths = newLibPaths;
3290 GetSystemPathBuffer(buffer, prj.topNode.path);
3291 PathCat(buffer, targetDirExp.dir);
3294 if(!fstrcmp(p, buffer))
3301 paths.Add(CopyString(buffer));
3303 delete targetDirExp;
3307 for(item : compiler.executableDirs)
3309 DirExpression dirExpr { };
3310 dirExpr.Evaluate(item, null, compiler, null, 0);
3313 for(p : newExePaths)
3315 if(!fstrcmp(p, dirExpr.dir))
3322 newExePaths.Add(CopySystemPath(dirExpr.dir));
3326 GetEnvironment("PATH", oldList, maxPathLen);
3328 printf("Old value of PATH: %s\n", oldList);
3330 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3331 for(c = 0; c < count; c++)
3334 for(p : newExePaths)
3336 if(!fstrcmp(p, oldPaths[c]))
3343 newExePaths.Add(CopySystemPath(oldPaths[c]));
3347 for(path : newExePaths)
3348 len += strlen(path) + 1;
3349 newList = new char[len + 1];
3351 for(path : newExePaths)
3353 strcat(newList, path);
3354 strcat(newList, pathListSep);
3356 newList[len - 1] = '\0';
3357 SetEnvironment("PATH", newList);
3359 printf("New value of PATH: %s\n", newList);
3366 #if defined(__unix__) || defined(__APPLE__)
3368 for(item : compiler.libraryDirs)
3370 if(!libPathExists[item]) // fstrcmp should be used
3372 String s = CopyString(item);
3374 libPathExists[s] = true;
3378 #if defined(__APPLE__)
3379 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3381 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3384 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3386 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3387 for(c = 0; c < count; c++)
3389 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3391 String s = CopyString(oldPaths[c]);
3393 libPathExists[s] = true;
3398 for(path : newLibPaths)
3399 len += strlen(path) + 1;
3400 newList = new char[len + 1];
3402 for(path : newLibPaths)
3404 strcat(newList, path);
3405 strcat(newList, pathListSep);
3407 newList[len - 1] = '\0';
3408 #if defined(__APPLE__)
3409 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3411 SetEnvironment("LD_LIBRARY_PATH", newList);
3414 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3420 delete libPathExists;
3423 if(compiler.distccEnabled && compiler.distccHosts)
3424 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3429 void DestroyTemporaryProjectDir()
3431 if(tmpPrjDir && tmpPrjDir[0])
3433 if(FileExists(tmpPrjDir).isDirectory)
3434 DestroyDir(tmpPrjDir);
3435 property::tmpPrjDir = null;
3441 // Graphics Driver Menu
3444 app.currentSkin.selectionColor = selectionColor;
3445 app.currentSkin.selectionText = selectionText;
3449 driverItems = new MenuItem[app.numDrivers];
3450 for(c = 0; c < app.numDrivers; c++)
3452 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3453 driverItems[c].id = c;
3454 driverItems[c].isRadio = true;
3457 driverItems = new MenuItem[2];
3458 #if defined(__unix__)
3459 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3460 driverItems[0].id = 0;
3461 driverItems[0].isRadio = true;
3463 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3464 driverItems[0].id = 0;
3465 driverItems[0].isRadio = true;
3467 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3468 driverItems[1].id = 1;
3469 driverItems[1].isRadio = true;
3471 /* skinItems = new MenuItem[app.numSkins];
3472 for(c = 0; c < app.numSkins; c++)
3474 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3475 skinItems[c].id = c;
3476 skinItems[c].isRadio = true;
3479 ideFileDialog.master = this;
3480 ideProjectFileDialog.master = this;
3482 //SetDriverAndSkin();
3486 void UpdateRecentMenus()
3489 Menu fileMenu = menu.FindMenu($"File");
3490 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3491 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3492 char * itemPath = new char[MAX_LOCATION];
3493 char * itemName = new char[MAX_LOCATION+4];
3495 recentFiles.Clear();
3498 for(recent : ideSettings.recentFiles)
3500 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3501 MakeSystemPath(itemPath);
3502 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3503 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3507 recentProjects.Clear();
3509 for(recent : ideSettings.recentProjects)
3511 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3512 MakeSystemPath(itemPath);
3513 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3514 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3526 delete languageItems;
3530 documentor.Puts("Quit\n");
3537 void DestroyDir(char * path)
3539 RecursiveDeleteFolderFSI fsi { };
3544 #if defined(__WIN32__)
3545 define sdkDirName = "Ecere SDK";
3547 define sdkDirName = "ecere";
3550 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3553 char * v = new char[maxPathLen];
3557 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3558 StripLastDirectory(path, path);
3559 PathCat(path, subDir);
3560 if(name) PathCat(path, name);
3561 if(FileExists(path) & attribs) found = true;
3563 #if defined(__WIN32__)
3566 GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3569 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3570 PathCat(path, subDir);
3571 if(name) PathCat(path, name);
3572 if(FileExists(path) & attribs) found = true;
3577 GetEnvironment("AppData", v, maxPathLen);
3580 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3581 PathCat(path, sdkDirName);
3582 PathCat(path, subDir);
3583 if(name) PathCat(path, name);
3584 if(FileExists(path) & attribs) found = true;
3589 GetEnvironment("ProgramData", v, maxPathLen);
3592 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3593 PathCat(path, sdkDirName);
3594 PathCat(path, subDir);
3595 if(name) PathCat(path, name);
3596 if(FileExists(path) & attribs) found = true;
3601 GetEnvironment("ProgramFiles", v, maxPathLen);
3604 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3605 PathCat(path, sdkDirName);
3606 PathCat(path, subDir);
3607 if(name) PathCat(path, name);
3608 if(FileExists(path) & attribs) found = true;
3613 GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3616 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3617 PathCat(path, sdkDirName);
3618 PathCat(path, subDir);
3619 if(name) PathCat(path, name);
3620 if(FileExists(path) & attribs) found = true;
3625 GetEnvironment("SystemDrive", v, maxPathLen);
3628 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3629 PathCat(path, "Program Files");
3630 PathCat(path, sdkDirName);
3631 PathCat(path, subDir);
3632 if(name) PathCat(path, name);
3633 if(FileExists(path) & attribs) found = true;
3642 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3643 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3644 for(c=0; c<numTokens; c++)
3646 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3647 PathCat(path, sdkDirName);
3648 PathCat(path, subDir);
3649 if(name) PathCat(path, name);
3650 if(FileExists(path) & attribs) found = true;
3658 void FindAndShellOpenInstalledFolder(const char * name)
3660 char path[MAX_LOCATION];
3661 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3665 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3667 char path[MAX_LOCATION];
3668 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3672 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3674 bool preserveRootFolder;
3676 void OutFolder(const char * folderPath, bool isRoot)
3678 if(!(preserveRootFolder && isRoot))
3679 RemoveDir(folderPath);
3682 bool OnFile(const char * filePath)
3684 DeleteFile(filePath);
3689 class IDEApp : GuiApplication
3691 //driver = "Win32Console";
3692 // driver = "OpenGL";
3696 TempFile includeFile { };
3701 char ext[MAX_EXTENSION];
3702 SetLoggingMode(stdOut, null);
3703 //SetLoggingMode(debug, null);
3705 settingsContainer.Load();
3707 if(ideSettings.language)
3709 const String language = GetLanguageString();
3710 if(ideSettings.language.OnCompare(language))
3712 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3717 // First count files arg to decide whether to maximize
3719 bool passThrough = false, debugWorkDir = false;
3722 for(c = 1; c<app.argc; c++)
3725 else if(debugWorkDir)
3726 debugWorkDir = false;
3727 else if(!strcmp(app.argv[c], "-t"));
3728 else if(!strcmp(app.argv[c], "-no-parsing"));
3729 else if(!strcmp(app.argv[c], "-debug-start"));
3730 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3731 debugWorkDir = true;
3732 else if(!strcmp(app.argv[c], "-@"))
3739 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3741 app.driver = "OpenGL";
3742 ide.driverItems[1].checked = true;
3746 #if defined(__unix__) || defined(__APPLE__)
3747 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3749 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3751 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3755 char model[MAX_LOCATION];
3756 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3758 ide.duck.modelFile = model;
3759 ide.duck.parent = ideMainFrame;
3762 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3763 ide.debugRubberDuck.disabled = false;
3767 desktop.caption = titleECEREIDE;
3770 for(c = 1; c<app.argc; c++)
3772 char fullPath[MAX_LOCATION];
3773 GetWorkingDir(fullPath, MAX_LOCATION);
3774 PathCat(fullPath, app.argv[c]);
3775 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3779 // Default to language specified by environment if no language selected
3780 if(!ideSettings.language)
3782 ideSettings.language = GetLanguageString();
3783 settingsContainer.Save();
3786 // Default to home directory if no directory yet set up
3787 if(!ideSettings.ideProjectFileDialogLocation[0])
3790 char location[MAX_LOCATION];
3791 char * home = getenv("HOME");
3792 char * homeDrive = getenv("HOMEDRIVE");
3793 char * homePath = getenv("HOMEPATH");
3794 char * userProfile = getenv("USERPROFILE");
3795 char * systemDrive = getenv("SystemDrive");
3796 if(home && FileExists(home).isDirectory)
3798 strcpy(location, home);
3801 if(!found && homeDrive && homePath)
3803 strcpy(location, homeDrive);
3804 PathCat(location, homePath);
3805 if(FileExists(location).isDirectory)
3808 if(!found && FileExists(userProfile).isDirectory)
3810 strcpy(location, userProfile);
3813 if(!found && FileExists(systemDrive).isDirectory)
3815 strcpy(location, systemDrive);
3820 ideSettings.ideProjectFileDialogLocation = location;
3821 if(!ideSettings.ideFileDialogLocation[0])
3822 ideSettings.ideFileDialogLocation = location;
3826 if(!LoadIncludeFile())
3827 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3829 // Create language menu
3831 String language = ideSettings.language;
3835 ide.languageItems = new MenuItem[languages.count];
3838 ide.languageItems[i] =
3840 ide.languageMenu, l.name;
3841 bitmap = { l.bitmap };
3845 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3847 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3849 // Re-select previous selected language if aborted
3850 String language = ideSettings.language;
3854 if(((!language || !language[0]) && i == 0) ||
3855 (language && !strcmpi(l.code, language)))
3857 ide.languageItems[i].checked = true;
3869 // Try to find country-specific language first
3875 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3877 ide.languageItems[i].checked = true;
3885 // Try generalizing locale
3886 if(!found && language)
3889 char genericLocale[256];
3891 strncpy(genericLocale, language, sizeof(genericLocale));
3892 genericLocale[sizeof(genericLocale)-1] = 0;
3894 under = strchr(genericLocale, '_');
3897 if(!strcmpi(genericLocale, "zh"))
3898 strcpy(genericLocale, "zh_CN");
3899 if(strcmp(genericLocale, language))
3903 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3905 ide.languageItems[i].checked = true;
3915 ide.languageItems[0].checked = true;
3917 MenuDivider { ide.languageMenu };
3920 ide.languageMenu, "Help Translate";
3922 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3924 ShellOpen("http://translations.launchpad.net/ecere");
3930 ideMainFrame.Create();
3931 if(app.argFilesCount > 1)
3932 ide.MenuWindowTileVert(null, 0);
3936 bool Cycle(bool idle)
3940 if(ide.documentor.Peek())
3943 ide.documentor.GetLine(line, sizeof(line));
3944 if(!strcmpi(line, "Exited"))
3946 ide.documentor.CloseInput();
3947 ide.documentor.CloseOutput();
3948 ide.documentor.Wait();
3949 delete ide.documentor;
3952 if(ide.documentor && ide.documentor.eof)
3954 ide.documentor.CloseInput();
3955 ide.documentor.CloseOutput();
3956 ide.documentor.Wait();
3957 delete ide.documentor;
3963 bool LoadIncludeFile()
3965 bool result = false;
3966 File include = FileOpen(":crossplatform.mk", read);
3969 File f = includeFile;
3972 for(; !include.Eof(); )
3975 int count = include.Read(buffer, 1, 4096);
3976 f.Write(buffer, 1, count);
3986 IDEMainFrame ideMainFrame { };
3988 define app = ((IDEApp)__thisModule);
3990 define titleECEREIDE = $"Ecere IDE (Debug)";
3992 define titleECEREIDE = $"Ecere IDE";