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);
1644 #ifdef GDB_DEBUG_GUI
1647 master = this, parent = this;
1648 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1650 void OnCommand(const char * string)
1653 ide.debugger.SendGDBCommand(string);
1658 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1660 //app.driver = app.drivers[selection.id];
1661 #if defined(__unix__) || defined(__APPLE__)
1662 app.driver = selection.id ? "OpenGL" : "X";
1664 app.driver = selection.id ? "OpenGL" : "GDI";
1666 delete ideSettings.displayDriver;
1667 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1669 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1671 settingsContainer.Save();
1672 //SetDriverAndSkin();
1676 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1678 app.skin = app.skins[selection.id];
1683 void SetDriverAndSkin()
1686 for(c = 0; c < app.numSkins; c++)
1687 if(!strcmp(app.skins[c], app.skin))
1689 skinItems[c].checked = true;
1692 for(c = 0; c < app.numDrivers; c++)
1693 if(!strcmp(app.drivers[c], app.driver))
1695 driverItems[c].checked = true;
1700 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1702 Project project = workspace.projects.firstIterator.data;
1703 projectView = ProjectView
1706 fileName = fileName;
1708 void NotifyDestroyed(Window window, DialogResult result)
1711 text = titleECEREIDE;
1716 projectView.Create();
1717 RepositionWindows(false);
1719 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1720 projectView.workspace = workspace;
1721 projectView.project = project;
1722 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1726 ide.breakpointsView.LoadFromWorkspace();
1727 ide.watchesView.LoadFromWorkspace();
1729 findInFilesDialog.projectNodeField.userData = projectView;
1732 char fileName[MAX_LOCATION];
1733 strcpy(fileName, project.topNode.path);
1734 PathCat(fileName, project.topNode.name);
1741 projectView.visible = false;
1742 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1744 if(findInFilesDialog)
1746 char workingDir[MAX_LOCATION];
1747 GetWorkingDir(workingDir, MAX_LOCATION);
1748 findInFilesDialog.SearchStop();
1749 findInFilesDialog.currentDirectory = workingDir;
1751 sheet.visible = false;
1752 toolBox.visible = false;
1753 outputView.visible = false;
1754 ideMainFrame.text = titleECEREIDE;
1761 void RepositionWindows(bool expand)
1766 bool callStackVisible = expand ? false : callStackView.visible;
1767 bool threadsVisible = expand ? false : threadsView.visible;
1768 bool watchesVisible = expand ? false : watchesView.visible;
1769 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1770 bool toolBoxVisible = toolBox.visible;
1771 bool outputVisible = expand ? false : outputView.visible;
1772 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1773 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1775 for(child = firstChild; child; child = child.next)
1777 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1778 child._class == class(Sheet) || child._class == class(ProjectView))
1780 Anchor anchor = child.anchor;
1781 anchor.top = topDistance;
1782 anchor.bottom = bottomDistance;
1783 if(child._class == class(CodeEditor) || child._class == class(Designer))
1785 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1786 anchor.right = toolBoxVisible ? 150 : 0;
1789 child.anchor = anchor;
1793 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1794 child._class == class(BreakpointsView))
1795 child.visible = false;
1798 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1800 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1804 bool ShowCodeEditor()
1807 activeClient.Activate();
1808 else if(projectView)
1810 projectView.visible = true;
1811 projectView.Activate();
1813 else if(sheet.visible)
1816 outputView.visible = false;
1820 void DocumentSaved(Window document, const char * fileName)
1822 ideSettings.AddRecentFile(fileName);
1823 ide.UpdateRecentMenus();
1824 ide.AdjustFileMenus();
1825 settingsContainer.Save();
1828 bool Window::OnFileModified(FileChange fileChange, const char * param)
1831 sprintf(temp, $"The document %s was modified by another application.\n"
1832 "Would you like to reload it and lose your changes?", this.fileName);
1833 if(MessageBox { type = yesNo, master = this/*.parent*/,
1834 text = $"Document has been modified", contents = temp }.Modal() == yes)
1836 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1837 char * fileName = CopyString(this.fileName);
1838 WindowState state = this.state;
1839 Anchor anchor = this.anchor;
1840 Size size = this.size;
1842 this.modifiedDocument = false;
1844 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1847 this.anchor = anchor;
1849 this.SetState(state, true, 0);
1857 void UpdateMakefiles()
1861 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1862 for(prj : workspace.projects)
1863 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1868 void UpdateCompilerConfigs(bool mute)
1870 UpdateToolBarActiveCompilers();
1873 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1874 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1877 projectView.ShowOutputBuildLog(true);
1878 projectView.DisplayCompiler(compiler, false);
1880 for(prj : workspace.projects)
1881 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1886 void UpdateToolBarActiveCompilers()
1888 toolBar.activeCompiler.Clear();
1889 for(compiler : ideSettings.compilerConfigs)
1891 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1892 if(workspace && workspace.compiler && !strcmp(compiler.name, workspace.compiler))
1893 toolBar.activeCompiler.currentRow = row;
1895 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1896 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1899 void UpdateToolBarActiveConfigs(bool selectionOnly)
1901 bool commonSelected = false;
1902 DataRow row = toolBar.activeConfig.currentRow;
1904 row = toolBar.activeConfig.FindRow(1);
1907 toolBar.activeConfig.Clear();
1908 row = toolBar.activeConfig.AddString($"(Mixed)");
1913 char * configName = null;
1916 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1917 for(prj : workspace.projects)
1919 for(cfg : prj.configurations)
1922 configs[cfg.name] = 1;
1927 toolBar.activeConfig.AddString(&name);
1931 if(projectView && projectView.project)
1933 for(prj : workspace.projects)
1935 if(prj.config && prj.config.name)
1937 configName = prj.config.name;
1943 commonSelected = true;
1944 for(prj : workspace.projects)
1946 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1948 commonSelected = false;
1956 commonSelected = false;
1957 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1959 if(!strcmp(row.string, configName))
1961 toolBar.activeConfig.currentRow = row;
1962 commonSelected = true;
1969 toolBar.activeConfig.Sort(null, 0);
1971 toolBar.activeConfig.currentRow = row;
1976 bool unavailable = !project;
1978 projectAddItem.disabled = unavailable;
1979 toolBar.buttonAddProject.disabled = unavailable;
1981 projectSettingsItem.disabled = unavailable;
1983 projectBrowseFolderItem.disabled = unavailable;
1985 viewProjectItem.disabled = unavailable;
1987 toolBar.activeConfig.disabled = unavailable;
1988 toolBar.activeCompiler.disabled = unavailable;
1989 toolBar.activeBitDepth.disabled = unavailable;
1992 debugUseValgrindItem.disabled = unavailable;
1993 AdjustValgrindMenus();
2002 void AdjustValgrindMenus()
2004 bool unavailable = !project || !debugUseValgrindItem.checked;
2005 debugValgrindNoLeakCheckItem.disabled = unavailable;
2006 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2007 debugValgrindYesLeakCheckItem.disabled = unavailable;
2008 debugValgrindFullLeakCheckItem.disabled = unavailable;
2010 debugValgrindTrackOriginsItem.disabled = unavailable;
2012 debugValgrindRSDefaultItem.disabled = unavailable;
2013 debugValgrindRS0Item.disabled = unavailable;
2014 debugValgrindRS16Item.disabled = unavailable;
2015 debugValgrindRS32Item.disabled = unavailable;
2016 debugValgrindRS64Item.disabled = unavailable;
2017 debugValgrindRS128Item.disabled = unavailable;
2018 debugValgrindRS256Item.disabled = unavailable;
2019 debugValgrindRS512Item.disabled = unavailable;
2023 property bool hasOpenedCodeEditors
2028 for(w = firstChild; w; w = w.next)
2029 if(w._class == class(CodeEditor) &&
2030 w.isDocument && !w.closing && w.visible && w.created &&
2031 w.fileName && w.fileName[0])
2037 void AdjustFileMenus()
2039 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2041 projectQuickItem.disabled = unavailable;
2044 void AdjustBuildMenus()
2046 bool unavailable = project && projectView.buildInProgress;
2047 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2049 projectNewItem.disabled = unavailable;
2050 toolBar.buttonNewProject.disabled = unavailable;
2051 projectOpenItem.disabled = unavailable;
2052 toolBar.buttonOpenProject.disabled = unavailable;
2054 unavailable = !project || projectView.buildInProgress;
2056 projectCloseItem.disabled = unavailable;
2057 // toolBar.buttonCloseProject.disabled = unavailable;
2059 projectRunItem.disabled = naForRun;
2060 toolBar.buttonRun.disabled = naForRun;
2062 projectBuildItem.disabled = false;
2063 projectBuildItem.text = unavailable ? $"Stop Build" : $"Build";
2064 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2066 projectLinkItem.disabled = unavailable;
2067 toolBar.buttonReLink.disabled = unavailable;
2068 projectRebuildItem.disabled = unavailable;
2069 toolBar.buttonRebuild.disabled = unavailable;
2070 projectCleanItem.disabled = unavailable;
2071 toolBar.buttonClean.disabled = unavailable;
2072 projectCleanTargetItem.disabled = unavailable;
2073 projectRealCleanItem.disabled = unavailable;
2074 // toolBar.buttonRealClean.disabled = unavailable;
2075 projectRegenerateItem.disabled = unavailable;
2076 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2077 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2078 projectInstallItem.disabled = unavailable;
2079 toolBar.buttonInstall.disabled = unavailable;
2081 projectCompileItem.disabled = unavailable;
2083 AdjustPopupBuildMenus();
2086 void AdjustPopupBuildMenus()
2088 bool unavailable = !project || projectView.buildInProgress;
2090 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2093 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
2096 menu.disabled = false;
2097 menu.text = unavailable ? $"Stop Build" : $"Build";
2098 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2101 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0); if(menu) menu.disabled = unavailable;
2102 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0); if(menu) menu.disabled = unavailable;
2103 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0); if(menu) menu.disabled = unavailable;
2104 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0); if(menu) menu.disabled = unavailable;
2105 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0); if(menu) menu.disabled = unavailable;
2106 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
2107 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, 0); if(menu) menu.disabled = unavailable;
2108 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0); if(menu) menu.disabled = unavailable;
2109 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0); if(menu) menu.disabled = unavailable;
2110 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0); if(menu) menu.disabled = unavailable;
2111 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0); if(menu) menu.disabled = unavailable;
2112 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0); if(menu) menu.disabled = unavailable;
2113 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
2114 projectView.popupMenu.Update(null);
2118 property bool areDebugMenusUnavailable { get {
2120 project.GetTargetType(project.config) != executable ||
2121 projectView.buildInProgress == buildingMainProject;
2124 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2125 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2126 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2128 void AdjustDebugMenus()
2130 bool unavailable = areDebugMenusUnavailable;
2131 bool running = isDebuggerRunning;
2132 bool stopped = isDebuggerStopped;
2133 bool active = debugger.isActive;
2135 bool isNotRunning = unavailable || !running;
2136 bool isNotNotRunning = unavailable || running;
2137 bool isNotStopped = unavailable || !stopped;
2138 bool isNotActive = unavailable || !active;
2140 debugStartResumeItem.disabled = isNotNotRunning;
2141 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2142 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2145 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2146 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2149 debugBreakItem.disabled = isNotRunning;
2150 debugStopItem.disabled = isNotActive;
2151 debugRestartItem.disabled = isNotActive;
2154 toolBar.buttonDebugPause.disabled = isNotRunning;
2155 toolBar.buttonDebugStop.disabled = isNotActive;
2156 toolBar.buttonDebugRestart.disabled = isNotActive;
2159 debugStepIntoItem.disabled = isNotNotRunning;
2160 debugStepOverItem.disabled = isNotNotRunning;
2161 debugSkipStepOverItem.disabled = isNotNotRunning;
2162 debugStepOutItem.disabled = isNotStopped;
2163 debugSkipStepOutItem.disabled = isNotStopped;
2165 debugStepUntilItem.disabled = isNotStopped;
2166 debugSkipStepUntilItem.disabled = isNotStopped;
2170 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2171 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2172 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2173 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2174 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2176 if((Designer)GetActiveDesigner())
2178 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2180 codeEditor.AdjustDebugMenus();
2184 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2186 char tempString[MAX_LOCATION];
2187 strcpy(tempString, directory);
2188 if(saveSettings && !projectView)
2190 ideSettings.ideFileDialogLocation = directory;
2191 settingsContainer.Save();
2194 ideFileDialog.currentDirectory = tempString;
2195 codeEditorFileDialog.currentDirectory = tempString;
2196 codeEditorFormFileDialog.currentDirectory = tempString;
2199 void ChangeProjectFileDialogDirectory(char * directory)
2201 ideSettings.ideProjectFileDialogLocation = directory;
2202 settingsContainer.Save();
2205 Window FindWindow(const char * filePath)
2207 Window document = null;
2209 // TOCHECK: Do we need to change slashes here?
2210 for(document = firstChild; document; document = document.next)
2212 const char * fileName = document.fileName;
2213 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2215 document.visible = true;
2216 document.Activate();
2223 bool DontTerminateDebugSession(const char * title)
2225 if(debugger.isActive)
2227 if(MessageBox { type = yesNo, master = ide,
2228 contents = $"Do you want to terminate the debugging session in progress?",
2229 text = title }.Modal() == no)
2232 MessageBox msg { type = yesNo, master = ide,
2233 contents = "Do you want to terminate the debugging session in progress?",
2235 if(msg.Modal() == no)
2247 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2249 char extension[MAX_EXTENSION] = "";
2250 Window document = null;
2251 bool isProject = false;
2252 bool needFileModified = true;
2253 char winFilePath[MAX_LOCATION];
2254 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2255 Window currentDoc = activeClient;
2256 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2259 GetExtension(filePath, extension);
2263 strcpy(extension, type);
2265 if(strcmp(extension, ProjectExtension))
2267 for(document = firstChild; document; document = document.next)
2269 const char * fileName = document.fileName;
2270 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2272 document.visible = true;
2274 document.Activate();
2280 if(createIfFails == whatever)
2282 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2284 needFileModified = false;
2285 if(openMethod == normal)
2287 if(DontTerminateDebugSession($"Open Project"))
2296 Workspace workspace = null;
2298 if(FileExists(filePath))
2300 if(!strcmp(extension, ProjectExtension))
2302 char workspaceFile[MAX_LOCATION];
2303 strcpy(workspaceFile, filePath);
2304 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2305 workspace = LoadWorkspace(workspaceFile, filePath);
2307 else if(!strcmp(extension, WorkspaceExtension))
2308 workspace = LoadWorkspace(filePath, null);
2315 CreateProjectView(workspace, filePath);
2316 document = projectView;
2318 toolBox.visible = true;
2319 sheet.visible = true;
2320 projectView.MakeActive();
2322 workspace.ParseLoadedBreakpoints();
2323 workspace.DropInvalidBreakpoints(null);
2326 ide.projectView.ShowOutputBuildLog(true);
2328 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2329 ide.projectView.DisplayCompiler(compiler, false);
2332 UpdateCompilerConfigs(false);
2335 char newWorkingDir[MAX_LOCATION];
2336 StripLastDirectory(filePath, newWorkingDir);
2337 ChangeFileDialogsDirectory(newWorkingDir, false);
2340 document.fileName = filePath;
2342 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2344 // this crashes on starting ide with epj file, solution please?
2345 // app.UpdateDisplay();
2347 workspace.holdTracking = true;
2348 for(ofi : workspace.openedFiles)
2350 if(ofi.state != closed)
2352 Window file = OpenFile(ofi.path, false, true, null, no, normal, noParsing);
2355 char fileName[MAX_LOCATION];
2357 GetLastDirectory(ofi.path, fileName);
2358 node = projectView.project.topNode.Find(fileName, true);
2360 node.EnsureVisible();
2364 ide.RepositionWindows(false);
2365 workspace.holdTracking = false;
2367 workspace.timer.Start();
2369 #if !defined(__WIN32__)
2370 // Valgrind Debug menu updates
2371 debugUseValgrindItem.checked = workspace.useValgrind;
2373 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2374 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2375 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2376 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2378 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2379 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2380 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2381 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2382 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2383 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2384 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2385 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2387 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2390 findInFilesDialog.mode = FindInFilesMode::project;
2391 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2394 char location[MAX_LOCATION];
2395 StripLastDirectory(ide.project.topNode.path, location);
2396 ChangeProjectFileDialogDirectory(location);
2403 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2405 ideProjectFileDialog.text = openProjectFileDialogTitle;
2406 if(ideProjectFileDialog.Modal() == cancel)
2408 filePath = ideProjectFileDialog.filePath;
2409 GetExtension(filePath, extension);
2420 else if(openMethod == add)
2425 char slashFilePath[MAX_LOCATION];
2426 GetSlashPathBuffer(slashFilePath, filePath);
2427 for(p : workspace.projects)
2429 if(!fstrcmp(p.filePath, slashFilePath))
2437 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2438 contents = $"This project is already present in workspace." }.Modal();
2442 prj = LoadProject(filePath, null);
2445 const char * activeConfigName = null;
2446 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2447 prj.StartMonitoring();
2448 workspace.projects.Add(prj);
2449 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2450 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2451 activeConfigName = toolBar.activeConfig.currentRow.string;
2452 if(activeConfigName)
2454 for(cfg : prj.configurations)
2456 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2464 projectView.AddNode(prj.topNode, null);
2465 workspace.modified = true;
2467 findInFilesDialog.AddProjectItem(prj);
2468 projectView.ShowOutputBuildLog(true);
2469 projectView.DisplayCompiler(compiler, false);
2470 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2474 char location[MAX_LOCATION];
2475 StripLastDirectory(prj.topNode.path, location);
2476 ChangeProjectFileDialogDirectory(location);
2479 // projectView is associated with the main project and not with the one just added but
2480 return projectView; // just to let the caller know something was opened
2488 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2489 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2490 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2492 if(FileExists(filePath))
2493 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2494 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2495 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2498 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2501 else if(!strcmp(extension, "3ds"))
2503 if(FileExists(filePath))
2504 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2505 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2506 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2510 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2513 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2514 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2515 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2516 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2517 !strcmp(extension, "js"))
2519 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2520 editor.updatingCode = true;
2521 if(editor.LoadFile(filePath))
2524 editor.visible = true;
2528 needFileModified = false;
2532 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2533 if(editor.LoadFile(filePath))
2536 editor.visible = true;
2540 needFileModified = false;
2543 if(document && (document._class == class(PictureEdit) ||
2544 document._class == class(ModelView)))
2549 document.fileName = filePath;
2550 if(workspace && !workspace.holdTracking)
2551 workspace.UpdateOpenedFileInfo(filePath, opened);
2555 if(!document && createIfFails != no)
2557 if(createIfFails != yes && !needFileModified &&
2558 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2559 createIfFails = yes;
2560 if(createIfFails == yes || createIfFails == whatever)
2562 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2564 document.fileName = filePath;
2570 if(projectView && document._class == class(CodeEditor) && workspace)
2572 int lineNumber, position;
2574 CodeEditor editor = (CodeEditor)document;
2575 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2576 editor.openedFileInfo.holdTracking = true;
2577 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2578 position = Max(editor.openedFileInfo.position - 1, 0);
2579 if(editor.editBox.GoToLineNum(lineNumber))
2580 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2581 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2582 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2583 editor.editBox.scroll = scroll;
2584 editor.openedFileInfo.holdTracking = false;
2587 if(needFileModified)
2588 document.OnFileModified = OnFileModified;
2589 document.NotifySaved = DocumentSaved;
2590 if(maximizeDoc && document.hasMaximize)
2591 document.state = maximized;
2594 ideSettings.AddRecentProject(document.fileName);
2596 ideSettings.AddRecentFile(document.fileName);
2597 ide.UpdateRecentMenus();
2598 ide.AdjustFileMenus();
2599 settingsContainer.Save();
2607 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2608 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2610 if(!parentClosing && ide.workspace)
2611 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2614 bool ModelView::ModelViewOnClose(bool parentClosing)
2616 if(!parentClosing && ide.workspace)
2617 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2620 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2622 if(!parentClosing && ide.workspace)
2623 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2628 void OnUnloadGraphics(Window window)
2630 display.ClearMaterials();
2631 display.ClearTextures();
2632 display.ClearMeshes();
2636 void UpdateStateLight(StatusField fld, bool on)
2638 fld.color = on ? lime : Color { 128,128,128 };
2639 fld.backColor = on ? dimGray : 0;
2643 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2645 UpdateStateLight(caps, app.GetKeyState(capsState));
2646 UpdateStateLight(num, app.GetKeyState(numState));
2650 bool OnKeyDown(Key key, unichar ch)
2654 case b: projectView.Update(null); break;
2655 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2656 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2661 bool OnKeyUp(Key key, unichar ch)
2665 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2666 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2671 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2674 projectView.GoToError(line, noParsing, objectFileExt);
2677 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2679 FileAttribs result { };
2680 FileAttribs fileAttribs;
2684 strcpy(selectedPath, prj.topNode.path);
2685 else if(dir && dir[0])
2686 strcpy(selectedPath, dir);
2688 selectedPath[0] = '\0';
2689 PathCat(selectedPath, filePath);
2691 if((fileAttribs = FileExists(selectedPath)).isFile)
2692 result = fileAttribs;
2696 for(p : workspace.projects)
2698 strcpy(selectedPath, p.topNode.path);
2699 PathCat(selectedPath, filePath);
2700 if((fileAttribs = FileExists(selectedPath)).isFile)
2703 result = fileAttribs;
2710 ProjectNode n = null;
2711 for(p : workspace.projects)
2713 if((n = p.topNode.Find(filePath, false)))
2715 n.GetFullFilePath(selectedPath);
2716 if((fileAttribs = FileExists(selectedPath)).isFile)
2719 result = fileAttribs;
2724 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2725 (fileAttribs = FileExists(selectedPath)).isFile)
2728 result = fileAttribs;
2736 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2739 const char *path = text;
2740 char *colon = strchr(text, ':');
2741 char filePath[MAX_LOCATION] = "";
2742 char completePath[MAX_LOCATION];
2743 int line = 0, col = 0;
2744 int len = strlen(text);
2746 FileAttribs fileAttribs;
2748 // support for valgrind output
2749 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2760 /*for(s=colon; *s; s++)
2769 //line = atoi(colon+1);
2771 // support for "Found n match(es) in "file/path";
2772 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)
2778 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2780 path = (colon - 1 > path) ? colon - 1 : path;
2781 colon = strstr(colon + 1, ":");
2783 if(*path == '*' && (s = strchr(path+1, '*')))
2785 while(isspace(*path)) path++;
2789 char * close = strchr(path, ')');
2793 strncpy(name, path+1, close - path - 1);
2794 name[close - path - 1] = '\0';
2795 for(p : ide.workspace.projects)
2797 if(!strcmp(p.name, name))
2807 prj = project ? project : (dir ? null : ide.project);
2810 strncpy(filePath, path, colon - path);
2811 filePath[colon - path] = '\0';
2812 line = atoi(colon + 1);
2813 colon = strstr(colon + 1, ":");
2815 col = atoi(colon + 1);
2817 else if(path - 1 >= text && *(path - 1) == '\"')
2819 colon = strchr(path, '\"');
2822 strncpy(filePath, path, colon - path);
2823 filePath[colon - path] = '\0';
2826 else if(path && !colon)
2828 strcpy(filePath, path);
2831 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2832 CodeLocationGoTo(completePath, fileAttribs, line, col);
2835 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2837 if(fileAttribs.isFile)
2839 char ext[MAX_EXTENSION];
2840 GetExtension(path, ext);
2842 if(binaryDocExt.Find(ext))
2844 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2845 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2847 char dirPath[MAX_LOCATION];
2848 StripLastDirectory(path, dirPath);
2853 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2854 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2856 EditBox editBox = codeEditor.editBox;
2857 editBox.GoToLineNum(line - 1);
2858 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2862 else if(fileAttribs.isDirectory)
2866 void OnRedraw(Surface surface)
2868 Bitmap bitmap = back.bitmap;
2870 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2873 void SheetSelected(SheetType sheetSelected)
2875 if(activeChild == sheet)
2877 if(sheetSelected == methods)
2879 viewPropertiesItem.accelerator = f4;
2880 viewPropertiesItem.parent = viewMenu;
2881 viewMethodsItem.parent = null;
2885 viewMethodsItem.accelerator = f4;
2886 viewMethodsItem.parent = viewMenu;
2887 viewPropertiesItem.parent = null;
2892 viewMethodsItem.parent = viewMenu;
2893 viewPropertiesItem.parent = viewMenu;
2894 if(sheetSelected == methods)
2896 viewMethodsItem.accelerator = f4;
2897 viewPropertiesItem.accelerator = 0;
2901 viewMethodsItem.accelerator = 0;
2902 viewPropertiesItem.accelerator = f4;
2907 void OnActivateClient(Window client, Window previous)
2909 //if(!client || client != previous)
2912 if(!client || client != previous)
2915 dataType = previous._class;
2916 if(previous && !strcmp(dataType.name, "CodeEditor"))
2918 ((CodeEditor)previous).UpdateFormCode();
2920 else if(previous && !strcmp(dataType.name, "Designer"))
2922 ((Designer)previous).codeEditor.UpdateFormCode();
2927 dataType = client._class;
2928 if(client && !strcmp(dataType.name, "CodeEditor"))
2930 CodeEditor codeEditor = (CodeEditor)client;
2931 SetPrivateModule(codeEditor.privateModule);
2932 SetCurrentContext(codeEditor.globalContext);
2933 SetTopContext(codeEditor.globalContext);
2934 SetGlobalContext(codeEditor.globalContext);
2936 SetDefines(&codeEditor.defines);
2937 SetImports(&codeEditor.imports);
2939 SetActiveDesigner(codeEditor.designer);
2941 sheet.codeEditor = codeEditor;
2942 toolBox.codeEditor = codeEditor;
2944 viewDesignerItem.parent = viewMenu;
2945 if(activeChild != codeEditor)
2947 viewCodeItem.parent = viewMenu;
2948 viewDesignerItem.accelerator = 0;
2949 viewCodeItem.accelerator = f8;
2953 viewCodeItem.parent = null;
2954 viewDesignerItem.accelerator = f8;
2957 else if(client && !strcmp(dataType.name, "Designer"))
2959 CodeEditor codeEditor = ((Designer)client).codeEditor;
2962 SetPrivateModule(codeEditor.privateModule);
2963 SetCurrentContext(codeEditor.globalContext);
2964 SetTopContext(codeEditor.globalContext);
2965 SetGlobalContext(codeEditor.globalContext);
2966 SetDefines(&codeEditor.defines);
2967 SetImports(&codeEditor.imports);
2971 SetPrivateModule(null);
2972 SetCurrentContext(null);
2973 SetTopContext(null);
2974 SetGlobalContext(null);
2979 SetActiveDesigner((Designer)client);
2981 sheet.codeEditor = codeEditor;
2982 toolBox.codeEditor = codeEditor;
2984 viewCodeItem.parent = viewMenu;
2985 if(activeChild != client)
2987 viewDesignerItem.parent = viewMenu;
2988 viewDesignerItem.accelerator = f8;
2989 viewCodeItem.accelerator = 0;
2993 viewDesignerItem.parent = null;
2994 viewCodeItem.accelerator = f8;
2999 if(!client && !projectView && sheet.visible)
3002 sheet.visible = false;
3003 toolBox.visible = false;
3006 sheet.codeEditor = null;
3007 toolBox.codeEditor = null;
3008 SetActiveDesigner(null);
3010 viewDesignerItem.parent = null;
3011 viewCodeItem.parent = null;
3014 SheetSelected(sheet.sheetSelected);
3017 projectCompileItem = null;
3022 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3024 CodeEditor codeEditor = (CodeEditor)client;
3025 EditBox editBox = codeEditor.editBox;
3027 statusBar.AddField(pos);
3029 caps = { width = 40, text = $"CAPS" };
3030 statusBar.AddField(caps);
3031 UpdateStateLight(caps, app.GetKeyState(capsState));
3033 ovr = { width = 36, text = $"OVR" };
3034 statusBar.AddField(ovr);
3035 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3037 num = { width = 36, text = $"NUM" };
3038 statusBar.AddField(num);
3039 UpdateStateLight(num, app.GetKeyState(numState));
3041 //statusBar.text = "Ready";
3043 if(projectView && projectView.project)
3045 bool isCObject = false;
3046 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3047 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3051 char nodeName[MAX_FILENAME];
3052 char name[MAX_FILENAME+96];
3054 ChangeExtension(node.name, "c", nodeName);
3055 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3056 projectCompileItem =
3058 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3060 bool NotifySelect(MenuItem selection, Modifiers mods)
3064 bool isCObject = false;
3065 bool isExcluded = false;
3066 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3070 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3073 List<ProjectNode> nodes { };
3075 projectView.Compile(node.project, nodes, false, false, isCObject ? cObject : normal);
3083 projectMenu.AddDynamic(projectCompileItem, ide, false);
3089 caps = ovr = num = null;
3094 bool OnClose(bool parentClosing)
3096 //return !projectView.buildInProgress;
3097 if(projectView && projectView.buildInProgress)
3099 if(DontTerminateDebugSession($"Close IDE"))
3101 if(findInFilesDialog)
3102 findInFilesDialog.SearchStop();
3105 workspace.timer.Stop();
3108 ideMainFrame.Destroy(0);
3115 bool passThrough = false;
3116 bool debugWorkDir = false;
3117 char * passDebugWorkDir = null;
3118 bool openAsText = false;
3119 DynamicString passArgs { };
3122 for(c = 1; c<app.argc; c++)
3126 const char * arg = app.argv[c];
3127 char * buf = new char[strlen(arg)*2+1];
3129 passArgs.concat(" ");
3131 passArgs.concat(buf);
3134 else if(debugWorkDir)
3136 passDebugWorkDir = CopyString(app.argv[c]);
3137 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3138 debugWorkDir = false;
3140 else if(!strcmp(app.argv[c], "-t"))
3142 else if(!strcmp(app.argv[c], "-no-parsing"))
3143 ide.noParsing = true;
3144 else if(!strcmp(app.argv[c], "-debug-start"))
3145 ide.debugStart = true;
3146 else if(!strcmp(app.argv[c], "-debug-hide-ide"))
3147 ide.debugHideIDE = true;
3148 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3149 debugWorkDir = true;
3150 else if(!strcmp(app.argv[c], "-@"))
3154 char fullPath[MAX_LOCATION];
3155 char parentPath[MAX_LOCATION];
3156 char ext[MAX_EXTENSION];
3158 FileAttribs dirAttribs;
3159 GetWorkingDir(fullPath, MAX_LOCATION);
3160 PathCat(fullPath, app.argv[c]);
3161 StripLastDirectory(fullPath, parentPath);
3162 GetExtension(app.argv[c], ext);
3163 isProject = !openAsText && !strcmpi(ext, "epj");
3165 if(isProject && c > 1 + (ide.debugStart ? 1 : 0) + (ide.debugHideIDE ? 1 : 0)) continue;
3167 // Create directory for projects (only)
3168 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3170 if(isProject && !FileExists(fullPath))
3172 char name[MAX_LOCATION];
3173 NewProjectDialog newProjectDialog;
3177 projectView.visible = false;
3178 if(!projectView.Destroy(0))
3182 newProjectDialog = { master = this };
3184 strcpy(name, app.argv[c]);
3185 StripExtension(name);
3186 GetLastDirectory(name, name);
3187 newProjectDialog.projectName.contents = name;
3188 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3189 newProjectDialog.locationEditBox.path = parentPath;
3190 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3192 incref newProjectDialog;
3193 newProjectDialog.Modal();
3196 ideSettings.AddRecentProject(projectView.fileName);
3197 ide.UpdateRecentMenus();
3198 settingsContainer.Save();
3200 delete newProjectDialog;
3201 // Open only one project
3205 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3207 else if(strstr(fullPath, "http://") == fullPath)
3208 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3211 if(passThrough && projectView && projectView.project && workspace)
3212 workspace.commandLineArgs = passArgs;
3213 if(passDebugWorkDir && projectView && projectView.project && workspace)
3215 workspace.debugDir = passDebugWorkDir;
3216 delete passDebugWorkDir;
3219 UpdateToolBarActiveConfigs(false);
3220 UpdateToolBarActiveCompilers();
3227 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3230 projectView.visible = false;
3231 projectView.Destroy(0);
3234 #ifdef GDB_DEBUG_GUI
3235 gdbDialog.Destroy(0);
3240 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3244 char * oldPaths[128];
3245 String oldList = new char[maxPathLen];
3246 Array<String> newExePaths { };
3247 //Map<String, bool> exePathExists { };
3249 #if defined(__unix__) || defined(__APPLE__)
3250 Array<String> newLibPaths { };
3251 Map<String, bool> libPathExists { };
3256 for(prj : workspace.projects)
3258 DirExpression targetDirExp;
3260 // SKIP FIRST PROJECT...
3261 if(prj == workspace.projects.firstIterator.data) continue;
3263 // NOTE: Right now the additional project config dir will be
3264 // obtained when the debugger is started, so toggling it
3265 // while building will change which library gets used.
3266 // To go with the initial state, e.g. when F5 was pressed,
3267 // we nould need to keep a list of all project's active
3268 // config upon startup.
3269 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3271 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3275 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3276 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3280 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3281 if(cfg.targetType == sharedLibrary && cfg.debug)
3285 if(targetDirExp.dir)
3287 char buffer[MAX_LOCATION];
3288 #if defined(__WIN32__)
3289 Array<String> paths = newExePaths;
3291 Array<String> paths = newLibPaths;
3293 GetSystemPathBuffer(buffer, prj.topNode.path);
3294 PathCat(buffer, targetDirExp.dir);
3297 if(!fstrcmp(p, buffer))
3304 paths.Add(CopyString(buffer));
3306 delete targetDirExp;
3310 for(item : compiler.executableDirs)
3312 DirExpression dirExpr { };
3313 dirExpr.Evaluate(item, null, compiler, null, 0);
3316 for(p : newExePaths)
3318 if(!fstrcmp(p, dirExpr.dir))
3325 newExePaths.Add(CopySystemPath(dirExpr.dir));
3329 GetEnvironment("PATH", oldList, maxPathLen);
3331 printf("Old value of PATH: %s\n", oldList);
3333 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3334 for(c = 0; c < count; c++)
3337 for(p : newExePaths)
3339 if(!fstrcmp(p, oldPaths[c]))
3346 newExePaths.Add(CopySystemPath(oldPaths[c]));
3350 for(path : newExePaths)
3351 len += strlen(path) + 1;
3352 newList = new char[len + 1];
3354 for(path : newExePaths)
3356 strcat(newList, path);
3357 strcat(newList, pathListSep);
3359 newList[len - 1] = '\0';
3360 SetEnvironment("PATH", newList);
3362 printf("New value of PATH: %s\n", newList);
3369 #if defined(__unix__) || defined(__APPLE__)
3371 for(item : compiler.libraryDirs)
3373 if(!libPathExists[item]) // fstrcmp should be used
3375 String s = CopyString(item);
3377 libPathExists[s] = true;
3381 #if defined(__APPLE__)
3382 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3384 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3387 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3389 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3390 for(c = 0; c < count; c++)
3392 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3394 String s = CopyString(oldPaths[c]);
3396 libPathExists[s] = true;
3401 for(path : newLibPaths)
3402 len += strlen(path) + 1;
3403 newList = new char[len + 1];
3405 for(path : newLibPaths)
3407 strcat(newList, path);
3408 strcat(newList, pathListSep);
3410 newList[len - 1] = '\0';
3411 #if defined(__APPLE__)
3412 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3414 SetEnvironment("LD_LIBRARY_PATH", newList);
3417 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3423 delete libPathExists;
3426 if(compiler.distccEnabled && compiler.distccHosts)
3427 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3432 void DestroyTemporaryProjectDir()
3434 if(tmpPrjDir && tmpPrjDir[0])
3436 if(FileExists(tmpPrjDir).isDirectory)
3437 DestroyDir(tmpPrjDir);
3438 property::tmpPrjDir = null;
3444 // Graphics Driver Menu
3447 app.currentSkin.selectionColor = selectionColor;
3448 app.currentSkin.selectionText = selectionText;
3452 driverItems = new MenuItem[app.numDrivers];
3453 for(c = 0; c < app.numDrivers; c++)
3455 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3456 driverItems[c].id = c;
3457 driverItems[c].isRadio = true;
3460 driverItems = new MenuItem[2];
3461 #if defined(__unix__)
3462 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3463 driverItems[0].id = 0;
3464 driverItems[0].isRadio = true;
3466 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3467 driverItems[0].id = 0;
3468 driverItems[0].isRadio = true;
3470 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3471 driverItems[1].id = 1;
3472 driverItems[1].isRadio = true;
3474 /* skinItems = new MenuItem[app.numSkins];
3475 for(c = 0; c < app.numSkins; c++)
3477 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3478 skinItems[c].id = c;
3479 skinItems[c].isRadio = true;
3482 ideFileDialog.master = this;
3483 ideProjectFileDialog.master = this;
3485 //SetDriverAndSkin();
3489 void UpdateRecentMenus()
3492 Menu fileMenu = menu.FindMenu($"File");
3493 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3494 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3495 char * itemPath = new char[MAX_LOCATION];
3496 char * itemName = new char[MAX_LOCATION+4];
3498 recentFiles.Clear();
3501 for(recent : ideSettings.recentFiles)
3503 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3504 MakeSystemPath(itemPath);
3505 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3506 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3510 recentProjects.Clear();
3512 for(recent : ideSettings.recentProjects)
3514 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3515 MakeSystemPath(itemPath);
3516 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3517 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3529 delete languageItems;
3533 documentor.Puts("Quit\n");
3540 void DestroyDir(char * path)
3542 RecursiveDeleteFolderFSI fsi { };
3547 #if defined(__WIN32__)
3548 define sdkDirName = "Ecere SDK";
3550 define sdkDirName = "ecere";
3553 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3556 char * v = new char[maxPathLen];
3560 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3561 StripLastDirectory(path, path);
3562 PathCat(path, subDir);
3563 if(name) PathCat(path, name);
3564 if(FileExists(path) & attribs) found = true;
3566 #if defined(__WIN32__)
3569 GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3572 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3573 PathCat(path, subDir);
3574 if(name) PathCat(path, name);
3575 if(FileExists(path) & attribs) found = true;
3580 GetEnvironment("AppData", v, maxPathLen);
3583 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3584 PathCat(path, sdkDirName);
3585 PathCat(path, subDir);
3586 if(name) PathCat(path, name);
3587 if(FileExists(path) & attribs) found = true;
3592 GetEnvironment("ProgramData", v, maxPathLen);
3595 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3596 PathCat(path, sdkDirName);
3597 PathCat(path, subDir);
3598 if(name) PathCat(path, name);
3599 if(FileExists(path) & attribs) found = true;
3604 GetEnvironment("ProgramFiles", v, maxPathLen);
3607 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3608 PathCat(path, sdkDirName);
3609 PathCat(path, subDir);
3610 if(name) PathCat(path, name);
3611 if(FileExists(path) & attribs) found = true;
3616 GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3619 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3620 PathCat(path, sdkDirName);
3621 PathCat(path, subDir);
3622 if(name) PathCat(path, name);
3623 if(FileExists(path) & attribs) found = true;
3628 GetEnvironment("SystemDrive", v, maxPathLen);
3631 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3632 PathCat(path, "Program Files");
3633 PathCat(path, sdkDirName);
3634 PathCat(path, subDir);
3635 if(name) PathCat(path, name);
3636 if(FileExists(path) & attribs) found = true;
3645 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3646 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3647 for(c=0; c<numTokens; c++)
3649 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3650 PathCat(path, sdkDirName);
3651 PathCat(path, subDir);
3652 if(name) PathCat(path, name);
3653 if(FileExists(path) & attribs) found = true;
3661 void FindAndShellOpenInstalledFolder(const char * name)
3663 char path[MAX_LOCATION];
3664 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3668 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3670 char path[MAX_LOCATION];
3671 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3675 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3677 bool preserveRootFolder;
3679 void OutFolder(const char * folderPath, bool isRoot)
3681 if(!(preserveRootFolder && isRoot))
3682 RemoveDir(folderPath);
3685 bool OnFile(const char * filePath)
3687 DeleteFile(filePath);
3692 class IDEApp : GuiApplication
3694 //driver = "Win32Console";
3695 // driver = "OpenGL";
3699 TempFile includeFile { };
3704 char ext[MAX_EXTENSION];
3705 SetLoggingMode(stdOut, null);
3706 //SetLoggingMode(debug, null);
3708 settingsContainer.Load();
3710 if(ideSettings.language)
3712 const String language = GetLanguageString();
3713 if(ideSettings.language.OnCompare(language))
3715 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3720 // First count files arg to decide whether to maximize
3722 bool passThrough = false, debugWorkDir = false;
3725 for(c = 1; c<app.argc; c++)
3728 else if(debugWorkDir)
3729 debugWorkDir = false;
3730 else if(!strcmp(app.argv[c], "-t"));
3731 else if(!strcmp(app.argv[c], "-no-parsing"));
3732 else if(!strcmp(app.argv[c], "-debug-start"));
3733 else if(!strcmp(app.argv[c], "-debug-hide-ide"));
3734 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3735 debugWorkDir = true;
3736 else if(!strcmp(app.argv[c], "-@"))
3743 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3745 app.driver = "OpenGL";
3746 ide.driverItems[1].checked = true;
3750 #if defined(__unix__) || defined(__APPLE__)
3751 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3753 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3755 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3759 char model[MAX_LOCATION];
3760 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3762 ide.duck.modelFile = model;
3763 ide.duck.parent = ideMainFrame;
3766 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3767 ide.debugRubberDuck.disabled = false;
3771 desktop.caption = titleECEREIDE;
3774 for(c = 1; c<app.argc; c++)
3776 char fullPath[MAX_LOCATION];
3777 GetWorkingDir(fullPath, MAX_LOCATION);
3778 PathCat(fullPath, app.argv[c]);
3779 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3783 // Default to language specified by environment if no language selected
3784 if(!ideSettings.language)
3786 ideSettings.language = GetLanguageString();
3787 settingsContainer.Save();
3790 // Default to home directory if no directory yet set up
3791 if(!ideSettings.ideProjectFileDialogLocation[0])
3794 char location[MAX_LOCATION];
3795 char * home = getenv("HOME");
3796 char * homeDrive = getenv("HOMEDRIVE");
3797 char * homePath = getenv("HOMEPATH");
3798 char * userProfile = getenv("USERPROFILE");
3799 char * systemDrive = getenv("SystemDrive");
3800 if(home && FileExists(home).isDirectory)
3802 strcpy(location, home);
3805 if(!found && homeDrive && homePath)
3807 strcpy(location, homeDrive);
3808 PathCat(location, homePath);
3809 if(FileExists(location).isDirectory)
3812 if(!found && FileExists(userProfile).isDirectory)
3814 strcpy(location, userProfile);
3817 if(!found && FileExists(systemDrive).isDirectory)
3819 strcpy(location, systemDrive);
3824 ideSettings.ideProjectFileDialogLocation = location;
3825 if(!ideSettings.ideFileDialogLocation[0])
3826 ideSettings.ideFileDialogLocation = location;
3830 if(!LoadIncludeFile())
3831 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3833 // Create language menu
3835 String language = ideSettings.language;
3839 ide.languageItems = new MenuItem[languages.count];
3842 ide.languageItems[i] =
3844 ide.languageMenu, l.name;
3845 bitmap = { l.bitmap };
3849 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3851 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3853 // Re-select previous selected language if aborted
3854 String language = ideSettings.language;
3858 if(((!language || !language[0]) && i == 0) ||
3859 (language && !strcmpi(l.code, language)))
3861 ide.languageItems[i].checked = true;
3873 // Try to find country-specific language first
3879 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3881 ide.languageItems[i].checked = true;
3889 // Try generalizing locale
3890 if(!found && language)
3893 char genericLocale[256];
3895 strncpy(genericLocale, language, sizeof(genericLocale));
3896 genericLocale[sizeof(genericLocale)-1] = 0;
3898 under = strchr(genericLocale, '_');
3901 if(!strcmpi(genericLocale, "zh"))
3902 strcpy(genericLocale, "zh_CN");
3903 if(strcmp(genericLocale, language))
3907 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3909 ide.languageItems[i].checked = true;
3919 ide.languageItems[0].checked = true;
3921 MenuDivider { ide.languageMenu };
3924 ide.languageMenu, "Help Translate";
3926 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3928 ShellOpen("http://translations.launchpad.net/ecere");
3934 ideMainFrame.Create();
3935 if(app.argFilesCount > 1)
3936 ide.MenuWindowTileVert(null, 0);
3940 bool Cycle(bool idle)
3944 if(ide.documentor.Peek())
3947 ide.documentor.GetLine(line, sizeof(line));
3948 if(!strcmpi(line, "Exited"))
3950 ide.documentor.CloseInput();
3951 ide.documentor.CloseOutput();
3952 ide.documentor.Wait();
3953 delete ide.documentor;
3956 if(ide.documentor && ide.documentor.eof)
3958 ide.documentor.CloseInput();
3959 ide.documentor.CloseOutput();
3960 ide.documentor.Wait();
3961 delete ide.documentor;
3967 bool LoadIncludeFile()
3969 bool result = false;
3970 File include = FileOpen(":crossplatform.mk", read);
3973 File f = includeFile;
3976 for(; !include.Eof(); )
3979 int count = include.Read(buffer, 1, 4096);
3980 f.Write(buffer, 1, count);
3990 IDEMainFrame ideMainFrame { };
3992 define app = ((IDEApp)__thisModule);
3994 define titleECEREIDE = $"Ecere IDE (Debug)";
3996 define titleECEREIDE = $"Ecere IDE";