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);
1897 toolBar.activeBitDepth.SelectRow(toolBar.activeBitDepth.FindRow(workspace ? workspace.bitDepth : 0));
1900 void UpdateToolBarActiveConfigs(bool selectionOnly)
1902 bool commonSelected = false;
1903 DataRow row = toolBar.activeConfig.currentRow;
1905 row = toolBar.activeConfig.FindRow(1);
1908 toolBar.activeConfig.Clear();
1909 row = toolBar.activeConfig.AddString($"(Mixed)");
1914 char * configName = null;
1917 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1918 for(prj : workspace.projects)
1920 for(cfg : prj.configurations)
1923 configs[cfg.name] = 1;
1928 toolBar.activeConfig.AddString(&name);
1932 if(projectView && projectView.project)
1934 for(prj : workspace.projects)
1936 if(prj.config && prj.config.name)
1938 configName = prj.config.name;
1944 commonSelected = true;
1945 for(prj : workspace.projects)
1947 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1949 commonSelected = false;
1957 commonSelected = false;
1958 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1960 if(!strcmp(row.string, configName))
1962 toolBar.activeConfig.currentRow = row;
1963 commonSelected = true;
1970 toolBar.activeConfig.Sort(null, 0);
1972 toolBar.activeConfig.currentRow = row;
1977 bool unavailable = !project;
1979 projectAddItem.disabled = unavailable;
1980 toolBar.buttonAddProject.disabled = unavailable;
1982 projectSettingsItem.disabled = unavailable;
1984 projectBrowseFolderItem.disabled = unavailable;
1986 viewProjectItem.disabled = unavailable;
1988 toolBar.activeConfig.disabled = unavailable;
1989 toolBar.activeCompiler.disabled = unavailable;
1990 toolBar.activeBitDepth.disabled = unavailable;
1993 debugUseValgrindItem.disabled = unavailable;
1994 AdjustValgrindMenus();
2003 void AdjustValgrindMenus()
2005 bool unavailable = !project || !debugUseValgrindItem.checked;
2006 debugValgrindNoLeakCheckItem.disabled = unavailable;
2007 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2008 debugValgrindYesLeakCheckItem.disabled = unavailable;
2009 debugValgrindFullLeakCheckItem.disabled = unavailable;
2011 debugValgrindTrackOriginsItem.disabled = unavailable;
2013 debugValgrindRSDefaultItem.disabled = unavailable;
2014 debugValgrindRS0Item.disabled = unavailable;
2015 debugValgrindRS16Item.disabled = unavailable;
2016 debugValgrindRS32Item.disabled = unavailable;
2017 debugValgrindRS64Item.disabled = unavailable;
2018 debugValgrindRS128Item.disabled = unavailable;
2019 debugValgrindRS256Item.disabled = unavailable;
2020 debugValgrindRS512Item.disabled = unavailable;
2024 property bool hasOpenedCodeEditors
2029 for(w = firstChild; w; w = w.next)
2030 if(w._class == class(CodeEditor) &&
2031 w.isDocument && !w.closing && w.visible && w.created &&
2032 w.fileName && w.fileName[0])
2038 void AdjustFileMenus()
2040 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2042 projectQuickItem.disabled = unavailable;
2045 void AdjustBuildMenus()
2047 bool unavailable = project && projectView.buildInProgress;
2048 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2050 projectNewItem.disabled = unavailable;
2051 toolBar.buttonNewProject.disabled = unavailable;
2052 projectOpenItem.disabled = unavailable;
2053 toolBar.buttonOpenProject.disabled = unavailable;
2055 unavailable = !project || projectView.buildInProgress;
2057 projectCloseItem.disabled = unavailable;
2058 // toolBar.buttonCloseProject.disabled = unavailable;
2060 projectRunItem.disabled = naForRun;
2061 toolBar.buttonRun.disabled = naForRun;
2063 projectBuildItem.disabled = false;
2064 projectBuildItem.text = unavailable ? $"Stop Build" : $"Build";
2065 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2067 projectLinkItem.disabled = unavailable;
2068 toolBar.buttonReLink.disabled = unavailable;
2069 projectRebuildItem.disabled = unavailable;
2070 toolBar.buttonRebuild.disabled = unavailable;
2071 projectCleanItem.disabled = unavailable;
2072 toolBar.buttonClean.disabled = unavailable;
2073 projectCleanTargetItem.disabled = unavailable;
2074 projectRealCleanItem.disabled = unavailable;
2075 // toolBar.buttonRealClean.disabled = unavailable;
2076 projectRegenerateItem.disabled = unavailable;
2077 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2078 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2079 projectInstallItem.disabled = unavailable;
2080 toolBar.buttonInstall.disabled = unavailable;
2082 projectCompileItem.disabled = unavailable;
2084 AdjustPopupBuildMenus();
2087 void AdjustPopupBuildMenus()
2089 bool unavailable = !project || projectView.buildInProgress;
2091 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2094 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
2097 menu.disabled = false;
2098 menu.text = unavailable ? $"Stop Build" : $"Build";
2099 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2102 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0); if(menu) menu.disabled = unavailable;
2103 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0); if(menu) menu.disabled = unavailable;
2104 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0); if(menu) menu.disabled = unavailable;
2105 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0); if(menu) menu.disabled = unavailable;
2106 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0); if(menu) menu.disabled = unavailable;
2107 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
2108 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, 0); if(menu) menu.disabled = unavailable;
2109 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0); if(menu) menu.disabled = unavailable;
2110 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0); if(menu) menu.disabled = unavailable;
2111 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0); if(menu) menu.disabled = unavailable;
2112 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0); if(menu) menu.disabled = unavailable;
2113 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0); if(menu) menu.disabled = unavailable;
2114 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
2115 projectView.popupMenu.Update(null);
2119 property bool areDebugMenusUnavailable { get {
2121 project.GetTargetType(project.config) != executable ||
2122 projectView.buildInProgress == buildingMainProject;
2125 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2126 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2127 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2129 void AdjustDebugMenus()
2131 bool unavailable = areDebugMenusUnavailable;
2132 bool running = isDebuggerRunning;
2133 bool stopped = isDebuggerStopped;
2134 bool active = debugger.isActive;
2136 bool isNotRunning = unavailable || !running;
2137 bool isNotNotRunning = unavailable || running;
2138 bool isNotStopped = unavailable || !stopped;
2139 bool isNotActive = unavailable || !active;
2141 debugStartResumeItem.disabled = isNotNotRunning;
2142 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2143 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2146 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2147 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2150 debugBreakItem.disabled = isNotRunning;
2151 debugStopItem.disabled = isNotActive;
2152 debugRestartItem.disabled = isNotActive;
2155 toolBar.buttonDebugPause.disabled = isNotRunning;
2156 toolBar.buttonDebugStop.disabled = isNotActive;
2157 toolBar.buttonDebugRestart.disabled = isNotActive;
2160 debugStepIntoItem.disabled = isNotNotRunning;
2161 debugStepOverItem.disabled = isNotNotRunning;
2162 debugSkipStepOverItem.disabled = isNotNotRunning;
2163 debugStepOutItem.disabled = isNotStopped;
2164 debugSkipStepOutItem.disabled = isNotStopped;
2166 debugStepUntilItem.disabled = isNotStopped;
2167 debugSkipStepUntilItem.disabled = isNotStopped;
2171 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2172 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2173 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2174 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2175 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2177 if((Designer)GetActiveDesigner())
2179 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2181 codeEditor.AdjustDebugMenus();
2185 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2187 char tempString[MAX_LOCATION];
2188 strcpy(tempString, directory);
2189 if(saveSettings && !projectView)
2191 ideSettings.ideFileDialogLocation = directory;
2192 settingsContainer.Save();
2195 ideFileDialog.currentDirectory = tempString;
2196 codeEditorFileDialog.currentDirectory = tempString;
2197 codeEditorFormFileDialog.currentDirectory = tempString;
2200 void ChangeProjectFileDialogDirectory(char * directory)
2202 ideSettings.ideProjectFileDialogLocation = directory;
2203 settingsContainer.Save();
2206 Window FindWindow(const char * filePath)
2208 Window document = null;
2210 // TOCHECK: Do we need to change slashes here?
2211 for(document = firstChild; document; document = document.next)
2213 const char * fileName = document.fileName;
2214 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2216 document.visible = true;
2217 document.Activate();
2224 bool DontTerminateDebugSession(const char * title)
2226 if(debugger.isActive)
2228 if(MessageBox { type = yesNo, master = ide,
2229 contents = $"Do you want to terminate the debugging session in progress?",
2230 text = title }.Modal() == no)
2233 MessageBox msg { type = yesNo, master = ide,
2234 contents = "Do you want to terminate the debugging session in progress?",
2236 if(msg.Modal() == no)
2248 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2250 char extension[MAX_EXTENSION] = "";
2251 Window document = null;
2252 bool isProject = false;
2253 bool needFileModified = true;
2254 char winFilePath[MAX_LOCATION];
2255 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2256 Window currentDoc = activeClient;
2257 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2260 GetExtension(filePath, extension);
2264 strcpy(extension, type);
2266 if(strcmp(extension, ProjectExtension))
2268 for(document = firstChild; document; document = document.next)
2270 const char * fileName = document.fileName;
2271 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2273 document.visible = true;
2275 document.Activate();
2281 if(createIfFails == whatever)
2283 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2285 needFileModified = false;
2286 if(openMethod == normal)
2288 if(DontTerminateDebugSession($"Open Project"))
2297 Workspace workspace = null;
2299 if(FileExists(filePath))
2301 if(!strcmp(extension, ProjectExtension))
2303 char workspaceFile[MAX_LOCATION];
2304 strcpy(workspaceFile, filePath);
2305 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2306 workspace = LoadWorkspace(workspaceFile, filePath);
2308 else if(!strcmp(extension, WorkspaceExtension))
2309 workspace = LoadWorkspace(filePath, null);
2316 CreateProjectView(workspace, filePath);
2317 document = projectView;
2319 toolBox.visible = true;
2320 sheet.visible = true;
2321 projectView.MakeActive();
2323 workspace.ParseLoadedBreakpoints();
2324 workspace.DropInvalidBreakpoints(null);
2327 ide.projectView.ShowOutputBuildLog(true);
2329 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2330 ide.projectView.DisplayCompiler(compiler, false);
2333 UpdateCompilerConfigs(false);
2336 char newWorkingDir[MAX_LOCATION];
2337 StripLastDirectory(filePath, newWorkingDir);
2338 ChangeFileDialogsDirectory(newWorkingDir, false);
2341 document.fileName = filePath;
2343 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2345 // this crashes on starting ide with epj file, solution please?
2346 // app.UpdateDisplay();
2348 workspace.holdTracking = true;
2349 for(ofi : workspace.openedFiles)
2351 if(ofi.state != closed)
2353 Window file = OpenFile(ofi.path, false, true, null, no, normal, noParsing);
2356 char fileName[MAX_LOCATION];
2358 GetLastDirectory(ofi.path, fileName);
2359 node = projectView.project.topNode.Find(fileName, true);
2361 node.EnsureVisible();
2365 ide.RepositionWindows(false);
2366 workspace.holdTracking = false;
2368 workspace.timer.Start();
2370 #if !defined(__WIN32__)
2371 // Valgrind Debug menu updates
2372 debugUseValgrindItem.checked = workspace.useValgrind;
2374 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2375 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2376 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2377 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2379 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2380 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2381 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2382 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2383 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2384 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2385 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2386 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2388 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2391 findInFilesDialog.mode = FindInFilesMode::project;
2392 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2395 char location[MAX_LOCATION];
2396 StripLastDirectory(ide.project.topNode.path, location);
2397 ChangeProjectFileDialogDirectory(location);
2404 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2406 ideProjectFileDialog.text = openProjectFileDialogTitle;
2407 if(ideProjectFileDialog.Modal() == cancel)
2409 filePath = ideProjectFileDialog.filePath;
2410 GetExtension(filePath, extension);
2421 else if(openMethod == add)
2426 char slashFilePath[MAX_LOCATION];
2427 GetSlashPathBuffer(slashFilePath, filePath);
2428 for(p : workspace.projects)
2430 if(!fstrcmp(p.filePath, slashFilePath))
2438 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2439 contents = $"This project is already present in workspace." }.Modal();
2443 prj = LoadProject(filePath, null);
2446 const char * activeConfigName = null;
2447 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2448 prj.StartMonitoring();
2449 workspace.projects.Add(prj);
2450 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2451 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2452 activeConfigName = toolBar.activeConfig.currentRow.string;
2453 if(activeConfigName)
2455 for(cfg : prj.configurations)
2457 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2465 projectView.AddNode(prj.topNode, null);
2466 workspace.modified = true;
2468 findInFilesDialog.AddProjectItem(prj);
2469 projectView.ShowOutputBuildLog(true);
2470 projectView.DisplayCompiler(compiler, false);
2471 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2475 char location[MAX_LOCATION];
2476 StripLastDirectory(prj.topNode.path, location);
2477 ChangeProjectFileDialogDirectory(location);
2480 // projectView is associated with the main project and not with the one just added but
2481 return projectView; // just to let the caller know something was opened
2489 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2490 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2491 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2493 if(FileExists(filePath))
2494 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2495 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2496 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2499 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2502 else if(!strcmp(extension, "3ds"))
2504 if(FileExists(filePath))
2505 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2506 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2507 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2511 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2514 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2515 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2516 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2517 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2518 !strcmp(extension, "js"))
2520 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2521 editor.updatingCode = true;
2522 if(editor.LoadFile(filePath))
2525 editor.visible = true;
2529 needFileModified = false;
2533 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2534 if(editor.LoadFile(filePath))
2537 editor.visible = true;
2541 needFileModified = false;
2544 if(document && (document._class == class(PictureEdit) ||
2545 document._class == class(ModelView)))
2550 document.fileName = filePath;
2551 if(workspace && !workspace.holdTracking)
2552 workspace.UpdateOpenedFileInfo(filePath, opened);
2556 if(!document && createIfFails != no)
2558 if(createIfFails != yes && !needFileModified &&
2559 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2560 createIfFails = yes;
2561 if(createIfFails == yes || createIfFails == whatever)
2563 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2565 document.fileName = filePath;
2571 if(projectView && document._class == class(CodeEditor) && workspace)
2573 int lineNumber, position;
2575 CodeEditor editor = (CodeEditor)document;
2576 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2577 editor.openedFileInfo.holdTracking = true;
2578 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2579 position = Max(editor.openedFileInfo.position - 1, 0);
2580 if(editor.editBox.GoToLineNum(lineNumber))
2581 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2582 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2583 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2584 editor.editBox.scroll = scroll;
2585 editor.openedFileInfo.holdTracking = false;
2588 if(needFileModified)
2589 document.OnFileModified = OnFileModified;
2590 document.NotifySaved = DocumentSaved;
2591 if(maximizeDoc && document.hasMaximize)
2592 document.state = maximized;
2595 ideSettings.AddRecentProject(document.fileName);
2597 ideSettings.AddRecentFile(document.fileName);
2598 ide.UpdateRecentMenus();
2599 ide.AdjustFileMenus();
2600 settingsContainer.Save();
2608 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2609 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2611 if(!parentClosing && ide.workspace)
2612 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2615 bool ModelView::ModelViewOnClose(bool parentClosing)
2617 if(!parentClosing && ide.workspace)
2618 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2621 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2623 if(!parentClosing && ide.workspace)
2624 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2629 void OnUnloadGraphics(Window window)
2631 display.ClearMaterials();
2632 display.ClearTextures();
2633 display.ClearMeshes();
2637 void UpdateStateLight(StatusField fld, bool on)
2639 fld.color = on ? lime : Color { 128,128,128 };
2640 fld.backColor = on ? dimGray : 0;
2644 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2646 UpdateStateLight(caps, app.GetKeyState(capsState));
2647 UpdateStateLight(num, app.GetKeyState(numState));
2651 bool OnKeyDown(Key key, unichar ch)
2655 case b: projectView.Update(null); break;
2656 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2657 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2662 bool OnKeyUp(Key key, unichar ch)
2666 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2667 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2672 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2675 projectView.GoToError(line, noParsing, objectFileExt);
2678 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2680 FileAttribs result { };
2681 FileAttribs fileAttribs;
2685 strcpy(selectedPath, prj.topNode.path);
2686 else if(dir && dir[0])
2687 strcpy(selectedPath, dir);
2689 selectedPath[0] = '\0';
2690 PathCat(selectedPath, filePath);
2692 if((fileAttribs = FileExists(selectedPath)).isFile)
2693 result = fileAttribs;
2697 for(p : workspace.projects)
2699 strcpy(selectedPath, p.topNode.path);
2700 PathCat(selectedPath, filePath);
2701 if((fileAttribs = FileExists(selectedPath)).isFile)
2704 result = fileAttribs;
2711 ProjectNode n = null;
2712 for(p : workspace.projects)
2714 if((n = p.topNode.Find(filePath, false)))
2716 n.GetFullFilePath(selectedPath);
2717 if((fileAttribs = FileExists(selectedPath)).isFile)
2720 result = fileAttribs;
2725 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2726 (fileAttribs = FileExists(selectedPath)).isFile)
2729 result = fileAttribs;
2737 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2740 const char *path = text;
2741 char *colon = strchr(text, ':');
2742 char filePath[MAX_LOCATION] = "";
2743 char completePath[MAX_LOCATION];
2744 int line = 0, col = 0;
2745 int len = strlen(text);
2747 FileAttribs fileAttribs;
2749 // support for valgrind output
2750 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2761 /*for(s=colon; *s; s++)
2770 //line = atoi(colon+1);
2772 // support for "Found n match(es) in "file/path";
2773 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)
2779 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2781 path = (colon - 1 > path) ? colon - 1 : path;
2782 colon = strstr(colon + 1, ":");
2784 if(*path == '*' && (s = strchr(path+1, '*')))
2786 while(isspace(*path)) path++;
2790 char * close = strchr(path, ')');
2794 strncpy(name, path+1, close - path - 1);
2795 name[close - path - 1] = '\0';
2796 for(p : ide.workspace.projects)
2798 if(!strcmp(p.name, name))
2808 prj = project ? project : (dir ? null : ide.project);
2811 strncpy(filePath, path, colon - path);
2812 filePath[colon - path] = '\0';
2813 line = atoi(colon + 1);
2814 colon = strstr(colon + 1, ":");
2816 col = atoi(colon + 1);
2818 else if(path - 1 >= text && *(path - 1) == '\"')
2820 colon = strchr(path, '\"');
2823 strncpy(filePath, path, colon - path);
2824 filePath[colon - path] = '\0';
2827 else if(path && !colon)
2829 strcpy(filePath, path);
2832 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2833 CodeLocationGoTo(completePath, fileAttribs, line, col);
2836 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2838 if(fileAttribs.isFile)
2840 char ext[MAX_EXTENSION];
2841 GetExtension(path, ext);
2843 if(binaryDocExt.Find(ext))
2845 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2846 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2848 char dirPath[MAX_LOCATION];
2849 StripLastDirectory(path, dirPath);
2854 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2855 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2857 EditBox editBox = codeEditor.editBox;
2858 editBox.GoToLineNum(line - 1);
2859 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2863 else if(fileAttribs.isDirectory)
2867 void OnRedraw(Surface surface)
2869 Bitmap bitmap = back.bitmap;
2871 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2874 void SheetSelected(SheetType sheetSelected)
2876 if(activeChild == sheet)
2878 if(sheetSelected == methods)
2880 viewPropertiesItem.accelerator = f4;
2881 viewPropertiesItem.parent = viewMenu;
2882 viewMethodsItem.parent = null;
2886 viewMethodsItem.accelerator = f4;
2887 viewMethodsItem.parent = viewMenu;
2888 viewPropertiesItem.parent = null;
2893 viewMethodsItem.parent = viewMenu;
2894 viewPropertiesItem.parent = viewMenu;
2895 if(sheetSelected == methods)
2897 viewMethodsItem.accelerator = f4;
2898 viewPropertiesItem.accelerator = 0;
2902 viewMethodsItem.accelerator = 0;
2903 viewPropertiesItem.accelerator = f4;
2908 void OnActivateClient(Window client, Window previous)
2910 //if(!client || client != previous)
2913 if(!client || client != previous)
2916 dataType = previous._class;
2917 if(previous && !strcmp(dataType.name, "CodeEditor"))
2919 ((CodeEditor)previous).UpdateFormCode();
2921 else if(previous && !strcmp(dataType.name, "Designer"))
2923 ((Designer)previous).codeEditor.UpdateFormCode();
2928 dataType = client._class;
2929 if(client && !strcmp(dataType.name, "CodeEditor"))
2931 CodeEditor codeEditor = (CodeEditor)client;
2932 SetPrivateModule(codeEditor.privateModule);
2933 SetCurrentContext(codeEditor.globalContext);
2934 SetTopContext(codeEditor.globalContext);
2935 SetGlobalContext(codeEditor.globalContext);
2937 SetDefines(&codeEditor.defines);
2938 SetImports(&codeEditor.imports);
2940 SetActiveDesigner(codeEditor.designer);
2942 sheet.codeEditor = codeEditor;
2943 toolBox.codeEditor = codeEditor;
2945 viewDesignerItem.parent = viewMenu;
2946 if(activeChild != codeEditor)
2948 viewCodeItem.parent = viewMenu;
2949 viewDesignerItem.accelerator = 0;
2950 viewCodeItem.accelerator = f8;
2954 viewCodeItem.parent = null;
2955 viewDesignerItem.accelerator = f8;
2958 else if(client && !strcmp(dataType.name, "Designer"))
2960 CodeEditor codeEditor = ((Designer)client).codeEditor;
2963 SetPrivateModule(codeEditor.privateModule);
2964 SetCurrentContext(codeEditor.globalContext);
2965 SetTopContext(codeEditor.globalContext);
2966 SetGlobalContext(codeEditor.globalContext);
2967 SetDefines(&codeEditor.defines);
2968 SetImports(&codeEditor.imports);
2972 SetPrivateModule(null);
2973 SetCurrentContext(null);
2974 SetTopContext(null);
2975 SetGlobalContext(null);
2980 SetActiveDesigner((Designer)client);
2982 sheet.codeEditor = codeEditor;
2983 toolBox.codeEditor = codeEditor;
2985 viewCodeItem.parent = viewMenu;
2986 if(activeChild != client)
2988 viewDesignerItem.parent = viewMenu;
2989 viewDesignerItem.accelerator = f8;
2990 viewCodeItem.accelerator = 0;
2994 viewDesignerItem.parent = null;
2995 viewCodeItem.accelerator = f8;
3000 if(!client && !projectView && sheet.visible)
3003 sheet.visible = false;
3004 toolBox.visible = false;
3007 sheet.codeEditor = null;
3008 toolBox.codeEditor = null;
3009 SetActiveDesigner(null);
3011 viewDesignerItem.parent = null;
3012 viewCodeItem.parent = null;
3015 SheetSelected(sheet.sheetSelected);
3018 projectCompileItem = null;
3023 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3025 CodeEditor codeEditor = (CodeEditor)client;
3026 EditBox editBox = codeEditor.editBox;
3028 statusBar.AddField(pos);
3030 caps = { width = 40, text = $"CAPS" };
3031 statusBar.AddField(caps);
3032 UpdateStateLight(caps, app.GetKeyState(capsState));
3034 ovr = { width = 36, text = $"OVR" };
3035 statusBar.AddField(ovr);
3036 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3038 num = { width = 36, text = $"NUM" };
3039 statusBar.AddField(num);
3040 UpdateStateLight(num, app.GetKeyState(numState));
3042 //statusBar.text = "Ready";
3044 if(projectView && projectView.project)
3046 bool isCObject = false;
3047 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3048 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3052 char nodeName[MAX_FILENAME];
3053 char name[MAX_FILENAME+96];
3055 ChangeExtension(node.name, "c", nodeName);
3056 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3057 projectCompileItem =
3059 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3061 bool NotifySelect(MenuItem selection, Modifiers mods)
3065 bool isCObject = false;
3066 bool isExcluded = false;
3067 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3071 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3074 List<ProjectNode> nodes { };
3076 projectView.Compile(node.project, nodes, false, false, isCObject ? cObject : normal);
3084 projectMenu.AddDynamic(projectCompileItem, ide, false);
3090 caps = ovr = num = null;
3095 bool OnClose(bool parentClosing)
3097 //return !projectView.buildInProgress;
3098 if(projectView && projectView.buildInProgress)
3100 if(DontTerminateDebugSession($"Close IDE"))
3102 if(findInFilesDialog)
3103 findInFilesDialog.SearchStop();
3106 workspace.timer.Stop();
3109 ideMainFrame.Destroy(0);
3116 bool passThrough = false;
3117 bool debugWorkDir = false;
3118 char * passDebugWorkDir = null;
3119 bool openAsText = false;
3120 DynamicString passArgs { };
3123 for(c = 1; c<app.argc; c++)
3127 const char * arg = app.argv[c];
3128 char * buf = new char[strlen(arg)*2+1];
3130 passArgs.concat(" ");
3132 passArgs.concat(buf);
3135 else if(debugWorkDir)
3137 passDebugWorkDir = CopyString(app.argv[c]);
3138 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3139 debugWorkDir = false;
3141 else if(!strcmp(app.argv[c], "-t"))
3143 else if(!strcmp(app.argv[c], "-no-parsing"))
3144 ide.noParsing = true;
3145 else if(!strcmp(app.argv[c], "-debug-start"))
3146 ide.debugStart = true;
3147 else if(!strcmp(app.argv[c], "-debug-hide-ide"))
3148 ide.debugHideIDE = true;
3149 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3150 debugWorkDir = true;
3151 else if(!strcmp(app.argv[c], "-@"))
3155 char fullPath[MAX_LOCATION];
3156 char parentPath[MAX_LOCATION];
3157 char ext[MAX_EXTENSION];
3159 FileAttribs dirAttribs;
3160 GetWorkingDir(fullPath, MAX_LOCATION);
3161 PathCat(fullPath, app.argv[c]);
3162 StripLastDirectory(fullPath, parentPath);
3163 GetExtension(app.argv[c], ext);
3164 isProject = !openAsText && !strcmpi(ext, "epj");
3166 if(isProject && c > 1 + (ide.debugStart ? 1 : 0) + (ide.debugHideIDE ? 1 : 0)) continue;
3168 // Create directory for projects (only)
3169 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3171 if(isProject && !FileExists(fullPath))
3173 char name[MAX_LOCATION];
3174 NewProjectDialog newProjectDialog;
3178 projectView.visible = false;
3179 if(!projectView.Destroy(0))
3183 newProjectDialog = { master = this };
3185 strcpy(name, app.argv[c]);
3186 StripExtension(name);
3187 GetLastDirectory(name, name);
3188 newProjectDialog.projectName.contents = name;
3189 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3190 newProjectDialog.locationEditBox.path = parentPath;
3191 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3193 incref newProjectDialog;
3194 newProjectDialog.Modal();
3197 ideSettings.AddRecentProject(projectView.fileName);
3198 ide.UpdateRecentMenus();
3199 settingsContainer.Save();
3201 delete newProjectDialog;
3202 // Open only one project
3206 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3208 else if(strstr(fullPath, "http://") == fullPath)
3209 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3212 if(passThrough && projectView && projectView.project && workspace)
3213 workspace.commandLineArgs = passArgs;
3214 if(passDebugWorkDir && projectView && projectView.project && workspace)
3216 workspace.debugDir = passDebugWorkDir;
3217 delete passDebugWorkDir;
3220 UpdateToolBarActiveConfigs(false);
3221 UpdateToolBarActiveCompilers();
3228 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3231 projectView.visible = false;
3232 projectView.Destroy(0);
3235 #ifdef GDB_DEBUG_GUI
3236 gdbDialog.Destroy(0);
3241 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3245 char * oldPaths[128];
3246 String oldList = new char[maxPathLen];
3247 Array<String> newExePaths { };
3248 //Map<String, bool> exePathExists { };
3250 #if defined(__unix__) || defined(__APPLE__)
3251 Array<String> newLibPaths { };
3252 Map<String, bool> libPathExists { };
3257 for(prj : workspace.projects)
3259 DirExpression targetDirExp;
3261 // SKIP FIRST PROJECT...
3262 if(prj == workspace.projects.firstIterator.data) continue;
3264 // NOTE: Right now the additional project config dir will be
3265 // obtained when the debugger is started, so toggling it
3266 // while building will change which library gets used.
3267 // To go with the initial state, e.g. when F5 was pressed,
3268 // we nould need to keep a list of all project's active
3269 // config upon startup.
3270 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3272 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3276 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3277 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3281 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3282 if(cfg.targetType == sharedLibrary && cfg.debug)
3286 if(targetDirExp.dir)
3288 char buffer[MAX_LOCATION];
3289 #if defined(__WIN32__)
3290 Array<String> paths = newExePaths;
3292 Array<String> paths = newLibPaths;
3294 GetSystemPathBuffer(buffer, prj.topNode.path);
3295 PathCat(buffer, targetDirExp.dir);
3298 if(!fstrcmp(p, buffer))
3305 paths.Add(CopyString(buffer));
3307 delete targetDirExp;
3311 for(item : compiler.executableDirs)
3313 DirExpression dirExpr { };
3314 dirExpr.Evaluate(item, null, compiler, null, 0);
3317 for(p : newExePaths)
3319 if(!fstrcmp(p, dirExpr.dir))
3326 newExePaths.Add(CopySystemPath(dirExpr.dir));
3330 GetEnvironment("PATH", oldList, maxPathLen);
3332 printf("Old value of PATH: %s\n", oldList);
3334 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3335 for(c = 0; c < count; c++)
3338 for(p : newExePaths)
3340 if(!fstrcmp(p, oldPaths[c]))
3347 newExePaths.Add(CopySystemPath(oldPaths[c]));
3351 for(path : newExePaths)
3352 len += strlen(path) + 1;
3353 newList = new char[len + 1];
3355 for(path : newExePaths)
3357 strcat(newList, path);
3358 strcat(newList, pathListSep);
3360 newList[len - 1] = '\0';
3361 SetEnvironment("PATH", newList);
3363 printf("New value of PATH: %s\n", newList);
3370 #if defined(__unix__) || defined(__APPLE__)
3372 for(item : compiler.libraryDirs)
3374 if(!libPathExists[item]) // fstrcmp should be used
3376 String s = CopyString(item);
3378 libPathExists[s] = true;
3382 #if defined(__APPLE__)
3383 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3385 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3388 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3390 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3391 for(c = 0; c < count; c++)
3393 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3395 String s = CopyString(oldPaths[c]);
3397 libPathExists[s] = true;
3402 for(path : newLibPaths)
3403 len += strlen(path) + 1;
3404 newList = new char[len + 1];
3406 for(path : newLibPaths)
3408 strcat(newList, path);
3409 strcat(newList, pathListSep);
3411 newList[len - 1] = '\0';
3412 #if defined(__APPLE__)
3413 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3415 SetEnvironment("LD_LIBRARY_PATH", newList);
3418 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3424 delete libPathExists;
3427 if(compiler.distccEnabled && compiler.distccHosts)
3428 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3433 void DestroyTemporaryProjectDir()
3435 if(tmpPrjDir && tmpPrjDir[0])
3437 if(FileExists(tmpPrjDir).isDirectory)
3438 DestroyDir(tmpPrjDir);
3439 property::tmpPrjDir = null;
3445 // Graphics Driver Menu
3448 app.currentSkin.selectionColor = selectionColor;
3449 app.currentSkin.selectionText = selectionText;
3453 driverItems = new MenuItem[app.numDrivers];
3454 for(c = 0; c < app.numDrivers; c++)
3456 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3457 driverItems[c].id = c;
3458 driverItems[c].isRadio = true;
3461 driverItems = new MenuItem[2];
3462 #if defined(__unix__)
3463 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3464 driverItems[0].id = 0;
3465 driverItems[0].isRadio = true;
3467 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3468 driverItems[0].id = 0;
3469 driverItems[0].isRadio = true;
3471 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3472 driverItems[1].id = 1;
3473 driverItems[1].isRadio = true;
3475 /* skinItems = new MenuItem[app.numSkins];
3476 for(c = 0; c < app.numSkins; c++)
3478 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3479 skinItems[c].id = c;
3480 skinItems[c].isRadio = true;
3483 ideFileDialog.master = this;
3484 ideProjectFileDialog.master = this;
3486 //SetDriverAndSkin();
3490 void UpdateRecentMenus()
3493 Menu fileMenu = menu.FindMenu($"File");
3494 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3495 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3496 char * itemPath = new char[MAX_LOCATION];
3497 char * itemName = new char[MAX_LOCATION+4];
3499 recentFiles.Clear();
3502 for(recent : ideSettings.recentFiles)
3504 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3505 MakeSystemPath(itemPath);
3506 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3507 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3511 recentProjects.Clear();
3513 for(recent : ideSettings.recentProjects)
3515 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3516 MakeSystemPath(itemPath);
3517 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3518 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3530 delete languageItems;
3534 documentor.Puts("Quit\n");
3541 void DestroyDir(char * path)
3543 RecursiveDeleteFolderFSI fsi { };
3548 #if defined(__WIN32__)
3549 define sdkDirName = "Ecere SDK";
3551 define sdkDirName = "ecere";
3554 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3557 char * v = new char[maxPathLen];
3561 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3562 StripLastDirectory(path, path);
3563 PathCat(path, subDir);
3564 if(name) PathCat(path, name);
3565 if(FileExists(path) & attribs) found = true;
3567 #if defined(__WIN32__)
3570 GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3573 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3574 PathCat(path, subDir);
3575 if(name) PathCat(path, name);
3576 if(FileExists(path) & attribs) found = true;
3581 GetEnvironment("AppData", v, maxPathLen);
3584 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3585 PathCat(path, sdkDirName);
3586 PathCat(path, subDir);
3587 if(name) PathCat(path, name);
3588 if(FileExists(path) & attribs) found = true;
3593 GetEnvironment("ProgramData", v, maxPathLen);
3596 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3597 PathCat(path, sdkDirName);
3598 PathCat(path, subDir);
3599 if(name) PathCat(path, name);
3600 if(FileExists(path) & attribs) found = true;
3605 GetEnvironment("ProgramFiles", v, maxPathLen);
3608 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3609 PathCat(path, sdkDirName);
3610 PathCat(path, subDir);
3611 if(name) PathCat(path, name);
3612 if(FileExists(path) & attribs) found = true;
3617 GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3620 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3621 PathCat(path, sdkDirName);
3622 PathCat(path, subDir);
3623 if(name) PathCat(path, name);
3624 if(FileExists(path) & attribs) found = true;
3629 GetEnvironment("SystemDrive", v, maxPathLen);
3632 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3633 PathCat(path, "Program Files");
3634 PathCat(path, sdkDirName);
3635 PathCat(path, subDir);
3636 if(name) PathCat(path, name);
3637 if(FileExists(path) & attribs) found = true;
3646 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3647 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3648 for(c=0; c<numTokens; c++)
3650 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3651 PathCat(path, sdkDirName);
3652 PathCat(path, subDir);
3653 if(name) PathCat(path, name);
3654 if(FileExists(path) & attribs) found = true;
3662 void FindAndShellOpenInstalledFolder(const char * name)
3664 char path[MAX_LOCATION];
3665 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3669 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3671 char path[MAX_LOCATION];
3672 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3676 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3678 bool preserveRootFolder;
3680 void OutFolder(const char * folderPath, bool isRoot)
3682 if(!(preserveRootFolder && isRoot))
3683 RemoveDir(folderPath);
3686 bool OnFile(const char * filePath)
3688 DeleteFile(filePath);
3693 class IDEApp : GuiApplication
3695 //driver = "Win32Console";
3696 // driver = "OpenGL";
3700 TempFile includeFile { };
3705 char ext[MAX_EXTENSION];
3706 SetLoggingMode(stdOut, null);
3707 //SetLoggingMode(debug, null);
3709 settingsContainer.Load();
3711 if(ideSettings.language)
3713 const String language = GetLanguageString();
3714 if(ideSettings.language.OnCompare(language))
3716 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3721 // First count files arg to decide whether to maximize
3723 bool passThrough = false, debugWorkDir = false;
3726 for(c = 1; c<app.argc; c++)
3729 else if(debugWorkDir)
3730 debugWorkDir = false;
3731 else if(!strcmp(app.argv[c], "-t"));
3732 else if(!strcmp(app.argv[c], "-no-parsing"));
3733 else if(!strcmp(app.argv[c], "-debug-start"));
3734 else if(!strcmp(app.argv[c], "-debug-hide-ide"));
3735 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3736 debugWorkDir = true;
3737 else if(!strcmp(app.argv[c], "-@"))
3744 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3746 app.driver = "OpenGL";
3747 ide.driverItems[1].checked = true;
3751 #if defined(__unix__) || defined(__APPLE__)
3752 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3754 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3756 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3760 char model[MAX_LOCATION];
3761 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3763 ide.duck.modelFile = model;
3764 ide.duck.parent = ideMainFrame;
3767 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3768 ide.debugRubberDuck.disabled = false;
3772 desktop.caption = titleECEREIDE;
3775 for(c = 1; c<app.argc; c++)
3777 char fullPath[MAX_LOCATION];
3778 GetWorkingDir(fullPath, MAX_LOCATION);
3779 PathCat(fullPath, app.argv[c]);
3780 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3784 // Default to language specified by environment if no language selected
3785 if(!ideSettings.language)
3787 ideSettings.language = GetLanguageString();
3788 settingsContainer.Save();
3791 // Default to home directory if no directory yet set up
3792 if(!ideSettings.ideProjectFileDialogLocation[0])
3795 char location[MAX_LOCATION];
3796 char * home = getenv("HOME");
3797 char * homeDrive = getenv("HOMEDRIVE");
3798 char * homePath = getenv("HOMEPATH");
3799 char * userProfile = getenv("USERPROFILE");
3800 char * systemDrive = getenv("SystemDrive");
3801 if(home && FileExists(home).isDirectory)
3803 strcpy(location, home);
3806 if(!found && homeDrive && homePath)
3808 strcpy(location, homeDrive);
3809 PathCat(location, homePath);
3810 if(FileExists(location).isDirectory)
3813 if(!found && FileExists(userProfile).isDirectory)
3815 strcpy(location, userProfile);
3818 if(!found && FileExists(systemDrive).isDirectory)
3820 strcpy(location, systemDrive);
3825 ideSettings.ideProjectFileDialogLocation = location;
3826 if(!ideSettings.ideFileDialogLocation[0])
3827 ideSettings.ideFileDialogLocation = location;
3831 if(!LoadIncludeFile())
3832 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3834 // Create language menu
3836 String language = ideSettings.language;
3840 ide.languageItems = new MenuItem[languages.count];
3843 ide.languageItems[i] =
3845 ide.languageMenu, l.name;
3846 bitmap = { l.bitmap };
3850 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3852 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3854 // Re-select previous selected language if aborted
3855 String language = ideSettings.language;
3859 if(((!language || !language[0]) && i == 0) ||
3860 (language && !strcmpi(l.code, language)))
3862 ide.languageItems[i].checked = true;
3874 // Try to find country-specific language first
3880 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3882 ide.languageItems[i].checked = true;
3890 // Try generalizing locale
3891 if(!found && language)
3894 char genericLocale[256];
3896 strncpy(genericLocale, language, sizeof(genericLocale));
3897 genericLocale[sizeof(genericLocale)-1] = 0;
3899 under = strchr(genericLocale, '_');
3902 if(!strcmpi(genericLocale, "zh"))
3903 strcpy(genericLocale, "zh_CN");
3904 if(strcmp(genericLocale, language))
3908 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3910 ide.languageItems[i].checked = true;
3920 ide.languageItems[0].checked = true;
3922 MenuDivider { ide.languageMenu };
3925 ide.languageMenu, "Help Translate";
3927 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3929 ShellOpen("http://translations.launchpad.net/ecere");
3935 ideMainFrame.Create();
3936 if(app.argFilesCount > 1)
3937 ide.MenuWindowTileVert(null, 0);
3941 bool Cycle(bool idle)
3945 if(ide.documentor.Peek())
3948 ide.documentor.GetLine(line, sizeof(line));
3949 if(!strcmpi(line, "Exited"))
3951 ide.documentor.CloseInput();
3952 ide.documentor.CloseOutput();
3953 ide.documentor.Wait();
3954 delete ide.documentor;
3957 if(ide.documentor && ide.documentor.eof)
3959 ide.documentor.CloseInput();
3960 ide.documentor.CloseOutput();
3961 ide.documentor.Wait();
3962 delete ide.documentor;
3968 bool LoadIncludeFile()
3970 bool result = false;
3971 File include = FileOpen(":crossplatform.mk", read);
3974 File f = includeFile;
3977 for(; !include.Eof(); )
3980 int count = include.Read(buffer, 1, 4096);
3981 f.Write(buffer, 1, count);
3991 IDEMainFrame ideMainFrame { };
3993 define app = ((IDEApp)__thisModule);
3995 define titleECEREIDE = $"Ecere IDE (Debug)";
3997 define titleECEREIDE = $"Ecere IDE";