2 public import static "ecere"
3 public import static "ec"
9 import "GlobalSettingsDialog"
10 import "NewProjectDialog"
11 import "FindInFilesDialog"
18 import "ProjectConfig"
20 import "NodeProperties"
21 import "ProjectSettings"
33 import "BreakpointsView"
34 import "CallStackView"
45 import "FileSystemIterator"
47 AVLTree<const String> binaryDocExt
49 "wav", "mp3", "flac", "ogg",
51 "avi", "mkv", "mpg", "mpeg",
52 "7z", "zip", "gz", "bz2", "xz", "rar", "z", "tar", "ear",
53 "pdf", "odp", "ods", "odt", "ppt", "doc", "xls", "pptx", "docx", "xlsx"
56 #if defined(__WIN32__)
57 define pathListSep = ";";
59 define pathListSep = ":";
62 define maxPathLen = 65 * MAX_LOCATION;
64 class PathBackup : struct
71 oldPath = new char[maxPathLen];
72 oldLDPath = new char[maxPathLen];
74 GetEnvironment("PATH", oldPath, maxPathLen);
75 #if defined(__APPLE__)
76 GetEnvironment("DYLD_LIBRARY_PATH", oldLDPath, maxPathLen);
78 GetEnvironment("LD_LIBRARY_PATH", oldLDPath, maxPathLen);
84 SetEnvironment("PATH", oldPath);
85 #if defined(__APPLE__)
86 SetEnvironment("DYLD_LIBRARY_PATH", oldLDPath);
88 SetEnvironment("LD_LIBRARY_PATH", oldLDPath);
95 enum OpenCreateIfFails { no, yes, something, whatever };
96 enum OpenMethod { normal, add };
98 static Array<FileFilter> fileFilters
100 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
101 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
102 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
103 { $"Text files (*.txt, *.text, *.nfo, *.info)", "txt, text, nfo, info" },
104 { $"Web files (*.html, *.htm, *.xhtml, *.css, *.php, *.js, *.jsi, *.rb, *.xml)", "html, htm, xhtml, css, php, js, jsi, rb, xml" },
105 { $"Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", "jpg, jpeg, bmp, pcx, png, gif" },
106 { $"3D Studio Model Files (*.3ds)", "3ds" },
107 { $"All files", null }
110 static Array<FileType> fileTypes
112 { $"Based on extension", null },
115 { $"3D Studio Model", "3ds" }
118 static Array<FileFilter> projectFilters
120 { $"Project Files (*.epj)", ProjectExtension }
123 static Array<FileType> projectTypes
125 { $"Project File", ProjectExtension }
128 static Array<FileFilter> findInFilesFileFilters
130 { $"eC Files (*.ec, *.eh)", "ec, eh" },
131 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
132 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
133 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
134 { $"Text files (*.txt)", "txt" },
135 { $"All files", null }
138 FileDialog ideFileDialog
140 type = multiOpen, text = $"Open";
141 types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType), filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter);
144 define openProjectFileDialogTitle = $"Open Project";
145 define addProjectFileDialogTitle = $"Open Additional Project";
146 FileDialog ideProjectFileDialog
149 types = projectTypes.array, sizeTypes = projectTypes.count * sizeof(FileType), filters = projectFilters.array, sizeFilters = projectFilters.count * sizeof(FileFilter);
152 GlobalSettingsDialog globalSettingsDialog
154 ideSettings = ideSettings;
155 settingsContainer = settingsContainer;
157 void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange)
159 switch(globalSettingsChange)
164 for(child = ide.firstChild; child; child = child.next)
166 if(child._class == class(CodeEditor))
168 CodeEditor codeEditor = (CodeEditor) child;
169 codeEditor.editBox.freeCaret = ideSettings.useFreeCaret;
170 // codeEditor.editBox.lineNumbers = ideSettings.showLineNumbers;
171 codeEditor.editBox.caretFollowsScrolling = ideSettings.caretFollowsScrolling;
172 codeEditor.OnPostCreate(); // Update editBox margin size
179 case compilerSettings:
181 ide.UpdateCompilerConfigs(true);
188 void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
193 lineY = (line - 1) * lineH;
194 if(lineY + lineH > scrollY && lineY + lineH < scrollY + boxH)
196 Bitmap bitmap = resource.bitmap;
198 surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
203 #define IDEItem(x) (&((IDEWorkSpace)0).x)
205 class IDEToolbar : ToolBar
209 ToolButton buttonNewFile { this, toolTip = $"New file", menuItemPtr = IDEItem(fileNewItem) };
211 ToolButton buttonOpenFile { this, toolTip = $"Open file", menuItemPtr = IDEItem(fileOpenItem) };
213 // ToolButton buttonCloseFile { this, toolTip = $"Close file", menuItemPtr = IDEItem(fileCloseItem) };
215 ToolButton buttonSaveFile { this, toolTip = $"Save file", menuItemPtr = IDEItem(fileSaveItem) };
217 ToolButton buttonSaveAllFile { this, toolTip = $"Save all", menuItemPtr = IDEItem(fileSaveAllItem) };
219 ToolSeparator separator1 { this };
228 // ToolSeparator separator2 { this };
232 ToolButton buttonNewProject { this, toolTip = $"New project", menuItemPtr = IDEItem(projectNewItem) };
234 ToolButton buttonOpenProject { this, toolTip = $"Open project", menuItemPtr = IDEItem(projectOpenItem) };
235 // Add project to workspace
236 ToolButton buttonAddProject { this, toolTip = $"Add project to workspace", menuItemPtr = IDEItem(projectAddItem), disabled = true; };
238 // ToolButton buttonCloseProject { this, toolTip = $"Close project", menuItemPtr = IDEItem(projectCloseItem), disabled = true; };
240 ToolSeparator separator3 { this };
242 // Build/Execution options
244 ToolButton buttonBuild { this, toolTip = $"Build project", menuItemPtr = IDEItem(projectBuildItem), disabled = true; };
246 ToolButton buttonReLink { this, toolTip = $"Relink project", menuItemPtr = IDEItem(projectLinkItem), disabled = true; };
248 ToolButton buttonRebuild { this, toolTip = $"Rebuild project", menuItemPtr = IDEItem(projectRebuildItem), disabled = true; };
250 ToolButton buttonClean { this, toolTip = $"Clean project", menuItemPtr = IDEItem(projectCleanItem), disabled = true; };
252 // ToolButton buttonRealClean { this, toolTip = $"Real clean project", menuItemPtr = IDEItem(projectRealCleanItem), disabled = true; };
253 // Regenerate Makefile
254 ToolButton buttonRegenerateMakefile { this, toolTip = $"Regenerate Makefile", menuItemPtr = IDEItem(projectRegenerateItem), disabled = true; };
255 // Compile actual file
257 ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem), disabled = true; };
258 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
259 ToolButton buttonInstall { this, toolTip = $"Install", menuItemPtr = IDEItem(projectInstallItem), disabled = true; };
262 ToolSeparator separator4 { this };
266 ToolButton buttonDebugStartResume { this, toolTip = $"Start", menuItemPtr = IDEItem(debugStartResumeItem), disabled = true; };
268 ToolButton buttonDebugRestart { this, toolTip = $"Restart", menuItemPtr = IDEItem(debugRestartItem), disabled = true; };
270 ToolButton buttonDebugPause { this, toolTip = $"Break", menuItemPtr = IDEItem(debugBreakItem), disabled = true; };
272 ToolButton buttonDebugStop { this, toolTip = $"Stop", menuItemPtr = IDEItem(debugStopItem), disabled = true; };
274 //ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem) };
276 ToolButton buttonDebugStepInto { this, toolTip = $"Step Into", menuItemPtr = IDEItem(debugStepIntoItem), disabled = true; };
278 ToolButton buttonDebugStepOver { this, toolTip = $"Step Over", menuItemPtr = IDEItem(debugStepOverItem), disabled = true; };
280 ToolButton buttonDebugStepOut { this, toolTip = $"Step Out", menuItemPtr = IDEItem(debugStepOutItem), disabled = true; };
282 ToolButton buttonDebugSkipStepOver { this, toolTip = $"Step Over Skipping Breakpoints", menuItemPtr = IDEItem(debugSkipStepOverItem), disabled = true; };
284 ToolSeparator separator5 { this };
286 Window spacer5 { this, size = { 4 } };
290 this, toolTip = $"Active Configuration(s)", size = { 160 }, disabled = true;
291 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
294 ide.workspace.SelectActiveConfig(row.string);
299 Window spacer6 { this, size = { 4 } };
301 DropBox activeCompiler
303 this, toolTip = $"Active Compiler", size = { 160 }, disabled = true;
304 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
306 if(ide.workspace && ide.projectView && row && strcmp(row.string, ide.workspace.compiler))
308 bool silent = ide.projectView.buildInProgress == none ? false : true;
309 CompilerConfig compiler = ideSettings.GetCompilerConfig(row.string);
310 ide.workspace.compiler = row.string;
311 ide.projectView.ShowOutputBuildLog(!silent);
313 ide.projectView.DisplayCompiler(compiler, false);
314 for(prj : ide.workspace.projects)
315 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
317 ide.workspace.Save();
323 DropBox activeBitDepth
325 this, toolTip = $"Active Bit Length", size = { 60 }, disabled = true;
326 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
328 if(ide.workspace && ide.projectView && row)
330 bool silent = ide.projectView.buildInProgress == none ? false : true;
331 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
332 ide.workspace.bitDepth = (int)row.tag;
333 ide.projectView.ShowOutputBuildLog(!silent);
335 ide.projectView.DisplayCompiler(compiler, false);
336 for(prj : ide.workspace.projects)
337 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
339 ide.workspace.Save();
345 Window spacer7 { this, size = { 4 } };
350 row = activeBitDepth.AddString("Auto");
352 activeBitDepth.AddString("32 bit").tag = 32;
353 activeBitDepth.AddString("64 bit").tag = 64;
354 activeBitDepth.currentRow = row;
358 class IDEMainFrame : Window
360 background = formColor;
361 borderStyle = sizable;
365 minClientSize = { 600, 300 };
367 icon = { ":icon.png" };
368 text = titleECEREIDE;
372 anchor = { top = 0, right = 0, bottom = 0 };
375 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
382 isActiveClient = true;
384 direction = vertical;
385 background = formColor;
386 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
394 ((IDEWorkSpace)master).toolBar = null;
397 IDEWorkSpace ideWorkSpace { stack, this, toolBar = toolBar };
400 define ide = ideMainFrame.ideWorkSpace;
402 class IDEWorkSpace : Window
404 background = Color { 85, 85, 85 };
407 hasVertScroll = true;
408 hasHorzScroll = true;
410 isActiveClient = true;
411 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
415 MenuItem * driverItems, * skinItems, * languageItems;
416 StatusField pos { width = 150 };
417 StatusField ovr, caps, num;
420 BitmapResource back { ":ecereBack.jpg", window = this };
421 BitmapResource bmpBp { ":codeMarks/breakpoint.png", window = this };
422 BitmapResource bmpBpDisabled { ":codeMarks/breakpointDisabled.png", window = this };
423 BitmapResource bmpBpHalf { ":codeMarks/breakpointHalf.png", window = this };
424 BitmapResource bmpBpHalfDisabled { ":codeMarks/breakpointHalfDisabled.png", window = this };
425 BitmapResource bmpCursor { ":codeMarks/cursor.png", window = this };
426 BitmapResource bmpCursorError { ":codeMarks/cursorError.png", window = this };
427 BitmapResource bmpTopFrame { ":codeMarks/topFrame.png", window = this };
428 BitmapResource bmpTopFrameError { ":codeMarks/topFrameError.png", window = this };
429 BitmapResource bmpTopFrameHalf { ":codeMarks/topFrameHalf.png", window = this };
430 BitmapResource bmpTopFrameHalfError { ":codeMarks/topFrameHalfError.png", window = this };
432 Debugger debugger { };
434 ProjectView projectView;
436 OutputView outputView
440 void OnGotoError(const char * line, bool noParsing)
442 CompilerConfig compiler = ide.workspace ? ideSettings.GetCompilerConfig(ide.workspace.compiler) : null;
443 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
444 ide.GoToError(line, noParsing, objectFileExt);
447 void OnCodeLocationParseAndGoTo(const char * line)
449 CompilerConfig compiler = ide.workspace ? ideSettings.GetCompilerConfig(ide.workspace.compiler) : null;
450 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
451 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir, objectFileExt);
454 bool OnKeyDown(Key key, unichar ch)
459 if(activeBox != findBox || !ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
460 ide.ShowCodeEditor();
464 OutputView::OnKeyDown(key, ch);
471 bool OnClose(bool parentClosing)
475 ide.RepositionWindows(false);
476 return parentClosing;
480 CallStackView callStackView
482 parent = this, font = { panelFont.faceName, panelFont.size };
484 void OnSelectFrame(int frameIndex)
486 ide.debugger.GoToStackFrameLine(frameIndex, true, true);
488 ide.debugger.SelectFrame(frameIndex);
491 void OnToggleBreakpoint()
493 Debugger debugger = ide.debugger;
494 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
496 int line = debugger.activeFrame.line;
497 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line);
500 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
501 if(codeEditor) { codeEditor.Update(null); Activate(); }
506 bool OnKeyDown(Key key, unichar ch)
510 case escape: ide.ShowCodeEditor(); break;
515 bool OnClose(bool parentClosing)
519 ide.RepositionWindows(false);
520 return parentClosing;
523 void OnRedraw(Surface surface)
525 Debugger debugger = ide.debugger;
526 Frame activeFrame = debugger.activeFrame;
530 int lineCursor, lineTopFrame;
531 int lineH, scrollY, boxH;
533 Breakpoint bp = null;
536 scrollY = editBox.scroll.y;
537 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
538 //activeThread = debugger.activeThread;
539 //hitThread = debugger.hitThread;
540 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
542 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
543 if(activeFrame.absoluteFile)
545 for(i : ide.workspace.breakpoints; i.type == user)
547 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
548 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
549 activeFrame.line == i.line)
557 DrawLineMarginIcon(surface,
558 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
559 lineCursor /*1*/, lineH, scrollY, boxH);
561 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
562 DrawLineMarginIcon(surface,
563 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
564 1, lineH, scrollY, boxH);
566 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
567 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
568 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
570 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
571 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
573 if(editBox.horzScroll && editBox.horzScroll.visible)
575 surface.SetBackground(control);
576 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
581 WatchesView watchesView { parent = this };
582 ThreadsView threadsView
584 parent = this, font = { panelFont.faceName, panelFont.size };
586 bool OnKeyDown(Key key, unichar ch)
590 case escape: ide.ShowCodeEditor(); break;
595 bool OnClose(bool parentClosing)
599 ide.RepositionWindows(false);
600 return parentClosing;
603 void OnSelectThread(int threadId)
606 ide.debugger.SelectThread(threadId);
609 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
612 Debugger debugger = ide.debugger;
613 *activeThread = debugger.activeThread;
614 *hitThread = debugger.hitThread;
615 *signalThread = debugger.signalThread;
620 BreakpointsView breakpointsView { parent = this };
622 ToolBox toolBox { parent = this, visible = false };
623 Sheet sheet { parent = this, visible = false };
626 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
628 Menu fileMenu { menu, $"File", f, hasMargin = true };
631 fileMenu, $"New", n, ctrlN;
632 bitmap = { ":actions/docNew.png" };
633 bool NotifySelect(MenuItem selection, Modifiers mods)
635 Window currentDoc = activeClient;
636 bool maximizeDoc = ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
637 Window document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, false);
638 RepositionWindows(false);
639 document.NotifySaved = DocumentSaved;
643 MenuItem fileOpenItem
645 fileMenu, $"Open...", o, ctrlO;
646 bitmap = { ":actions/docOpen.png" };
647 bool NotifySelect(MenuItem selection, Modifiers mods)
649 if(!projectView && ideSettings.ideFileDialogLocation)
650 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
653 if(ideFileDialog.Modal() == ok)
655 bool gotWhatWeWant = false;
657 int numSelections = ideFileDialog.numSelections;
658 const char * const * multiFilePaths = ideFileDialog.multiFilePaths;
660 for(c = 0; c < numSelections; c++)
662 if(OpenFile(multiFilePaths[c], false, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
663 gotWhatWeWant = true;
666 MessageBox { type = yesNo, master = this, text = $"Error opening file",
667 contents = $"Open a different file?" }.Modal() == no)
669 if(!projectView && gotWhatWeWant)
670 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
671 ide.RepositionWindows(false);
681 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
682 MenuDivider { fileMenu };
683 MenuItem fileSaveItem
685 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
687 // For the toolbar button; clients can still override that for the menu item
688 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
690 Window w = activeClient;
692 w.MenuFileSave(null, 0);
696 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
697 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
698 MenuDivider { fileMenu };
701 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
702 bool NotifySelect(MenuItem selection, Modifiers mods)
704 findInFilesDialog.replaceMode = false;
705 findInFilesDialog.Show();
709 MenuItem replaceInFiles
711 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
712 bool NotifySelect(MenuItem selection, Modifiers mods)
714 findInFilesDialog.replaceMode = true;
715 findInFilesDialog.Show();
719 MenuDivider { fileMenu };
720 MenuItem globalSettingsItem
722 fileMenu, $"Global Settings...", g;
723 bool NotifySelect(MenuItem selection, Modifiers mods)
725 globalSettingsDialog.master = this;
726 if(ide.workspace && ide.workspace.compiler)
727 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.compiler;
728 else if(ideSettings.defaultCompiler)
729 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
730 globalSettingsDialog.Modal();
734 MenuDivider { fileMenu };
735 Menu recentFiles { fileMenu, $"Recent Files", r };
736 Menu recentProjects { fileMenu, $"Recent Projects", p };
737 MenuDivider { fileMenu };
740 fileMenu, $"Exit", x, altF4;
742 bool NotifySelect(MenuItem selection, Modifiers mods)
744 ideMainFrame.Destroy(0);
749 bool FileRecentFile(MenuItem selection, Modifiers mods)
752 for(file : ideSettings.recentFiles)
754 if(id == selection.id)
757 char extension[MAX_EXTENSION] = "";
758 GetExtension(file, extension);
759 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
762 char * command = PrintString("ide ", isProjectFile ? "-t " : "", file);
768 OpenFile(file, false, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
769 ide.RepositionWindows(false);
778 bool FileRecentProject(MenuItem selection, Modifiers mods)
781 for(file : ideSettings.recentProjects)
783 if(id == selection.id)
787 char * command = PrintString("ide ", file);
792 OpenFile(file, false, true, null, no, normal, mods.ctrl && mods.shift);
800 MenuPlacement editMenu { menu, $"Edit", e };
802 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
803 MenuItem projectNewItem
805 projectMenu, $"New...", n, Key { n, true, true };
806 bitmap = { ":actions/projNew.png" };
807 bool NotifySelect(MenuItem selection, Modifiers mods)
809 if(!DontTerminateDebugSession($"New Project"))
812 NewProjectDialog newProjectDialog { master = this };
813 incref newProjectDialog;
814 result = newProjectDialog.Modal();
819 newProjectDialog.CreateNewProject();
822 ideSettings.AddRecentProject(projectView.fileName);
823 ide.UpdateRecentMenus();
824 settingsContainer.Save();
828 delete newProjectDialog;
833 MenuItem projectOpenItem
835 projectMenu, $"Open...", o, Key { o, true, true };
836 bitmap = { ":actions/projOpen.png" };
837 bool NotifySelect(MenuItem selection, Modifiers mods)
839 if(ideSettings.ideProjectFileDialogLocation)
840 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
842 ideProjectFileDialog.text = openProjectFileDialogTitle;
843 if(ideProjectFileDialog.Modal() == ok)
845 OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
846 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
851 MenuItem projectQuickItem
853 projectMenu, $"Quick...", q, f7, disabled = true;
854 bool NotifySelect(MenuItem selection, Modifiers mods)
857 QuickProjectDialog { this }.Modal();
861 MenuItem projectAddItem
863 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
864 bitmap = { ":actions/projAdd.png" };
866 bool NotifySelect(MenuItem selection, Modifiers mods)
868 if(ideSettings.ideProjectFileDialogLocation)
869 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
871 ideProjectFileDialog.text = addProjectFileDialogTitle;
874 if(ideProjectFileDialog.Modal() == ok)
876 if(OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
878 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
879 contents = $"Add a different project?" }.Modal() == no)
890 MenuItem projectCloseItem
892 projectMenu, $"Close", c, disabled = true;
893 bool NotifySelect(MenuItem selection, Modifiers mods)
897 if(!ide.DontTerminateDebugSession($"Project Close"))
903 MenuDivider { projectMenu };
904 MenuItem projectSettingsItem
906 projectMenu, $"Settings...", s, altF7, disabled = true;
907 bool NotifySelect(MenuItem selection, Modifiers mods)
909 projectView.MenuSettings(projectView.active ? selection : null, mods);
913 MenuDivider { projectMenu };
914 MenuItem projectBrowseFolderItem
916 projectMenu, $"Browse Project Folder", p, disabled = true;
917 bool NotifySelect(MenuItem selection, Modifiers mods)
920 projectView.MenuBrowseFolder(null, mods);
924 MenuDivider { projectMenu };
925 MenuItem projectRunItem
927 projectMenu, $"Run", r, ctrlF5, disabled = true;
928 bitmap = { ":actions/run.png" };
929 bool NotifySelect(MenuItem selection, Modifiers mods)
932 projectView.Run(null, mods);
936 MenuItem projectBuildItem
938 projectMenu, $"Build", b, f7, disabled = true;
939 bitmap = { ":actions/build.png" };
940 bool NotifySelect(MenuItem selection, Modifiers mods)
944 if(projectView.buildInProgress == none)
945 projectView.ProjectBuild(projectView.active ? selection : null, mods);
947 projectView.stopBuild = true;
952 MenuItem projectLinkItem
954 projectMenu, $"Relink", l, disabled = true;
955 bitmap = { ":actions/relink.png" };
956 bool NotifySelect(MenuItem selection, Modifiers mods)
959 projectView.ProjectLink(projectView.active ? selection : null, mods);
963 MenuItem projectRebuildItem
965 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
966 bitmap = { ":actions/rebuild.png" };
967 bool NotifySelect(MenuItem selection, Modifiers mods)
970 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
974 MenuItem projectCleanTargetItem
976 projectMenu, $"Clean Target", g, disabled = true;
977 bitmap = { ":actions/clean.png" };
978 bool NotifySelect(MenuItem selection, Modifiers mods)
983 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
988 MenuItem projectCleanItem
990 projectMenu, $"Clean", e, disabled = true;
991 bitmap = { ":actions/clean.png" };
992 bool NotifySelect(MenuItem selection, Modifiers mods)
997 projectView.ProjectClean(projectView.active ? selection : null, mods);
1002 MenuItem projectRealCleanItem
1004 projectMenu, $"Real Clean", disabled = true;
1005 bitmap = { ":actions/clean.png" };
1006 bool NotifySelect(MenuItem selection, Modifiers mods)
1011 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1016 MenuItem projectRegenerateItem
1018 projectMenu, $"Regenerate Makefile", m, disabled = true;
1019 bitmap = { ":actions/regMakefile.png" };
1020 bool NotifySelect(MenuItem selection, Modifiers mods)
1023 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1027 MenuItem projectInstallItem
1029 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
1030 projectMenu, $"Install", t, disabled = true;
1032 bitmap = { ":status/software-update-available.png" };
1033 bool NotifySelect(MenuItem selection, Modifiers mods)
1036 projectView.ProjectInstall(projectView.active ? selection : null, mods);
1040 MenuItem projectCompileItem;
1041 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1042 MenuItem debugStartResumeItem
1044 debugMenu, $"Start", s, f5, disabled = true;
1045 bitmap = { ":actions/debug.png" };
1046 NotifySelect = MenuDebugStart;
1048 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1052 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1053 if(!projectView.DebugStart())
1054 debugStartResumeItem.disabled = false; // same exception
1058 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1061 projectView.DebugResume();
1064 MenuItem debugRestartItem
1066 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1067 bitmap = { ":actions/restart.png" };
1068 bool NotifySelect(MenuItem selection, Modifiers mods)
1071 projectView.DebugRestart();
1075 MenuItem debugBreakItem
1077 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1078 bitmap = { ":actions/pause.png" };
1079 bool NotifySelect(MenuItem selection, Modifiers mods)
1081 if(projectView && projectView.buildInProgress != none)
1084 projectView.DebugBreak();
1088 MenuItem debugStopItem
1090 debugMenu, $"Stop", p, shiftF5, disabled = true;
1091 bitmap = { ":actions/stopDebug.png" };
1092 bool NotifySelect(MenuItem selection, Modifiers mods)
1095 projectView.DebugStop();
1099 MenuDivider { debugMenu };
1103 // nonClient = true,
1110 anchor = { right = 0, bottom = 0 },
1112 isActiveClient = false,
1114 clickThrough = true,
1115 size = { 500, 500 };
1117 bool OnLoadGraphics()
1119 ModelView::OnLoadGraphics();
1120 camera.position.z /= 1.3;
1121 camera.orientation = Euler { yaw = 280, pitch = 20 };
1127 bool OnRightButtonDown(int x, int y, Modifiers mods)
1129 if(!displaySystem.flags.flipping) return true;
1130 MenuWindowMove(null, 0);
1134 bool OnRightButtonUp(int x, int y, Modifiers mods)
1136 position = position;
1141 MenuItem debugRubberDuck
1143 debugMenu, $"Rubber Duck", checkable = true, disabled = true;
1144 bool NotifySelect(MenuItem selection, Modifiers mods)
1146 if(selection.checked)
1154 MenuDivider { debugMenu };
1155 MenuItem debugUseValgrindItem
1157 debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
1158 bool NotifySelect(MenuItem selection, Modifiers mods)
1162 ide.workspace.useValgrind = selection.checked;
1163 ide.workspace.Save();
1165 ide.AdjustValgrindMenus();
1169 Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
1170 MenuItem debugValgrindNoLeakCheckItem { debugValgrindLeakCheckItem, $"No" , f, id = ValgrindLeakCheck::no , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1171 MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; };
1172 MenuItem debugValgrindYesLeakCheckItem { debugValgrindLeakCheckItem, $"Yes" , f, id = ValgrindLeakCheck::yes , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1173 MenuItem debugValgrindFullLeakCheckItem { debugValgrindLeakCheckItem, $"Full" , f, id = ValgrindLeakCheck::full , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1174 bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
1178 if(selection.checked)
1180 ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
1182 debugValgrindNoLeakCheckItem.checked = debugValgrindNoLeakCheckItem.id == vgLeakCheck;
1183 debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
1184 debugValgrindYesLeakCheckItem.checked = debugValgrindYesLeakCheckItem.id == vgLeakCheck;
1185 debugValgrindFullLeakCheckItem.checked = debugValgrindFullLeakCheckItem.id == vgLeakCheck;
1187 ide.workspace.vgLeakCheck = vgLeakCheck;
1188 ide.workspace.Save();
1191 selection.checked = true;
1195 Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
1196 MenuItem debugValgrindRSDefaultItem { debugValgrindRedzoneSizeItem, $"Default", f, id = -1, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; };
1197 MenuItem debugValgrindRS0Item { debugValgrindRedzoneSizeItem, "0" , f, id = 0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1198 MenuItem debugValgrindRS16Item { debugValgrindRedzoneSizeItem, "16" , f, id = 16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1199 MenuItem debugValgrindRS32Item { debugValgrindRedzoneSizeItem, "32" , f, id = 32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1200 MenuItem debugValgrindRS64Item { debugValgrindRedzoneSizeItem, "64" , f, id = 64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1201 MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, "128" , f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1202 MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, "256" , f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1203 MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, "512" , f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1204 bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
1208 if(selection.checked)
1210 int vgRedzoneSize = (int)selection.id;
1212 debugValgrindRSDefaultItem.checked = debugValgrindRSDefaultItem.id == vgRedzoneSize;
1213 debugValgrindRS0Item.checked = debugValgrindRS0Item.id == vgRedzoneSize;
1214 debugValgrindRS16Item.checked = debugValgrindRS16Item.id == vgRedzoneSize;
1215 debugValgrindRS32Item.checked = debugValgrindRS32Item.id == vgRedzoneSize;
1216 debugValgrindRS64Item.checked = debugValgrindRS64Item.id == vgRedzoneSize;
1217 debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
1218 debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
1219 debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
1221 ide.workspace.vgRedzoneSize = vgRedzoneSize;
1222 ide.workspace.Save();
1225 selection.checked = true;
1229 MenuItem debugValgrindTrackOriginsItem
1231 debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
1232 bool NotifySelect(MenuItem selection, Modifiers mods)
1236 ide.workspace.vgTrackOrigins = selection.checked;
1237 ide.workspace.Save();
1243 MenuDivider { debugMenu };
1244 MenuItem debugStepIntoItem
1246 debugMenu, $"Step Into", i, f11, disabled = true;
1247 bitmap = { ":actions/stepInto.png" };
1248 bool NotifySelect(MenuItem selection, Modifiers mods)
1250 if(projectView) projectView.DebugStepInto();
1254 MenuItem debugStepOverItem
1256 debugMenu, $"Step Over", v, f10, disabled = true;
1257 bitmap = { ":actions/stepOver.png" };
1258 bool NotifySelect(MenuItem selection, Modifiers mods)
1260 if(projectView) projectView.DebugStepOver(false);
1264 MenuItem debugSkipStepOverItem
1266 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1267 bitmap = { ":actions/stepOverSkipBreak.png" };
1268 bool NotifySelect(MenuItem selection, Modifiers mods)
1270 if(projectView) projectView.DebugStepOver(true);
1274 MenuItem debugStepOutItem
1276 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1277 bitmap = { ":actions/stepOut.png" };
1278 bool NotifySelect(MenuItem selection, Modifiers mods)
1280 if(projectView) projectView.DebugStepOut(false);
1284 MenuItem debugSkipStepOutItem
1286 debugMenu, $"Step Out Skipping Breakpoints", n, Key { f11, ctrl = true, shift = true }, disabled = true;
1287 bitmap = { ":actions/skipBreaks.png" };
1288 bool NotifySelect(MenuItem selection, Modifiers mods)
1290 if(projectView) projectView.DebugStepOut(true);
1295 MenuItem debugStepUntilItem
1297 debugMenu, $"Step Over Until Next Line", x, disabled = true;
1298 bool NotifySelect(MenuItem selection, Modifiers mods)
1300 if(projectView) projectView.DebugStepUntil(false);
1304 MenuItem debugSkipStepUntilItem
1306 debugMenu, $"Step Over Until Next Line Skipping Breakpoints", e, Key { f10, shift = true, alt = true }, disabled = true;
1307 bool NotifySelect(MenuItem selection, Modifiers mods)
1309 if(projectView) projectView.DebugStepUntil(true);
1314 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1315 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1316 MenuPlacement debugRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level", l };
1317 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", g };
1319 MenuPlacement debugBpRunToCursorItem { debugMenu, $"BP Run To Cursor" };
1320 MenuPlacement debugBpSkipRunToCursorItem { debugMenu, $"BP Run To Cursor Skipping Breakpoints" };
1321 MenuPlacement debugBpRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level" };
1322 MenuPlacement debugBpSkipRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level Skipping Breakpoints" };
1324 //MenuDivider { debugMenu };
1325 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1326 MenuPlacement imageMenu { menu, $"Image", i };
1327 Menu viewMenu { menu, $"View", v };
1328 MenuItem viewProjectItem
1330 viewMenu, $"Project View", j, alt0, disabled = true;
1331 bool NotifySelect(MenuItem selection, Modifiers mods)
1335 projectView.visible = true;
1336 projectView.Activate();
1341 MenuPlacement { viewMenu, $"View Designer" };
1342 MenuPlacement { viewMenu, $"View Code" };
1343 MenuPlacement { viewMenu, $"View Properties" };
1344 MenuPlacement { viewMenu, $"View Methods" };
1345 MenuItem viewDesignerItem
1347 viewMenu, $"View Designer", d, f8;
1348 bool NotifySelect(MenuItem selection, Modifiers mods)
1350 Window client = activeClient;
1351 Class dataType = client._class;
1352 if(!strcmp(dataType.name, "Designer"))
1354 client.visible = true;
1358 ((CodeEditor)client).ViewDesigner();
1362 MenuItem viewCodeItem
1364 viewMenu, $"View Code", c, f8;
1365 bool NotifySelect(MenuItem selection, Modifiers mods)
1367 Window client = activeClient;
1368 Class dataType = client._class;
1369 if(!strcmp(dataType.name, "Designer"))
1370 client = ((Designer)client).codeEditor;
1373 // Do this after so the caret isn't moved yet...
1374 client.visible = true;
1378 MenuItem viewPropertiesItem
1380 viewMenu, $"View Properties", p, f4;
1381 bool NotifySelect(MenuItem selection, Modifiers mods)
1383 sheet.visible = true;
1384 sheet.sheetSelected = properties;
1389 MenuItem viewMethodsItem
1391 viewMenu, $"View Methods", m, f4;
1392 bool NotifySelect(MenuItem selection, Modifiers mods)
1394 sheet.visible = true;
1395 sheet.sheetSelected = methods;
1400 MenuItem viewToolBoxItem
1402 viewMenu, $"View Toolbox", x, f12;
1403 bool NotifySelect(MenuItem selection, Modifiers mods)
1405 toolBox.visible = true;
1410 MenuItem viewOutputItem
1412 viewMenu, $"Output", o, alt2;
1413 bool NotifySelect(MenuItem selection, Modifiers mods)
1419 MenuItem viewWatchesItem
1421 viewMenu, $"Watches", w, alt3;
1422 bool NotifySelect(MenuItem selection, Modifiers mods)
1428 MenuItem viewThreadsItem
1430 viewMenu, $"Threads", t, alt4;
1431 bool NotifySelect(MenuItem selection, Modifiers mods)
1437 MenuItem viewBreakpointsItem
1439 viewMenu, $"Breakpoints", b, alt5;
1440 bool NotifySelect(MenuItem selection, Modifiers mods)
1442 breakpointsView.Show();
1446 MenuItem viewCallStackItem
1448 viewMenu, $"Call Stack", s, alt7;
1449 bool NotifySelect(MenuItem selection, Modifiers mods)
1451 callStackView.Show();
1455 MenuItem viewAllDebugViews
1457 viewMenu, $"All Debug Views", a, alt9;
1458 bool NotifySelect(MenuItem selection, Modifiers mods)
1463 callStackView.Show();
1464 breakpointsView.Show();
1468 #ifdef GDB_DEBUG_GUI
1469 MenuDivider { viewMenu };
1470 MenuItem viewGDBItem
1472 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1473 bool NotifySelect(MenuItem selection, Modifiers mods)
1480 MenuDivider { viewMenu };
1481 MenuItem viewColorPicker
1483 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1484 bool NotifySelect(MenuItem selection, Modifiers mods)
1486 ColorPicker colorPicker { master = this };
1487 colorPicker.Modal();
1491 MenuDivider { viewMenu };
1495 viewMenu, "Full Screen", f, checkable = true;
1497 bool NotifySelect(MenuItem selection, Modifiers mods)
1499 app.fullScreen ^= true;
1501 anchor = { 0, 0, 0, 0 };
1506 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1508 MenuDivider { viewMenu };
1510 Menu languageMenu { viewMenu, "Language", l };
1512 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1513 Menu windowMenu { menu, $"Window", w };
1514 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1515 MenuDivider { windowMenu };
1516 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1517 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1518 MenuDivider { windowMenu };
1519 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1520 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1521 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1522 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1523 MenuDivider { windowMenu };
1524 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1525 Menu helpMenu { menu, $"Help", h };
1528 helpMenu, $"API Reference", r, f1;
1529 bool NotifySelect(MenuItem selection, Modifiers mods)
1533 char * p = new char[MAX_LOCATION];
1535 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1536 PathCat(p, "documentor");
1537 #if defined(__WIN32__)
1538 ChangeExtension(p, "exe", p);
1540 if(!FileExists(p).isFile)
1541 strcpy(p, "documentor");
1543 documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
1548 Process_ShowWindows(documentor.GetProcessID());
1549 // documentor.Puts("Activate\n");
1554 MenuDivider { helpMenu };
1557 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1558 bool NotifySelect(MenuItem selection, Modifiers mods)
1560 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1564 MenuDivider { helpMenu };
1567 helpMenu, $"Documentation Folder", d;
1568 bool NotifySelect(MenuItem selection, Modifiers mods)
1570 FindAndShellOpenInstalledFolder("doc");
1576 helpMenu, $"Samples Folder", s;
1577 bool NotifySelect(MenuItem selection, Modifiers mods)
1579 FindAndShellOpenInstalledFolder("samples");
1585 helpMenu, $"Extras Folder", x;
1586 bool NotifySelect(MenuItem selection, Modifiers mods)
1588 FindAndShellOpenInstalledFolder("extras");
1592 MenuDivider { helpMenu };
1595 helpMenu, $"Community Forums", f;
1596 bool NotifySelect(MenuItem selection, Modifiers mods)
1598 ShellOpen("http://ecere.com/forums");
1602 MenuDivider { helpMenu };
1605 helpMenu, $"About...", a;
1606 bool NotifySelect(MenuItem selection, Modifiers mods)
1608 AboutIDE { master = this }.Modal();
1613 property ToolBox toolBox
1615 get { return toolBox; }
1618 property Sheet sheet
1620 get { return sheet; }
1623 property Project project
1625 get { return projectView ? projectView.project : null; }
1628 property Workspace workspace
1630 get { return projectView ? projectView.workspace : null; }
1633 FindInFilesDialog findInFilesDialog
1636 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1643 #ifdef GDB_DEBUG_GUI
1646 master = this, parent = this;
1647 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1649 void OnCommand(const char * string)
1652 ide.debugger.SendGDBCommand(string);
1657 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1659 //app.driver = app.drivers[selection.id];
1660 #if defined(__unix__) || defined(__APPLE__)
1661 app.driver = selection.id ? "OpenGL" : "X";
1663 app.driver = selection.id ? "OpenGL" : "GDI";
1665 delete ideSettings.displayDriver;
1666 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1668 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1670 settingsContainer.Save();
1671 //SetDriverAndSkin();
1675 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1677 app.skin = app.skins[selection.id];
1682 void SetDriverAndSkin()
1685 for(c = 0; c < app.numSkins; c++)
1686 if(!strcmp(app.skins[c], app.skin))
1688 skinItems[c].checked = true;
1691 for(c = 0; c < app.numDrivers; c++)
1692 if(!strcmp(app.drivers[c], app.driver))
1694 driverItems[c].checked = true;
1699 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1701 Project project = workspace.projects.firstIterator.data;
1702 projectView = ProjectView
1705 fileName = fileName;
1707 void NotifyDestroyed(Window window, DialogResult result)
1710 text = titleECEREIDE;
1715 projectView.Create();
1716 RepositionWindows(false);
1718 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1719 projectView.workspace = workspace;
1720 projectView.project = project;
1721 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1725 ide.breakpointsView.LoadFromWorkspace();
1726 ide.watchesView.LoadFromWorkspace();
1728 findInFilesDialog.projectNodeField.userData = projectView;
1731 char fileName[MAX_LOCATION];
1732 strcpy(fileName, project.topNode.path);
1733 PathCat(fileName, project.topNode.name);
1740 projectView.visible = false;
1741 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1743 if(findInFilesDialog)
1745 char workingDir[MAX_LOCATION];
1746 GetWorkingDir(workingDir, MAX_LOCATION);
1747 findInFilesDialog.SearchStop();
1748 findInFilesDialog.currentDirectory = workingDir;
1750 sheet.visible = false;
1751 toolBox.visible = false;
1752 outputView.visible = false;
1753 ideMainFrame.text = titleECEREIDE;
1760 void RepositionWindows(bool expand)
1765 bool callStackVisible = expand ? false : callStackView.visible;
1766 bool threadsVisible = expand ? false : threadsView.visible;
1767 bool watchesVisible = expand ? false : watchesView.visible;
1768 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1769 bool toolBoxVisible = toolBox.visible;
1770 bool outputVisible = expand ? false : outputView.visible;
1771 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1772 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1774 for(child = firstChild; child; child = child.next)
1776 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1777 child._class == class(Sheet) || child._class == class(ProjectView))
1779 Anchor anchor = child.anchor;
1780 anchor.top = topDistance;
1781 anchor.bottom = bottomDistance;
1782 if(child._class == class(CodeEditor) || child._class == class(Designer))
1784 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1785 anchor.right = toolBoxVisible ? 150 : 0;
1788 child.anchor = anchor;
1792 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1793 child._class == class(BreakpointsView))
1794 child.visible = false;
1797 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1799 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1803 bool ShowCodeEditor()
1806 activeClient.Activate();
1807 else if(projectView)
1809 projectView.visible = true;
1810 projectView.Activate();
1812 else if(sheet.visible)
1815 outputView.visible = false;
1819 void DocumentSaved(Window document, const char * fileName)
1821 ideSettings.AddRecentFile(fileName);
1822 ide.UpdateRecentMenus();
1823 ide.AdjustFileMenus();
1824 settingsContainer.Save();
1827 bool Window::OnFileModified(FileChange fileChange, const char * param)
1830 sprintf(temp, $"The document %s was modified by another application.\n"
1831 "Would you like to reload it and lose your changes?", this.fileName);
1832 if(MessageBox { type = yesNo, master = this/*.parent*/,
1833 text = $"Document has been modified", contents = temp }.Modal() == yes)
1835 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1836 char * fileName = CopyString(this.fileName);
1837 WindowState state = this.state;
1838 Anchor anchor = this.anchor;
1839 Size size = this.size;
1841 this.modifiedDocument = false;
1843 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1846 this.anchor = anchor;
1848 this.SetState(state, true, 0);
1856 void UpdateMakefiles()
1860 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1861 for(prj : workspace.projects)
1862 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1867 void UpdateCompilerConfigs(bool mute)
1869 UpdateToolBarActiveCompilers();
1872 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1873 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1876 projectView.ShowOutputBuildLog(true);
1877 projectView.DisplayCompiler(compiler, false);
1879 for(prj : workspace.projects)
1880 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1885 void UpdateToolBarActiveCompilers()
1887 toolBar.activeCompiler.Clear();
1888 for(compiler : ideSettings.compilerConfigs)
1890 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1891 if(workspace && workspace.compiler && !strcmp(compiler.name, workspace.compiler))
1892 toolBar.activeCompiler.currentRow = row;
1894 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1895 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1896 toolBar.activeBitDepth.SelectRow(toolBar.activeBitDepth.FindRow(workspace ? workspace.bitDepth : 0));
1899 void UpdateToolBarActiveConfigs(bool selectionOnly)
1901 bool commonSelected = false;
1902 DataRow row = toolBar.activeConfig.currentRow;
1904 row = toolBar.activeConfig.FindRow(1);
1907 toolBar.activeConfig.Clear();
1908 row = toolBar.activeConfig.AddString($"(Mixed)");
1913 char * configName = null;
1916 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1917 for(prj : workspace.projects)
1919 for(cfg : prj.configurations)
1922 configs[cfg.name] = 1;
1927 toolBar.activeConfig.AddString(&name);
1931 if(projectView && projectView.project)
1933 for(prj : workspace.projects)
1935 if(prj.config && prj.config.name)
1937 configName = prj.config.name;
1943 commonSelected = true;
1944 for(prj : workspace.projects)
1946 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1948 commonSelected = false;
1956 commonSelected = false;
1957 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1959 if(!strcmp(row.string, configName))
1961 toolBar.activeConfig.currentRow = row;
1962 commonSelected = true;
1969 toolBar.activeConfig.Sort(null, 0);
1971 toolBar.activeConfig.currentRow = row;
1976 bool unavailable = !project;
1978 projectAddItem.disabled = unavailable;
1979 toolBar.buttonAddProject.disabled = unavailable;
1981 projectSettingsItem.disabled = unavailable;
1983 projectBrowseFolderItem.disabled = unavailable;
1985 viewProjectItem.disabled = unavailable;
1987 toolBar.activeConfig.disabled = unavailable;
1988 toolBar.activeCompiler.disabled = unavailable;
1989 toolBar.activeBitDepth.disabled = unavailable;
1992 debugUseValgrindItem.disabled = unavailable;
1993 AdjustValgrindMenus();
2002 void AdjustValgrindMenus()
2004 bool unavailable = !project || !debugUseValgrindItem.checked;
2005 debugValgrindNoLeakCheckItem.disabled = unavailable;
2006 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2007 debugValgrindYesLeakCheckItem.disabled = unavailable;
2008 debugValgrindFullLeakCheckItem.disabled = unavailable;
2010 debugValgrindTrackOriginsItem.disabled = unavailable;
2012 debugValgrindRSDefaultItem.disabled = unavailable;
2013 debugValgrindRS0Item.disabled = unavailable;
2014 debugValgrindRS16Item.disabled = unavailable;
2015 debugValgrindRS32Item.disabled = unavailable;
2016 debugValgrindRS64Item.disabled = unavailable;
2017 debugValgrindRS128Item.disabled = unavailable;
2018 debugValgrindRS256Item.disabled = unavailable;
2019 debugValgrindRS512Item.disabled = unavailable;
2023 property bool hasOpenedCodeEditors
2028 for(w = firstChild; w; w = w.next)
2029 if(w._class == class(CodeEditor) &&
2030 w.isDocument && !w.closing && w.visible && w.created &&
2031 w.fileName && w.fileName[0])
2037 void AdjustFileMenus()
2039 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2041 projectQuickItem.disabled = unavailable;
2044 void AdjustBuildMenus()
2046 bool unavailable = project && projectView.buildInProgress;
2047 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2049 projectNewItem.disabled = unavailable;
2050 toolBar.buttonNewProject.disabled = unavailable;
2051 projectOpenItem.disabled = unavailable;
2052 toolBar.buttonOpenProject.disabled = unavailable;
2054 unavailable = !project || projectView.buildInProgress;
2056 projectCloseItem.disabled = unavailable;
2057 // toolBar.buttonCloseProject.disabled = unavailable;
2059 projectRunItem.disabled = naForRun;
2060 toolBar.buttonRun.disabled = naForRun;
2062 projectBuildItem.disabled = false;
2063 projectBuildItem.text = unavailable ? $"Stop Build" : $"Build";
2064 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2066 projectLinkItem.disabled = unavailable;
2067 toolBar.buttonReLink.disabled = unavailable;
2068 projectRebuildItem.disabled = unavailable;
2069 toolBar.buttonRebuild.disabled = unavailable;
2070 projectCleanItem.disabled = unavailable;
2071 toolBar.buttonClean.disabled = unavailable;
2072 projectCleanTargetItem.disabled = unavailable;
2073 projectRealCleanItem.disabled = unavailable;
2074 // toolBar.buttonRealClean.disabled = unavailable;
2075 projectRegenerateItem.disabled = unavailable;
2076 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2077 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2078 projectInstallItem.disabled = unavailable;
2079 toolBar.buttonInstall.disabled = unavailable;
2081 projectCompileItem.disabled = unavailable;
2083 AdjustPopupBuildMenus();
2086 void AdjustPopupBuildMenus()
2088 bool unavailable = !project || projectView.buildInProgress;
2090 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2093 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
2096 menu.disabled = false;
2097 menu.text = unavailable ? $"Stop Build" : $"Build";
2098 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2101 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0); if(menu) menu.disabled = unavailable;
2102 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0); if(menu) menu.disabled = unavailable;
2103 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0); if(menu) menu.disabled = unavailable;
2104 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0); if(menu) menu.disabled = unavailable;
2105 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0); if(menu) menu.disabled = unavailable;
2106 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
2107 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, 0); if(menu) menu.disabled = unavailable;
2108 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0); if(menu) menu.disabled = unavailable;
2109 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0); if(menu) menu.disabled = unavailable;
2110 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0); if(menu) menu.disabled = unavailable;
2111 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0); if(menu) menu.disabled = unavailable;
2112 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0); if(menu) menu.disabled = unavailable;
2113 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
2114 projectView.popupMenu.Update(null);
2118 property bool areDebugMenusUnavailable { get {
2120 project.GetTargetType(project.config) != executable ||
2121 projectView.buildInProgress == buildingMainProject;
2124 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2125 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2126 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2128 void AdjustDebugMenus()
2130 bool unavailable = areDebugMenusUnavailable;
2131 bool running = isDebuggerRunning;
2132 bool stopped = isDebuggerStopped;
2133 bool active = debugger.isActive;
2135 bool isNotRunning = unavailable || !running;
2136 bool isNotNotRunning = unavailable || running;
2137 bool isNotStopped = unavailable || !stopped;
2138 bool isNotActive = unavailable || !active;
2140 debugStartResumeItem.disabled = isNotNotRunning;
2141 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2142 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2145 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2146 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2149 debugBreakItem.disabled = isNotRunning;
2150 debugStopItem.disabled = isNotActive;
2151 debugRestartItem.disabled = isNotActive;
2154 toolBar.buttonDebugPause.disabled = isNotRunning;
2155 toolBar.buttonDebugStop.disabled = isNotActive;
2156 toolBar.buttonDebugRestart.disabled = isNotActive;
2159 debugStepIntoItem.disabled = isNotNotRunning;
2160 debugStepOverItem.disabled = isNotNotRunning;
2161 debugSkipStepOverItem.disabled = isNotNotRunning;
2162 debugStepOutItem.disabled = isNotStopped;
2163 debugSkipStepOutItem.disabled = isNotStopped;
2165 debugStepUntilItem.disabled = isNotStopped;
2166 debugSkipStepUntilItem.disabled = isNotStopped;
2170 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2171 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2172 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2173 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2174 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2176 if((Designer)GetActiveDesigner())
2178 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2180 codeEditor.AdjustDebugMenus();
2184 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2186 char tempString[MAX_LOCATION];
2187 strcpy(tempString, directory);
2188 if(saveSettings && !projectView)
2190 ideSettings.ideFileDialogLocation = directory;
2191 settingsContainer.Save();
2194 ideFileDialog.currentDirectory = tempString;
2195 codeEditorFileDialog.currentDirectory = tempString;
2196 codeEditorFormFileDialog.currentDirectory = tempString;
2199 void ChangeProjectFileDialogDirectory(char * directory)
2201 ideSettings.ideProjectFileDialogLocation = directory;
2202 settingsContainer.Save();
2205 Window FindWindow(const char * filePath)
2207 Window document = null;
2209 // TOCHECK: Do we need to change slashes here?
2210 for(document = firstChild; document; document = document.next)
2212 const char * fileName = document.fileName;
2213 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2215 document.visible = true;
2216 document.Activate();
2223 bool DontTerminateDebugSession(const char * title)
2225 if(debugger.isActive)
2227 if(MessageBox { type = yesNo, master = ide,
2228 contents = $"Do you want to terminate the debugging session in progress?",
2229 text = title }.Modal() == no)
2232 MessageBox msg { type = yesNo, master = ide,
2233 contents = "Do you want to terminate the debugging session in progress?",
2235 if(msg.Modal() == no)
2247 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2249 char extension[MAX_EXTENSION] = "";
2250 Window document = null;
2251 bool isProject = false;
2252 bool needFileModified = true;
2253 char winFilePath[MAX_LOCATION];
2254 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2255 Window currentDoc = activeClient;
2256 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2259 GetExtension(filePath, extension);
2263 strcpy(extension, type);
2265 if(strcmp(extension, ProjectExtension))
2267 for(document = firstChild; document; document = document.next)
2269 const char * fileName = document.fileName;
2270 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2272 document.visible = true;
2274 document.Activate();
2280 if(createIfFails == whatever)
2282 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2284 needFileModified = false;
2285 if(openMethod == normal)
2287 if(DontTerminateDebugSession($"Open Project"))
2296 Workspace workspace = null;
2298 if(FileExists(filePath))
2300 if(!strcmp(extension, ProjectExtension))
2302 char workspaceFile[MAX_LOCATION];
2303 strcpy(workspaceFile, filePath);
2304 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2305 workspace = LoadWorkspace(workspaceFile, filePath);
2307 else if(!strcmp(extension, WorkspaceExtension))
2308 workspace = LoadWorkspace(filePath, null);
2315 CreateProjectView(workspace, filePath);
2316 document = projectView;
2318 toolBox.visible = true;
2319 sheet.visible = true;
2320 projectView.MakeActive();
2322 workspace.ParseLoadedBreakpoints();
2323 workspace.DropInvalidBreakpoints(null);
2326 ide.projectView.ShowOutputBuildLog(true);
2328 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2329 ide.projectView.DisplayCompiler(compiler, false);
2332 UpdateCompilerConfigs(false);
2335 char newWorkingDir[MAX_LOCATION];
2336 StripLastDirectory(filePath, newWorkingDir);
2337 ChangeFileDialogsDirectory(newWorkingDir, false);
2340 document.fileName = filePath;
2342 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2344 // this crashes on starting ide with epj file, solution please?
2345 // app.UpdateDisplay();
2347 workspace.holdTracking = true;
2348 for(ofi : workspace.openedFiles)
2350 if(ofi.state != closed)
2352 Window file = OpenFile(ofi.path, false, true, null, no, normal, noParsing);
2355 char fileName[MAX_LOCATION];
2357 GetLastDirectory(ofi.path, fileName);
2358 node = projectView.project.topNode.Find(fileName, true);
2360 node.EnsureVisible();
2364 ide.RepositionWindows(false);
2365 workspace.holdTracking = false;
2367 workspace.timer.Start();
2369 #if !defined(__WIN32__)
2370 // Valgrind Debug menu updates
2371 debugUseValgrindItem.checked = workspace.useValgrind;
2373 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2374 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2375 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2376 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2378 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2379 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2380 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2381 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2382 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2383 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2384 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2385 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2387 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2390 findInFilesDialog.mode = FindInFilesMode::project;
2391 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2394 char location[MAX_LOCATION];
2395 StripLastDirectory(ide.project.topNode.path, location);
2396 ChangeProjectFileDialogDirectory(location);
2403 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2405 ideProjectFileDialog.text = openProjectFileDialogTitle;
2406 if(ideProjectFileDialog.Modal() == cancel)
2408 filePath = ideProjectFileDialog.filePath;
2409 GetExtension(filePath, extension);
2420 else if(openMethod == add)
2425 char slashFilePath[MAX_LOCATION];
2426 GetSlashPathBuffer(slashFilePath, filePath);
2427 for(p : workspace.projects)
2429 if(!fstrcmp(p.filePath, slashFilePath))
2437 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2438 contents = $"This project is already present in workspace." }.Modal();
2442 prj = LoadProject(filePath, null);
2445 const char * activeConfigName = null;
2446 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2447 prj.StartMonitoring();
2448 workspace.projects.Add(prj);
2449 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2450 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2451 activeConfigName = toolBar.activeConfig.currentRow.string;
2452 if(activeConfigName)
2454 for(cfg : prj.configurations)
2456 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2464 projectView.AddNode(prj.topNode, null);
2465 workspace.modified = true;
2467 findInFilesDialog.AddProjectItem(prj);
2468 projectView.ShowOutputBuildLog(true);
2469 projectView.DisplayCompiler(compiler, false);
2470 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2474 char location[MAX_LOCATION];
2475 StripLastDirectory(prj.topNode.path, location);
2476 ChangeProjectFileDialogDirectory(location);
2479 // projectView is associated with the main project and not with the one just added but
2480 return projectView; // just to let the caller know something was opened
2488 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2489 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2490 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2492 if(FileExists(filePath))
2493 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2494 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2495 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2498 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2501 else if(!strcmp(extension, "3ds"))
2503 if(FileExists(filePath))
2504 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2505 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2506 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2510 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2513 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2514 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2515 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2516 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2517 !strcmp(extension, "js"))
2519 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2520 editor.updatingCode = true;
2521 if(editor.LoadFile(filePath))
2524 editor.visible = true;
2528 needFileModified = false;
2532 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2533 if(editor.LoadFile(filePath))
2536 editor.visible = true;
2540 needFileModified = false;
2543 if(document && (document._class == class(PictureEdit) ||
2544 document._class == class(ModelView)))
2549 document.fileName = filePath;
2550 if(workspace && !workspace.holdTracking)
2551 workspace.UpdateOpenedFileInfo(filePath, opened);
2555 if(!document && createIfFails != no)
2557 if(createIfFails != yes && !needFileModified &&
2558 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2559 createIfFails = yes;
2560 if(createIfFails == yes || createIfFails == whatever)
2562 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2564 document.fileName = filePath;
2570 if(projectView && document._class == class(CodeEditor) && workspace)
2572 int lineNumber, position;
2574 CodeEditor editor = (CodeEditor)document;
2575 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2576 editor.openedFileInfo.holdTracking = true;
2577 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2578 position = Max(editor.openedFileInfo.position - 1, 0);
2579 if(editor.editBox.GoToLineNum(lineNumber))
2580 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2581 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2582 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2583 editor.editBox.scroll = scroll;
2584 editor.openedFileInfo.holdTracking = false;
2587 if(needFileModified)
2588 document.OnFileModified = OnFileModified;
2589 document.NotifySaved = DocumentSaved;
2590 if(maximizeDoc && document.hasMaximize)
2591 document.state = maximized;
2594 ideSettings.AddRecentProject(document.fileName);
2596 ideSettings.AddRecentFile(document.fileName);
2597 ide.UpdateRecentMenus();
2598 ide.AdjustFileMenus();
2599 settingsContainer.Save();
2607 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2608 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2610 if(!parentClosing && ide.workspace)
2611 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2614 bool ModelView::ModelViewOnClose(bool parentClosing)
2616 if(!parentClosing && ide.workspace)
2617 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2620 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2622 if(!parentClosing && ide.workspace)
2623 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2628 void OnUnloadGraphics(Window window)
2630 display.ClearMaterials();
2631 display.ClearTextures();
2632 display.ClearMeshes();
2636 void UpdateStateLight(StatusField fld, bool on)
2638 fld.color = on ? lime : Color { 128,128,128 };
2639 fld.backColor = on ? dimGray : 0;
2643 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2645 UpdateStateLight(caps, app.GetKeyState(capsState));
2646 UpdateStateLight(num, app.GetKeyState(numState));
2650 bool OnKeyDown(Key key, unichar ch)
2654 case b: projectView.Update(null); break;
2655 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2656 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2661 bool OnKeyUp(Key key, unichar ch)
2665 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2666 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2671 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2674 projectView.GoToError(line, noParsing, objectFileExt);
2677 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2679 FileAttribs result { };
2680 FileAttribs fileAttribs;
2684 strcpy(selectedPath, prj.topNode.path);
2685 else if(dir && dir[0])
2686 strcpy(selectedPath, dir);
2688 selectedPath[0] = '\0';
2689 PathCat(selectedPath, filePath);
2691 if((fileAttribs = FileExists(selectedPath)).isFile)
2692 result = fileAttribs;
2696 for(p : workspace.projects)
2698 strcpy(selectedPath, p.topNode.path);
2699 PathCat(selectedPath, filePath);
2700 if((fileAttribs = FileExists(selectedPath)).isFile)
2703 result = fileAttribs;
2710 ProjectNode n = null;
2711 for(p : workspace.projects)
2713 if((n = p.topNode.Find(filePath, false)))
2715 n.GetFullFilePath(selectedPath);
2716 if((fileAttribs = FileExists(selectedPath)).isFile)
2719 result = fileAttribs;
2724 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2725 (fileAttribs = FileExists(selectedPath)).isFile)
2728 result = fileAttribs;
2736 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2739 const char *path = text;
2740 char *colon = strchr(text, ':');
2741 char filePath[MAX_LOCATION] = "";
2742 char completePath[MAX_LOCATION];
2743 int line = 0, col = 0;
2744 int len = strlen(text);
2746 FileAttribs fileAttribs;
2748 // support for valgrind output
2749 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2760 /*for(s=colon; *s; s++)
2769 //line = atoi(colon+1);
2771 // support for "Found n match(es) in "file/path";
2772 else if(path[len-1] == '\"' && strstr(path, $"Found %d match%s in \"%s\"%s\n\n"."Found") && strstr(path, $"match") && strstr(path, $"in") && (s = strstr(path, "\"")) && s != path+len-1)
2778 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2780 path = (colon - 1 > path) ? colon - 1 : path;
2781 colon = strstr(colon + 1, ":");
2783 if(*path == '*' && (s = strchr(path+1, '*')))
2785 while(isspace(*path)) path++;
2789 char * close = strchr(path, ')');
2793 strncpy(name, path+1, close - path - 1);
2794 name[close - path - 1] = '\0';
2795 for(p : ide.workspace.projects)
2797 if(!strcmp(p.name, name))
2807 prj = project ? project : (dir ? null : ide.project);
2810 strncpy(filePath, path, colon - path);
2811 filePath[colon - path] = '\0';
2812 line = atoi(colon + 1);
2813 colon = strstr(colon + 1, ":");
2815 col = atoi(colon + 1);
2817 else if(path - 1 >= text && *(path - 1) == '\"')
2819 colon = strchr(path, '\"');
2822 strncpy(filePath, path, colon - path);
2823 filePath[colon - path] = '\0';
2826 else if(path && !colon)
2828 strcpy(filePath, path);
2831 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2832 CodeLocationGoTo(completePath, fileAttribs, line, col);
2835 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2837 if(fileAttribs.isFile)
2839 char ext[MAX_EXTENSION];
2840 GetExtension(path, ext);
2842 if(binaryDocExt.Find(ext))
2844 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2845 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2847 char dirPath[MAX_LOCATION];
2848 StripLastDirectory(path, dirPath);
2853 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2854 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2856 EditBox editBox = codeEditor.editBox;
2857 editBox.GoToLineNum(line - 1);
2858 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2862 else if(fileAttribs.isDirectory)
2866 void OnRedraw(Surface surface)
2868 Bitmap bitmap = back.bitmap;
2870 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2873 void SheetSelected(SheetType sheetSelected)
2875 if(activeChild == sheet)
2877 if(sheetSelected == methods)
2879 viewPropertiesItem.accelerator = f4;
2880 viewPropertiesItem.parent = viewMenu;
2881 viewMethodsItem.parent = null;
2885 viewMethodsItem.accelerator = f4;
2886 viewMethodsItem.parent = viewMenu;
2887 viewPropertiesItem.parent = null;
2892 viewMethodsItem.parent = viewMenu;
2893 viewPropertiesItem.parent = viewMenu;
2894 if(sheetSelected == methods)
2896 viewMethodsItem.accelerator = f4;
2897 viewPropertiesItem.accelerator = 0;
2901 viewMethodsItem.accelerator = 0;
2902 viewPropertiesItem.accelerator = f4;
2907 void OnActivateClient(Window client, Window previous)
2909 //if(!client || client != previous)
2912 if(!client || client != previous)
2915 dataType = previous._class;
2916 if(previous && !strcmp(dataType.name, "CodeEditor"))
2918 ((CodeEditor)previous).UpdateFormCode();
2920 else if(previous && !strcmp(dataType.name, "Designer"))
2922 ((Designer)previous).codeEditor.UpdateFormCode();
2927 dataType = client._class;
2928 if(client && !strcmp(dataType.name, "CodeEditor"))
2930 CodeEditor codeEditor = (CodeEditor)client;
2931 SetPrivateModule(codeEditor.privateModule);
2932 SetCurrentContext(codeEditor.globalContext);
2933 SetTopContext(codeEditor.globalContext);
2934 SetGlobalContext(codeEditor.globalContext);
2936 SetDefines(&codeEditor.defines);
2937 SetImports(&codeEditor.imports);
2939 SetActiveDesigner(codeEditor.designer);
2941 sheet.codeEditor = codeEditor;
2942 toolBox.codeEditor = codeEditor;
2944 viewDesignerItem.parent = viewMenu;
2945 if(activeChild != codeEditor)
2947 viewCodeItem.parent = viewMenu;
2948 viewDesignerItem.accelerator = 0;
2949 viewCodeItem.accelerator = f8;
2953 viewCodeItem.parent = null;
2954 viewDesignerItem.accelerator = f8;
2957 else if(client && !strcmp(dataType.name, "Designer"))
2959 CodeEditor codeEditor = ((Designer)client).codeEditor;
2962 SetPrivateModule(codeEditor.privateModule);
2963 SetCurrentContext(codeEditor.globalContext);
2964 SetTopContext(codeEditor.globalContext);
2965 SetGlobalContext(codeEditor.globalContext);
2966 SetDefines(&codeEditor.defines);
2967 SetImports(&codeEditor.imports);
2971 SetPrivateModule(null);
2972 SetCurrentContext(null);
2973 SetTopContext(null);
2974 SetGlobalContext(null);
2979 SetActiveDesigner((Designer)client);
2981 sheet.codeEditor = codeEditor;
2982 toolBox.codeEditor = codeEditor;
2984 viewCodeItem.parent = viewMenu;
2985 if(activeChild != client)
2987 viewDesignerItem.parent = viewMenu;
2988 viewDesignerItem.accelerator = f8;
2989 viewCodeItem.accelerator = 0;
2993 viewDesignerItem.parent = null;
2994 viewCodeItem.accelerator = f8;
2999 if(!client && !projectView && sheet.visible)
3002 sheet.visible = false;
3003 toolBox.visible = false;
3006 sheet.codeEditor = null;
3007 toolBox.codeEditor = null;
3008 SetActiveDesigner(null);
3010 viewDesignerItem.parent = null;
3011 viewCodeItem.parent = null;
3014 SheetSelected(sheet.sheetSelected);
3017 projectCompileItem = null;
3022 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3024 CodeEditor codeEditor = (CodeEditor)client;
3025 EditBox editBox = codeEditor.editBox;
3027 statusBar.AddField(pos);
3029 caps = { width = 40, text = $"CAPS" };
3030 statusBar.AddField(caps);
3031 UpdateStateLight(caps, app.GetKeyState(capsState));
3033 ovr = { width = 36, text = $"OVR" };
3034 statusBar.AddField(ovr);
3035 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3037 num = { width = 36, text = $"NUM" };
3038 statusBar.AddField(num);
3039 UpdateStateLight(num, app.GetKeyState(numState));
3041 //statusBar.text = "Ready";
3043 if(projectView && projectView.project)
3045 bool isCObject = false;
3046 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3047 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3051 char nodeName[MAX_FILENAME];
3052 char name[MAX_FILENAME+96];
3054 ChangeExtension(node.name, "c", nodeName);
3055 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3056 projectCompileItem =
3058 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3060 bool NotifySelect(MenuItem selection, Modifiers mods)
3064 bool isCObject = false;
3065 bool isExcluded = false;
3066 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3070 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3073 List<ProjectNode> nodes { };
3075 projectView.Compile(node.project, nodes, mods.ctrl && mods.shift, isCObject ? cObject : normal);
3083 projectMenu.AddDynamic(projectCompileItem, ide, false);
3089 caps = ovr = num = null;
3094 bool OnClose(bool parentClosing)
3096 //return !projectView.buildInProgress;
3097 if(projectView && projectView.buildInProgress)
3099 if(DontTerminateDebugSession($"Close IDE"))
3101 if(findInFilesDialog)
3102 findInFilesDialog.SearchStop();
3105 workspace.timer.Stop();
3108 ideMainFrame.Destroy(0);
3115 bool passThrough = false;
3116 bool debugWorkDir = false;
3117 char * passDebugWorkDir = null;
3118 bool openAsText = false;
3119 DynamicString passArgs { };
3122 for(c = 1; c<app.argc; c++)
3126 const char * arg = app.argv[c];
3127 char * buf = new char[strlen(arg)*2+1];
3129 passArgs.concat(" ");
3131 passArgs.concat(buf);
3134 else if(debugWorkDir)
3136 passDebugWorkDir = CopyString(app.argv[c]);
3137 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3138 debugWorkDir = false;
3140 else if(!strcmp(app.argv[c], "-t"))
3142 else if(!strcmp(app.argv[c], "-no-parsing"))
3143 ide.noParsing = true;
3144 else if(!strcmp(app.argv[c], "-debug-start"))
3145 ide.debugStart = true;
3146 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3147 debugWorkDir = true;
3148 else if(!strcmp(app.argv[c], "-@"))
3152 char fullPath[MAX_LOCATION];
3153 char parentPath[MAX_LOCATION];
3154 char ext[MAX_EXTENSION];
3156 FileAttribs dirAttribs;
3157 GetWorkingDir(fullPath, MAX_LOCATION);
3158 PathCat(fullPath, app.argv[c]);
3159 StripLastDirectory(fullPath, parentPath);
3160 GetExtension(app.argv[c], ext);
3161 isProject = !openAsText && !strcmpi(ext, "epj");
3163 if(isProject && c > 1 + (ide.debugStart ? 1 : 0)) continue;
3165 // Create directory for projects (only)
3166 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3168 if(isProject && !FileExists(fullPath))
3170 char name[MAX_LOCATION];
3171 NewProjectDialog newProjectDialog;
3175 projectView.visible = false;
3176 if(!projectView.Destroy(0))
3180 newProjectDialog = { master = this };
3182 strcpy(name, app.argv[c]);
3183 StripExtension(name);
3184 GetLastDirectory(name, name);
3185 newProjectDialog.projectName.contents = name;
3186 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3187 newProjectDialog.locationEditBox.path = parentPath;
3188 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3190 incref newProjectDialog;
3191 newProjectDialog.Modal();
3194 ideSettings.AddRecentProject(projectView.fileName);
3195 ide.UpdateRecentMenus();
3196 settingsContainer.Save();
3198 delete newProjectDialog;
3199 // Open only one project
3203 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3205 else if(strstr(fullPath, "http://") == fullPath)
3206 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3209 if(passThrough && projectView && projectView.project && workspace)
3210 workspace.commandLineArgs = passArgs;
3211 if(passDebugWorkDir && projectView && projectView.project && workspace)
3213 workspace.debugDir = passDebugWorkDir;
3214 delete passDebugWorkDir;
3217 UpdateToolBarActiveConfigs(false);
3218 UpdateToolBarActiveCompilers();
3225 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3228 projectView.visible = false;
3229 projectView.Destroy(0);
3232 #ifdef GDB_DEBUG_GUI
3233 gdbDialog.Destroy(0);
3238 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3242 char * oldPaths[128];
3243 String oldList = new char[maxPathLen];
3244 Array<String> newExePaths { };
3245 //Map<String, bool> exePathExists { };
3247 #if defined(__unix__) || defined(__APPLE__)
3248 Array<String> newLibPaths { };
3249 Map<String, bool> libPathExists { };
3254 for(prj : workspace.projects)
3256 DirExpression targetDirExp;
3258 // SKIP FIRST PROJECT...
3259 if(prj == workspace.projects.firstIterator.data) continue;
3261 // NOTE: Right now the additional project config dir will be
3262 // obtained when the debugger is started, so toggling it
3263 // while building will change which library gets used.
3264 // To go with the initial state, e.g. when F5 was pressed,
3265 // we nould need to keep a list of all project's active
3266 // config upon startup.
3267 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3269 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3273 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3274 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3278 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3279 if(cfg.targetType == sharedLibrary && cfg.debug)
3283 if(targetDirExp.dir)
3285 char buffer[MAX_LOCATION];
3286 #if defined(__WIN32__)
3287 Array<String> paths = newExePaths;
3289 Array<String> paths = newLibPaths;
3291 GetSystemPathBuffer(buffer, prj.topNode.path);
3292 PathCat(buffer, targetDirExp.dir);
3295 if(!fstrcmp(p, buffer))
3302 paths.Add(CopyString(buffer));
3304 delete targetDirExp;
3308 for(item : compiler.executableDirs)
3310 DirExpression dirExpr { };
3311 dirExpr.Evaluate(item, null, compiler, null, 0);
3314 for(p : newExePaths)
3316 if(!fstrcmp(p, dirExpr.dir))
3323 newExePaths.Add(CopySystemPath(dirExpr.dir));
3327 GetEnvironment("PATH", oldList, maxPathLen);
3329 printf("Old value of PATH: %s\n", oldList);
3331 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3332 for(c = 0; c < count; c++)
3335 for(p : newExePaths)
3337 if(!fstrcmp(p, oldPaths[c]))
3344 newExePaths.Add(CopySystemPath(oldPaths[c]));
3348 for(path : newExePaths)
3349 len += strlen(path) + 1;
3350 newList = new char[len + 1];
3352 for(path : newExePaths)
3354 strcat(newList, path);
3355 strcat(newList, pathListSep);
3357 newList[len - 1] = '\0';
3358 SetEnvironment("PATH", newList);
3360 printf("New value of PATH: %s\n", newList);
3367 #if defined(__unix__) || defined(__APPLE__)
3369 for(item : compiler.libraryDirs)
3371 if(!libPathExists[item]) // fstrcmp should be used
3373 String s = CopyString(item);
3375 libPathExists[s] = true;
3379 #if defined(__APPLE__)
3380 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3382 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3385 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3387 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3388 for(c = 0; c < count; c++)
3390 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3392 String s = CopyString(oldPaths[c]);
3394 libPathExists[s] = true;
3399 for(path : newLibPaths)
3400 len += strlen(path) + 1;
3401 newList = new char[len + 1];
3403 for(path : newLibPaths)
3405 strcat(newList, path);
3406 strcat(newList, pathListSep);
3408 newList[len - 1] = '\0';
3409 #if defined(__APPLE__)
3410 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3412 SetEnvironment("LD_LIBRARY_PATH", newList);
3415 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3421 delete libPathExists;
3424 if(compiler.distccEnabled && compiler.distccHosts)
3425 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3430 void DestroyTemporaryProjectDir()
3432 if(tmpPrjDir && tmpPrjDir[0])
3434 if(FileExists(tmpPrjDir).isDirectory)
3435 DestroyDir(tmpPrjDir);
3436 property::tmpPrjDir = null;
3442 // Graphics Driver Menu
3445 app.currentSkin.selectionColor = selectionColor;
3446 app.currentSkin.selectionText = selectionText;
3450 driverItems = new MenuItem[app.numDrivers];
3451 for(c = 0; c < app.numDrivers; c++)
3453 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3454 driverItems[c].id = c;
3455 driverItems[c].isRadio = true;
3458 driverItems = new MenuItem[2];
3459 #if defined(__unix__)
3460 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3461 driverItems[0].id = 0;
3462 driverItems[0].isRadio = true;
3464 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3465 driverItems[0].id = 0;
3466 driverItems[0].isRadio = true;
3468 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3469 driverItems[1].id = 1;
3470 driverItems[1].isRadio = true;
3472 /* skinItems = new MenuItem[app.numSkins];
3473 for(c = 0; c < app.numSkins; c++)
3475 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3476 skinItems[c].id = c;
3477 skinItems[c].isRadio = true;
3480 ideFileDialog.master = this;
3481 ideProjectFileDialog.master = this;
3483 //SetDriverAndSkin();
3487 void UpdateRecentMenus()
3490 Menu fileMenu = menu.FindMenu($"File");
3491 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3492 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3493 char * itemPath = new char[MAX_LOCATION];
3494 char * itemName = new char[MAX_LOCATION+4];
3496 recentFiles.Clear();
3499 for(recent : ideSettings.recentFiles)
3501 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3502 MakeSystemPath(itemPath);
3503 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3504 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3508 recentProjects.Clear();
3510 for(recent : ideSettings.recentProjects)
3512 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3513 MakeSystemPath(itemPath);
3514 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3515 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3527 delete languageItems;
3531 documentor.Puts("Quit\n");
3538 void DestroyDir(char * path)
3540 RecursiveDeleteFolderFSI fsi { };
3545 #if defined(__WIN32__)
3546 define sdkDirName = "Ecere SDK";
3548 define sdkDirName = "ecere";
3551 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3554 char * v = new char[maxPathLen];
3558 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3559 StripLastDirectory(path, path);
3560 PathCat(path, subDir);
3561 if(name) PathCat(path, name);
3562 if(FileExists(path) & attribs) found = true;
3564 #if defined(__WIN32__)
3567 GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3570 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3571 PathCat(path, subDir);
3572 if(name) PathCat(path, name);
3573 if(FileExists(path) & attribs) found = true;
3578 GetEnvironment("AppData", v, maxPathLen);
3581 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3582 PathCat(path, sdkDirName);
3583 PathCat(path, subDir);
3584 if(name) PathCat(path, name);
3585 if(FileExists(path) & attribs) found = true;
3590 GetEnvironment("ProgramData", v, maxPathLen);
3593 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3594 PathCat(path, sdkDirName);
3595 PathCat(path, subDir);
3596 if(name) PathCat(path, name);
3597 if(FileExists(path) & attribs) found = true;
3602 GetEnvironment("ProgramFiles", v, maxPathLen);
3605 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3606 PathCat(path, sdkDirName);
3607 PathCat(path, subDir);
3608 if(name) PathCat(path, name);
3609 if(FileExists(path) & attribs) found = true;
3614 GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3617 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3618 PathCat(path, sdkDirName);
3619 PathCat(path, subDir);
3620 if(name) PathCat(path, name);
3621 if(FileExists(path) & attribs) found = true;
3626 GetEnvironment("SystemDrive", v, maxPathLen);
3629 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3630 PathCat(path, "Program Files");
3631 PathCat(path, sdkDirName);
3632 PathCat(path, subDir);
3633 if(name) PathCat(path, name);
3634 if(FileExists(path) & attribs) found = true;
3644 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3645 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3648 p = new char[MAX_LOCATION];
3650 strcat(p, "/usr/share");
3654 for(c=0; c<numTokens; c++)
3656 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3657 PathCat(path, sdkDirName);
3658 PathCat(path, subDir);
3660 PathCat(path, name);
3661 if(FileExists(path) & attribs)
3674 void FindAndShellOpenInstalledFolder(const char * name)
3676 char path[MAX_LOCATION];
3677 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3681 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3683 char path[MAX_LOCATION];
3684 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3688 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3690 bool preserveRootFolder;
3692 void OutFolder(const char * folderPath, bool isRoot)
3694 if(!(preserveRootFolder && isRoot))
3695 RemoveDir(folderPath);
3698 bool OnFile(const char * filePath)
3700 DeleteFile(filePath);
3705 class IDEApp : GuiApplication
3707 //driver = "Win32Console";
3708 // driver = "OpenGL";
3712 TempFile includeFile { };
3717 char ext[MAX_EXTENSION];
3718 SetLoggingMode(stdOut, null);
3719 //SetLoggingMode(debug, null);
3721 settingsContainer.Load();
3723 if(ideSettings.language)
3725 const String language = GetLanguageString();
3726 if(ideSettings.language.OnCompare(language))
3728 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3733 // First count files arg to decide whether to maximize
3735 bool passThrough = false, debugWorkDir = false;
3738 for(c = 1; c<app.argc; c++)
3741 else if(debugWorkDir)
3742 debugWorkDir = false;
3743 else if(!strcmp(app.argv[c], "-t"));
3744 else if(!strcmp(app.argv[c], "-no-parsing"));
3745 else if(!strcmp(app.argv[c], "-debug-start"));
3746 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3747 debugWorkDir = true;
3748 else if(!strcmp(app.argv[c], "-@"))
3755 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3757 app.driver = "OpenGL";
3758 ide.driverItems[1].checked = true;
3762 #if defined(__unix__) || defined(__APPLE__)
3763 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3765 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3767 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3771 char model[MAX_LOCATION];
3772 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3774 ide.duck.modelFile = model;
3775 ide.duck.parent = ideMainFrame;
3778 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3779 ide.debugRubberDuck.disabled = false;
3783 desktop.caption = titleECEREIDE;
3786 for(c = 1; c<app.argc; c++)
3788 char fullPath[MAX_LOCATION];
3789 GetWorkingDir(fullPath, MAX_LOCATION);
3790 PathCat(fullPath, app.argv[c]);
3791 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3795 // Default to language specified by environment if no language selected
3796 if(!ideSettings.language)
3798 ideSettings.language = GetLanguageString();
3799 settingsContainer.Save();
3802 // Default to home directory if no directory yet set up
3803 if(!ideSettings.ideProjectFileDialogLocation[0])
3806 char location[MAX_LOCATION];
3807 char * home = getenv("HOME");
3808 char * homeDrive = getenv("HOMEDRIVE");
3809 char * homePath = getenv("HOMEPATH");
3810 char * userProfile = getenv("USERPROFILE");
3811 char * systemDrive = getenv("SystemDrive");
3812 if(home && FileExists(home).isDirectory)
3814 strcpy(location, home);
3817 if(!found && homeDrive && homePath)
3819 strcpy(location, homeDrive);
3820 PathCat(location, homePath);
3821 if(FileExists(location).isDirectory)
3824 if(!found && FileExists(userProfile).isDirectory)
3826 strcpy(location, userProfile);
3829 if(!found && FileExists(systemDrive).isDirectory)
3831 strcpy(location, systemDrive);
3836 ideSettings.ideProjectFileDialogLocation = location;
3837 if(!ideSettings.ideFileDialogLocation[0])
3838 ideSettings.ideFileDialogLocation = location;
3842 if(!LoadIncludeFile())
3843 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3845 // Create language menu
3847 String language = ideSettings.language;
3851 ide.languageItems = new MenuItem[languages.count];
3854 ide.languageItems[i] =
3856 ide.languageMenu, l.name;
3857 bitmap = { l.bitmap };
3861 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3863 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3865 // Re-select previous selected language if aborted
3866 String language = ideSettings.language;
3870 if(((!language || !language[0]) && i == 0) ||
3871 (language && !strcmpi(l.code, language)))
3873 ide.languageItems[i].checked = true;
3885 // Try to find country-specific language first
3891 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3893 ide.languageItems[i].checked = true;
3901 // Try generalizing locale
3902 if(!found && language)
3905 char genericLocale[256];
3907 strncpy(genericLocale, language, sizeof(genericLocale));
3908 genericLocale[sizeof(genericLocale)-1] = 0;
3910 under = strchr(genericLocale, '_');
3913 if(!strcmpi(genericLocale, "zh"))
3914 strcpy(genericLocale, "zh_CN");
3915 if(strcmp(genericLocale, language))
3919 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3921 ide.languageItems[i].checked = true;
3931 ide.languageItems[0].checked = true;
3933 MenuDivider { ide.languageMenu };
3936 ide.languageMenu, "Help Translate";
3938 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3940 ShellOpen("http://translations.launchpad.net/ecere");
3946 ideMainFrame.Create();
3947 if(app.argFilesCount > 1)
3948 ide.MenuWindowTileVert(null, 0);
3952 bool Cycle(bool idle)
3956 if(ide.documentor.Peek())
3959 ide.documentor.GetLine(line, sizeof(line));
3960 if(!strcmpi(line, "Exited"))
3962 ide.documentor.CloseInput();
3963 ide.documentor.CloseOutput();
3964 ide.documentor.Wait();
3965 delete ide.documentor;
3968 if(ide.documentor && ide.documentor.eof)
3970 ide.documentor.CloseInput();
3971 ide.documentor.CloseOutput();
3972 ide.documentor.Wait();
3973 delete ide.documentor;
3979 bool LoadIncludeFile()
3981 bool result = false;
3982 File include = FileOpen(":crossplatform.mk", read);
3985 File f = includeFile;
3988 for(; !include.Eof(); )
3991 int count = include.Read(buffer, 1, 4096);
3992 f.Write(buffer, 1, count);
4002 IDEMainFrame ideMainFrame { };
4004 define app = ((IDEApp)__thisModule);
4006 define titleECEREIDE = $"Ecere IDE (Debug)";
4008 define titleECEREIDE = $"Ecere IDE";