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.activeCompiler))
308 bool silent = ide.projectView.buildInProgress == none ? false : true;
309 CompilerConfig compiler = ideSettings.GetCompilerConfig(row.string);
310 ide.workspace.activeCompiler = 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.activeCompiler);
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.activeCompiler) : 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.activeCompiler) : 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.activeCompiler)
727 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.activeCompiler;
728 else if(ideSettings.defaultCompiler)
729 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
730 globalSettingsDialog.Modal();
734 MenuDivider { fileMenu };
735 Menu recentFiles { fileMenu, $"Recent Files", r };
736 Menu recentProjects { fileMenu, $"Recent Projects", p };
737 MenuDivider { fileMenu };
740 fileMenu, $"Exit", x, altF4;
742 bool NotifySelect(MenuItem selection, Modifiers mods)
744 ideMainFrame.Destroy(0);
749 bool FileRecentFile(MenuItem selection, Modifiers mods)
752 for(file : ideSettings.recentFiles)
754 if(id == selection.id)
757 char extension[MAX_EXTENSION] = "";
758 GetExtension(file, extension);
759 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
762 char * command = PrintString("ide ", isProjectFile ? "-t " : "", file);
768 OpenFile(file, false, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
769 ide.RepositionWindows(false);
778 bool FileRecentProject(MenuItem selection, Modifiers mods)
781 for(file : ideSettings.recentProjects)
783 if(id == selection.id)
787 char * command = PrintString("ide ", file);
792 OpenFile(file, false, true, null, no, normal, mods.ctrl && mods.shift);
800 MenuPlacement editMenu { menu, $"Edit", e };
802 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
803 MenuItem projectNewItem
805 projectMenu, $"New...", n, Key { n, true, true };
806 bitmap = { ":actions/projNew.png" };
807 bool NotifySelect(MenuItem selection, Modifiers mods)
809 if(!DontTerminateDebugSession($"New Project"))
812 NewProjectDialog newProjectDialog { master = this };
813 incref newProjectDialog;
814 result = newProjectDialog.Modal();
819 newProjectDialog.CreateNewProject();
822 ideSettings.AddRecentProject(projectView.fileName);
823 ide.UpdateRecentMenus();
824 settingsContainer.Save();
828 delete newProjectDialog;
833 MenuItem projectOpenItem
835 projectMenu, $"Open...", o, Key { o, true, true };
836 bitmap = { ":actions/projOpen.png" };
837 bool NotifySelect(MenuItem selection, Modifiers mods)
839 if(ideSettings.ideProjectFileDialogLocation)
840 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
842 ideProjectFileDialog.text = openProjectFileDialogTitle;
843 if(ideProjectFileDialog.Modal() == ok)
845 OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
846 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
851 MenuItem projectQuickItem
853 projectMenu, $"Quick...", q, f7, disabled = true;
854 bool NotifySelect(MenuItem selection, Modifiers mods)
857 QuickProjectDialog { this }.Modal();
861 MenuItem projectAddItem
863 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
864 bitmap = { ":actions/projAdd.png" };
866 bool NotifySelect(MenuItem selection, Modifiers mods)
868 if(ideSettings.ideProjectFileDialogLocation)
869 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
871 ideProjectFileDialog.text = addProjectFileDialogTitle;
874 if(ideProjectFileDialog.Modal() == ok)
876 if(OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
878 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
879 contents = $"Add a different project?" }.Modal() == no)
890 MenuItem projectCloseItem
892 projectMenu, $"Close", c, disabled = true;
893 bool NotifySelect(MenuItem selection, Modifiers mods)
897 if(!ide.DontTerminateDebugSession($"Project Close"))
903 MenuDivider { projectMenu };
904 MenuItem projectSettingsItem
906 projectMenu, $"Settings...", s, altF7, disabled = true;
907 bool NotifySelect(MenuItem selection, Modifiers mods)
909 projectView.MenuSettings(projectView.active ? selection : null, mods);
913 MenuDivider { projectMenu };
914 MenuItem projectBrowseFolderItem
916 projectMenu, $"Browse Project Folder", p, disabled = true;
917 bool NotifySelect(MenuItem selection, Modifiers mods)
920 projectView.MenuBrowseFolder(null, mods);
924 MenuDivider { projectMenu };
925 MenuItem projectRunItem
927 projectMenu, $"Run", r, ctrlF5, disabled = true;
928 bitmap = { ":actions/run.png" };
929 bool NotifySelect(MenuItem selection, Modifiers mods)
932 projectView.Run(null, mods);
936 MenuItem projectBuildItem
938 projectMenu, $"Build", b, f7, disabled = true;
939 bitmap = { ":actions/build.png" };
940 bool NotifySelect(MenuItem selection, Modifiers mods)
944 if(projectView.buildInProgress == none)
945 projectView.ProjectBuild(projectView.active ? selection : null, mods);
947 projectView.stopBuild = true;
952 MenuItem projectLinkItem
954 projectMenu, $"Relink", l, disabled = true;
955 bitmap = { ":actions/relink.png" };
956 bool NotifySelect(MenuItem selection, Modifiers mods)
959 projectView.ProjectLink(projectView.active ? selection : null, mods);
963 MenuItem projectRebuildItem
965 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
966 bitmap = { ":actions/rebuild.png" };
967 bool NotifySelect(MenuItem selection, Modifiers mods)
970 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
974 MenuItem projectCleanTargetItem
976 projectMenu, $"Clean Target", g, disabled = true;
977 bitmap = { ":actions/clean.png" };
978 bool NotifySelect(MenuItem selection, Modifiers mods)
983 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
988 MenuItem projectCleanItem
990 projectMenu, $"Clean", e, disabled = true;
991 bitmap = { ":actions/clean.png" };
992 bool NotifySelect(MenuItem selection, Modifiers mods)
997 projectView.ProjectClean(projectView.active ? selection : null, mods);
1002 MenuItem projectRealCleanItem
1004 projectMenu, $"Real Clean", disabled = true;
1005 bitmap = { ":actions/clean.png" };
1006 bool NotifySelect(MenuItem selection, Modifiers mods)
1011 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1016 MenuItem projectRegenerateItem
1018 projectMenu, $"Regenerate Makefile", m, disabled = true;
1019 bitmap = { ":actions/regMakefile.png" };
1020 bool NotifySelect(MenuItem selection, Modifiers mods)
1023 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1027 MenuItem projectInstallItem
1029 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
1030 projectMenu, $"Install", t, disabled = true;
1032 bitmap = { ":status/software-update-available.png" };
1033 bool NotifySelect(MenuItem selection, Modifiers mods)
1036 projectView.ProjectInstall(projectView.active ? selection : null, mods);
1040 MenuItem projectCompileItem;
1041 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1042 MenuItem debugStartResumeItem
1044 debugMenu, $"Start", s, f5, disabled = true;
1045 bitmap = { ":actions/debug.png" };
1046 NotifySelect = MenuDebugStart;
1048 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1052 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1053 if(!projectView.DebugStart())
1054 debugStartResumeItem.disabled = false; // same exception
1058 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1061 projectView.DebugResume();
1064 MenuItem debugRestartItem
1066 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1067 bitmap = { ":actions/restart.png" };
1068 bool NotifySelect(MenuItem selection, Modifiers mods)
1071 projectView.DebugRestart();
1075 MenuItem debugBreakItem
1077 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1078 bitmap = { ":actions/pause.png" };
1079 bool NotifySelect(MenuItem selection, Modifiers mods)
1081 if(projectView && projectView.buildInProgress != none)
1084 projectView.DebugBreak();
1088 MenuItem debugStopItem
1090 debugMenu, $"Stop", p, shiftF5, disabled = true;
1091 bitmap = { ":actions/stopDebug.png" };
1092 bool NotifySelect(MenuItem selection, Modifiers mods)
1095 projectView.DebugStop();
1099 MenuDivider { debugMenu };
1103 // nonClient = true,
1110 anchor = { right = 0, bottom = 0 },
1112 isActiveClient = false,
1114 clickThrough = true,
1115 size = { 500, 500 };
1117 bool OnLoadGraphics()
1119 ModelView::OnLoadGraphics();
1120 camera.position.z /= 1.3;
1121 camera.orientation = Euler { yaw = 280, pitch = 20 };
1127 bool OnRightButtonDown(int x, int y, Modifiers mods)
1129 if(!displaySystem.flags.flipping) return true;
1130 MenuWindowMove(null, 0);
1134 bool OnRightButtonUp(int x, int y, Modifiers mods)
1136 position = position;
1141 MenuItem debugRubberDuck
1143 debugMenu, $"Rubber Duck", checkable = true, disabled = true;
1144 bool NotifySelect(MenuItem selection, Modifiers mods)
1146 if(selection.checked)
1154 MenuDivider { debugMenu };
1155 MenuItem debugUseValgrindItem
1157 debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
1158 bool NotifySelect(MenuItem selection, Modifiers mods)
1162 ide.workspace.useValgrind = selection.checked;
1163 ide.workspace.Save();
1165 ide.AdjustValgrindMenus();
1169 Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
1170 MenuItem debugValgrindNoLeakCheckItem { debugValgrindLeakCheckItem, $"No" , f, id = ValgrindLeakCheck::no , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1171 MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; };
1172 MenuItem debugValgrindYesLeakCheckItem { debugValgrindLeakCheckItem, $"Yes" , f, id = ValgrindLeakCheck::yes , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1173 MenuItem debugValgrindFullLeakCheckItem { debugValgrindLeakCheckItem, $"Full" , f, id = ValgrindLeakCheck::full , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1174 bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
1178 if(selection.checked)
1180 ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
1182 debugValgrindNoLeakCheckItem.checked = debugValgrindNoLeakCheckItem.id == vgLeakCheck;
1183 debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
1184 debugValgrindYesLeakCheckItem.checked = debugValgrindYesLeakCheckItem.id == vgLeakCheck;
1185 debugValgrindFullLeakCheckItem.checked = debugValgrindFullLeakCheckItem.id == vgLeakCheck;
1187 ide.workspace.vgLeakCheck = vgLeakCheck;
1188 ide.workspace.Save();
1191 selection.checked = true;
1195 Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
1196 MenuItem debugValgrindRSDefaultItem { debugValgrindRedzoneSizeItem, $"Default", f, id = -1, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; };
1197 MenuItem debugValgrindRS0Item { debugValgrindRedzoneSizeItem, "0" , f, id = 0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1198 MenuItem debugValgrindRS16Item { debugValgrindRedzoneSizeItem, "16" , f, id = 16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1199 MenuItem debugValgrindRS32Item { debugValgrindRedzoneSizeItem, "32" , f, id = 32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1200 MenuItem debugValgrindRS64Item { debugValgrindRedzoneSizeItem, "64" , f, id = 64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1201 MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, "128" , f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1202 MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, "256" , f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1203 MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, "512" , f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1204 bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
1208 if(selection.checked)
1210 int vgRedzoneSize = (int)selection.id;
1212 debugValgrindRSDefaultItem.checked = debugValgrindRSDefaultItem.id == vgRedzoneSize;
1213 debugValgrindRS0Item.checked = debugValgrindRS0Item.id == vgRedzoneSize;
1214 debugValgrindRS16Item.checked = debugValgrindRS16Item.id == vgRedzoneSize;
1215 debugValgrindRS32Item.checked = debugValgrindRS32Item.id == vgRedzoneSize;
1216 debugValgrindRS64Item.checked = debugValgrindRS64Item.id == vgRedzoneSize;
1217 debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
1218 debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
1219 debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
1221 ide.workspace.vgRedzoneSize = vgRedzoneSize;
1222 ide.workspace.Save();
1225 selection.checked = true;
1229 MenuItem debugValgrindTrackOriginsItem
1231 debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
1232 bool NotifySelect(MenuItem selection, Modifiers mods)
1236 ide.workspace.vgTrackOrigins = selection.checked;
1237 ide.workspace.Save();
1243 MenuDivider { debugMenu };
1244 MenuItem debugStepIntoItem
1246 debugMenu, $"Step Into", i, f11, disabled = true;
1247 bitmap = { ":actions/stepInto.png" };
1248 bool NotifySelect(MenuItem selection, Modifiers mods)
1250 if(projectView) projectView.DebugStepInto();
1254 MenuItem debugStepOverItem
1256 debugMenu, $"Step Over", v, f10, disabled = true;
1257 bitmap = { ":actions/stepOver.png" };
1258 bool NotifySelect(MenuItem selection, Modifiers mods)
1260 if(projectView) projectView.DebugStepOver(false);
1264 MenuItem debugSkipStepOverItem
1266 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1267 bitmap = { ":actions/stepOverSkipBreak.png" };
1268 bool NotifySelect(MenuItem selection, Modifiers mods)
1270 if(projectView) projectView.DebugStepOver(true);
1274 MenuItem debugStepOutItem
1276 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1277 bitmap = { ":actions/stepOut.png" };
1278 bool NotifySelect(MenuItem selection, Modifiers mods)
1280 if(projectView) projectView.DebugStepOut(false);
1284 MenuItem debugSkipStepOutItem
1286 debugMenu, $"Step Out Skipping Breakpoints", n, Key { f11, ctrl = true, shift = true }, disabled = true;
1287 bitmap = { ":actions/skipBreaks.png" };
1288 bool NotifySelect(MenuItem selection, Modifiers mods)
1290 if(projectView) projectView.DebugStepOut(true);
1295 MenuItem debugStepUntilItem
1297 debugMenu, $"Step Over Until Next Line", x, disabled = true;
1298 bool NotifySelect(MenuItem selection, Modifiers mods)
1300 if(projectView) projectView.DebugStepUntil(false);
1304 MenuItem debugSkipStepUntilItem
1306 debugMenu, $"Step Over Until Next Line Skipping Breakpoints", e, Key { f10, shift = true, alt = true }, disabled = true;
1307 bool NotifySelect(MenuItem selection, Modifiers mods)
1309 if(projectView) projectView.DebugStepUntil(true);
1314 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1315 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1316 MenuPlacement debugRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level", l };
1317 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", g };
1319 MenuPlacement debugBpRunToCursorItem { debugMenu, $"BP Run To Cursor" };
1320 MenuPlacement debugBpSkipRunToCursorItem { debugMenu, $"BP Run To Cursor Skipping Breakpoints" };
1321 MenuPlacement debugBpRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level" };
1322 MenuPlacement debugBpSkipRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level Skipping Breakpoints" };
1324 //MenuDivider { debugMenu };
1325 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1326 MenuPlacement imageMenu { menu, $"Image", i };
1327 Menu viewMenu { menu, $"View", v };
1328 MenuItem viewProjectItem
1330 viewMenu, $"Project View", j, alt0, disabled = true;
1331 bool NotifySelect(MenuItem selection, Modifiers mods)
1335 projectView.visible = true;
1336 projectView.Activate();
1341 MenuPlacement { viewMenu, $"View Designer" };
1342 MenuPlacement { viewMenu, $"View Code" };
1343 MenuPlacement { viewMenu, $"View Properties" };
1344 MenuPlacement { viewMenu, $"View Methods" };
1345 MenuItem viewDesignerItem
1347 viewMenu, $"View Designer", d, f8;
1348 bool NotifySelect(MenuItem selection, Modifiers mods)
1350 Window client = activeClient;
1351 Class dataType = client._class;
1352 if(!strcmp(dataType.name, "Designer"))
1354 client.visible = true;
1358 ((CodeEditor)client).ViewDesigner();
1362 MenuItem viewCodeItem
1364 viewMenu, $"View Code", c, f8;
1365 bool NotifySelect(MenuItem selection, Modifiers mods)
1367 Window client = activeClient;
1368 Class dataType = client._class;
1369 if(!strcmp(dataType.name, "Designer"))
1370 client = ((Designer)client).codeEditor;
1373 // Do this after so the caret isn't moved yet...
1374 client.visible = true;
1378 MenuItem viewPropertiesItem
1380 viewMenu, $"View Properties", p, f4;
1381 bool NotifySelect(MenuItem selection, Modifiers mods)
1383 sheet.visible = true;
1384 sheet.sheetSelected = properties;
1389 MenuItem viewMethodsItem
1391 viewMenu, $"View Methods", m, f4;
1392 bool NotifySelect(MenuItem selection, Modifiers mods)
1394 sheet.visible = true;
1395 sheet.sheetSelected = methods;
1400 MenuItem viewToolBoxItem
1402 viewMenu, $"View Toolbox", x, f12;
1403 bool NotifySelect(MenuItem selection, Modifiers mods)
1405 toolBox.visible = true;
1410 MenuItem viewOutputItem
1412 viewMenu, $"Output", o, alt2;
1413 bool NotifySelect(MenuItem selection, Modifiers mods)
1419 MenuItem viewWatchesItem
1421 viewMenu, $"Watches", w, alt3;
1422 bool NotifySelect(MenuItem selection, Modifiers mods)
1428 MenuItem viewThreadsItem
1430 viewMenu, $"Threads", t, alt4;
1431 bool NotifySelect(MenuItem selection, Modifiers mods)
1437 MenuItem viewBreakpointsItem
1439 viewMenu, $"Breakpoints", b, alt5;
1440 bool NotifySelect(MenuItem selection, Modifiers mods)
1442 breakpointsView.Show();
1446 MenuItem viewCallStackItem
1448 viewMenu, $"Call Stack", s, alt7;
1449 bool NotifySelect(MenuItem selection, Modifiers mods)
1451 callStackView.Show();
1455 MenuItem viewAllDebugViews
1457 viewMenu, $"All Debug Views", a, alt9;
1458 bool NotifySelect(MenuItem selection, Modifiers mods)
1463 callStackView.Show();
1464 breakpointsView.Show();
1468 #ifdef GDB_DEBUG_GUI
1469 MenuDivider { viewMenu };
1470 MenuItem viewGDBItem
1472 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1473 bool NotifySelect(MenuItem selection, Modifiers mods)
1480 MenuDivider { viewMenu };
1481 MenuItem viewColorPicker
1483 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1484 bool NotifySelect(MenuItem selection, Modifiers mods)
1486 ColorPicker colorPicker { master = this };
1487 colorPicker.Modal();
1491 MenuDivider { viewMenu };
1495 viewMenu, "Full Screen", f, checkable = true;
1497 bool NotifySelect(MenuItem selection, Modifiers mods)
1499 app.fullScreen ^= true;
1501 anchor = { 0, 0, 0, 0 };
1506 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1508 MenuDivider { viewMenu };
1510 Menu languageMenu { viewMenu, "Language", l };
1512 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1513 Menu windowMenu { menu, $"Window", w };
1514 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1515 MenuDivider { windowMenu };
1516 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1517 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1518 MenuDivider { windowMenu };
1519 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1520 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1521 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1522 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1523 MenuDivider { windowMenu };
1524 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1525 Menu helpMenu { menu, $"Help", h };
1528 helpMenu, $"API Reference", r, f1;
1529 bool NotifySelect(MenuItem selection, Modifiers mods)
1533 char * p = new char[MAX_LOCATION];
1535 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1536 PathCat(p, "documentor");
1537 #if defined(__WIN32__)
1538 ChangeExtension(p, "exe", p);
1540 if(!FileExists(p).isFile)
1541 strcpy(p, "documentor");
1543 documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
1548 Process_ShowWindows(documentor.GetProcessID());
1549 // documentor.Puts("Activate\n");
1554 MenuDivider { helpMenu };
1557 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1558 bool NotifySelect(MenuItem selection, Modifiers mods)
1560 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1564 MenuDivider { helpMenu };
1567 helpMenu, $"Documentation Folder", d;
1568 bool NotifySelect(MenuItem selection, Modifiers mods)
1570 FindAndShellOpenInstalledFolder("doc");
1576 helpMenu, $"Samples Folder", s;
1577 bool NotifySelect(MenuItem selection, Modifiers mods)
1579 FindAndShellOpenInstalledFolder("samples");
1585 helpMenu, $"Extras Folder", x;
1586 bool NotifySelect(MenuItem selection, Modifiers mods)
1588 FindAndShellOpenInstalledFolder("extras");
1592 MenuDivider { helpMenu };
1595 helpMenu, $"Community Forums", f;
1596 bool NotifySelect(MenuItem selection, Modifiers mods)
1598 ShellOpen("http://ecere.com/forums");
1602 MenuDivider { helpMenu };
1605 helpMenu, $"About...", a;
1606 bool NotifySelect(MenuItem selection, Modifiers mods)
1608 AboutIDE { master = this }.Modal();
1613 property ToolBox toolBox
1615 get { return toolBox; }
1618 property Sheet sheet
1620 get { return sheet; }
1623 property Project project
1625 get { return projectView ? projectView.project : null; }
1628 property Workspace workspace
1630 get { return projectView ? projectView.workspace : null; }
1633 FindInFilesDialog findInFilesDialog
1636 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1644 #ifdef GDB_DEBUG_GUI
1647 master = this, parent = this;
1648 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1650 void OnCommand(const char * string)
1653 ide.debugger.SendGDBCommand(string);
1658 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1660 //app.driver = app.drivers[selection.id];
1661 #if defined(__unix__) || defined(__APPLE__)
1662 app.driver = selection.id ? "OpenGL" : "X";
1664 app.driver = selection.id ? "OpenGL" : "GDI";
1666 delete ideSettings.displayDriver;
1667 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1669 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1671 settingsContainer.Save();
1672 //SetDriverAndSkin();
1676 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1678 app.skin = app.skins[selection.id];
1683 void SetDriverAndSkin()
1686 for(c = 0; c < app.numSkins; c++)
1687 if(!strcmp(app.skins[c], app.skin))
1689 skinItems[c].checked = true;
1692 for(c = 0; c < app.numDrivers; c++)
1693 if(!strcmp(app.drivers[c], app.driver))
1695 driverItems[c].checked = true;
1700 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1702 Project project = workspace.projects.firstIterator.data;
1703 projectView = ProjectView
1706 fileName = fileName;
1708 void NotifyDestroyed(Window window, DialogResult result)
1711 text = titleECEREIDE;
1716 projectView.Create();
1717 RepositionWindows(false);
1719 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1720 projectView.workspace = workspace;
1721 projectView.project = project;
1722 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1726 ide.breakpointsView.LoadFromWorkspace();
1727 ide.watchesView.LoadFromWorkspace();
1729 findInFilesDialog.projectNodeField.userData = projectView;
1732 char fileName[MAX_LOCATION];
1733 strcpy(fileName, project.topNode.path);
1734 PathCat(fileName, project.topNode.name);
1741 projectView.visible = false;
1742 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1744 if(findInFilesDialog)
1746 char workingDir[MAX_LOCATION];
1747 GetWorkingDir(workingDir, MAX_LOCATION);
1748 findInFilesDialog.SearchStop();
1749 findInFilesDialog.currentDirectory = workingDir;
1751 sheet.visible = false;
1752 toolBox.visible = false;
1753 outputView.visible = false;
1754 ideMainFrame.text = titleECEREIDE;
1761 void RepositionWindows(bool expand)
1766 bool callStackVisible = expand ? false : callStackView.visible;
1767 bool threadsVisible = expand ? false : threadsView.visible;
1768 bool watchesVisible = expand ? false : watchesView.visible;
1769 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1770 bool toolBoxVisible = toolBox.visible;
1771 bool outputVisible = expand ? false : outputView.visible;
1772 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1773 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1775 for(child = firstChild; child; child = child.next)
1777 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1778 child._class == class(Sheet) || child._class == class(ProjectView))
1780 Anchor anchor = child.anchor;
1781 anchor.top = topDistance;
1782 anchor.bottom = bottomDistance;
1783 if(child._class == class(CodeEditor) || child._class == class(Designer))
1785 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1786 anchor.right = toolBoxVisible ? 150 : 0;
1789 child.anchor = anchor;
1793 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1794 child._class == class(BreakpointsView))
1795 child.visible = false;
1798 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1800 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1804 bool ShowCodeEditor()
1807 activeClient.Activate();
1808 else if(projectView)
1810 projectView.visible = true;
1811 projectView.Activate();
1813 else if(sheet.visible)
1816 outputView.visible = false;
1820 void DocumentSaved(Window document, const char * fileName)
1822 ideSettings.AddRecentFile(fileName);
1823 ide.UpdateRecentMenus();
1824 ide.AdjustFileMenus();
1825 settingsContainer.Save();
1828 bool Window::OnFileModified(FileChange fileChange, const char * param)
1831 sprintf(temp, $"The document %s was modified by another application.\n"
1832 "Would you like to reload it and lose your changes?", this.fileName);
1833 if(MessageBox { type = yesNo, master = this/*.parent*/,
1834 text = $"Document has been modified", contents = temp }.Modal() == yes)
1836 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1837 char * fileName = CopyString(this.fileName);
1838 WindowState state = this.state;
1839 Anchor anchor = this.anchor;
1840 Size size = this.size;
1842 this.modifiedDocument = false;
1844 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1847 this.anchor = anchor;
1849 this.SetState(state, true, 0);
1857 void UpdateMakefiles()
1861 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
1862 for(prj : workspace.projects)
1863 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1868 void UpdateCompilerConfigs(bool mute)
1870 UpdateToolBarActiveCompilers();
1873 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1874 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
1877 projectView.ShowOutputBuildLog(true);
1878 projectView.DisplayCompiler(compiler, false);
1880 for(prj : workspace.projects)
1881 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1886 void UpdateToolBarActiveCompilers()
1888 toolBar.activeCompiler.Clear();
1889 for(compiler : ideSettings.compilerConfigs)
1891 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1892 if(workspace && workspace.activeCompiler && !strcmp(compiler.name, workspace.activeCompiler))
1893 toolBar.activeCompiler.currentRow = row;
1895 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1896 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1897 toolBar.activeBitDepth.SelectRow(toolBar.activeBitDepth.FindRow(workspace ? workspace.bitDepth : 0));
1900 void UpdateToolBarActiveConfigs(bool selectionOnly)
1902 bool commonSelected = false;
1903 DataRow row = toolBar.activeConfig.currentRow;
1905 row = toolBar.activeConfig.FindRow(1);
1908 toolBar.activeConfig.Clear();
1909 row = toolBar.activeConfig.AddString($"(Mixed)");
1914 char * configName = null;
1917 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1918 for(prj : workspace.projects)
1920 for(cfg : prj.configurations)
1923 configs[cfg.name] = 1;
1928 toolBar.activeConfig.AddString(&name);
1932 if(projectView && projectView.project)
1934 for(prj : workspace.projects)
1936 if(prj.config && prj.config.name)
1938 configName = prj.config.name;
1944 commonSelected = true;
1945 for(prj : workspace.projects)
1947 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1949 commonSelected = false;
1957 commonSelected = false;
1958 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1960 if(!strcmp(row.string, configName))
1962 toolBar.activeConfig.currentRow = row;
1963 commonSelected = true;
1970 toolBar.activeConfig.Sort(null, 0);
1972 toolBar.activeConfig.currentRow = row;
1977 bool unavailable = !project;
1979 projectAddItem.disabled = unavailable;
1980 toolBar.buttonAddProject.disabled = unavailable;
1982 projectSettingsItem.disabled = unavailable;
1984 projectBrowseFolderItem.disabled = unavailable;
1986 viewProjectItem.disabled = unavailable;
1988 toolBar.activeConfig.disabled = unavailable;
1989 toolBar.activeCompiler.disabled = unavailable;
1990 toolBar.activeBitDepth.disabled = unavailable;
1993 debugUseValgrindItem.disabled = unavailable;
1994 AdjustValgrindMenus();
2003 void AdjustValgrindMenus()
2005 bool unavailable = !project || !debugUseValgrindItem.checked;
2006 debugValgrindNoLeakCheckItem.disabled = unavailable;
2007 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2008 debugValgrindYesLeakCheckItem.disabled = unavailable;
2009 debugValgrindFullLeakCheckItem.disabled = unavailable;
2011 debugValgrindTrackOriginsItem.disabled = unavailable;
2013 debugValgrindRSDefaultItem.disabled = unavailable;
2014 debugValgrindRS0Item.disabled = unavailable;
2015 debugValgrindRS16Item.disabled = unavailable;
2016 debugValgrindRS32Item.disabled = unavailable;
2017 debugValgrindRS64Item.disabled = unavailable;
2018 debugValgrindRS128Item.disabled = unavailable;
2019 debugValgrindRS256Item.disabled = unavailable;
2020 debugValgrindRS512Item.disabled = unavailable;
2024 property bool hasOpenedCodeEditors
2029 for(w = firstChild; w; w = w.next)
2030 if(w._class == class(CodeEditor) &&
2031 w.isDocument && !w.closing && w.visible && w.created &&
2032 w.fileName && w.fileName[0])
2038 void AdjustFileMenus()
2040 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2042 projectQuickItem.disabled = unavailable;
2045 void AdjustBuildMenus()
2047 bool unavailable = project && projectView.buildInProgress;
2048 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2050 projectNewItem.disabled = unavailable;
2051 toolBar.buttonNewProject.disabled = unavailable;
2052 projectOpenItem.disabled = unavailable;
2053 toolBar.buttonOpenProject.disabled = unavailable;
2055 unavailable = !project || projectView.buildInProgress;
2057 projectCloseItem.disabled = unavailable;
2058 // toolBar.buttonCloseProject.disabled = unavailable;
2060 projectRunItem.disabled = naForRun;
2061 toolBar.buttonRun.disabled = naForRun;
2063 projectBuildItem.disabled = false;
2064 projectBuildItem.text = unavailable ? $"Stop Build" : $"Build";
2065 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2067 projectLinkItem.disabled = unavailable;
2068 toolBar.buttonReLink.disabled = unavailable;
2069 projectRebuildItem.disabled = unavailable;
2070 toolBar.buttonRebuild.disabled = unavailable;
2071 projectCleanItem.disabled = unavailable;
2072 toolBar.buttonClean.disabled = unavailable;
2073 projectCleanTargetItem.disabled = unavailable;
2074 projectRealCleanItem.disabled = unavailable;
2075 // toolBar.buttonRealClean.disabled = unavailable;
2076 projectRegenerateItem.disabled = unavailable;
2077 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2078 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2079 projectInstallItem.disabled = unavailable;
2080 toolBar.buttonInstall.disabled = unavailable;
2082 projectCompileItem.disabled = unavailable;
2084 AdjustPopupBuildMenus();
2087 void AdjustPopupBuildMenus()
2089 bool unavailable = !project || projectView.buildInProgress;
2091 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2094 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
2097 menu.disabled = false;
2098 menu.text = unavailable ? $"Stop Build" : $"Build";
2099 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2102 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0); if(menu) menu.disabled = unavailable;
2103 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0); if(menu) menu.disabled = unavailable;
2104 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0); if(menu) menu.disabled = unavailable;
2105 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0); if(menu) menu.disabled = unavailable;
2106 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0); if(menu) menu.disabled = unavailable;
2107 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
2108 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, 0); if(menu) menu.disabled = unavailable;
2109 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0); if(menu) menu.disabled = unavailable;
2110 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0); if(menu) menu.disabled = unavailable;
2111 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0); if(menu) menu.disabled = unavailable;
2112 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0); if(menu) menu.disabled = unavailable;
2113 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0); if(menu) menu.disabled = unavailable;
2114 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
2115 projectView.popupMenu.Update(null);
2119 property bool areDebugMenusUnavailable { get {
2121 project.GetTargetType(project.config) != executable ||
2122 projectView.buildInProgress == buildingMainProject;
2125 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2126 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2127 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2129 void AdjustDebugMenus()
2131 bool unavailable = areDebugMenusUnavailable;
2132 bool running = isDebuggerRunning;
2133 bool stopped = isDebuggerStopped;
2134 bool active = debugger.isActive;
2136 bool isNotRunning = unavailable || !running;
2137 bool isNotNotRunning = unavailable || running;
2138 bool isNotStopped = unavailable || !stopped;
2139 bool isNotActive = unavailable || !active;
2141 debugStartResumeItem.disabled = isNotNotRunning;
2142 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2143 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2146 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2147 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2150 debugBreakItem.disabled = isNotRunning;
2151 debugStopItem.disabled = isNotActive;
2152 debugRestartItem.disabled = isNotActive;
2155 toolBar.buttonDebugPause.disabled = isNotRunning;
2156 toolBar.buttonDebugStop.disabled = isNotActive;
2157 toolBar.buttonDebugRestart.disabled = isNotActive;
2160 debugStepIntoItem.disabled = isNotNotRunning;
2161 debugStepOverItem.disabled = isNotNotRunning;
2162 debugSkipStepOverItem.disabled = isNotNotRunning;
2163 debugStepOutItem.disabled = isNotStopped;
2164 debugSkipStepOutItem.disabled = isNotStopped;
2166 debugStepUntilItem.disabled = isNotStopped;
2167 debugSkipStepUntilItem.disabled = isNotStopped;
2171 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2172 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2173 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2174 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2175 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2177 if((Designer)GetActiveDesigner())
2179 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2181 codeEditor.AdjustDebugMenus();
2185 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2187 char tempString[MAX_LOCATION];
2188 strcpy(tempString, directory);
2189 if(saveSettings && !projectView)
2191 ideSettings.ideFileDialogLocation = directory;
2192 settingsContainer.Save();
2195 ideFileDialog.currentDirectory = tempString;
2196 codeEditorFileDialog.currentDirectory = tempString;
2197 codeEditorFormFileDialog.currentDirectory = tempString;
2200 void ChangeProjectFileDialogDirectory(char * directory)
2202 ideSettings.ideProjectFileDialogLocation = directory;
2203 settingsContainer.Save();
2206 Window FindWindow(const char * filePath)
2208 Window document = null;
2210 // TOCHECK: Do we need to change slashes here?
2211 for(document = firstChild; document; document = document.next)
2213 const char * fileName = document.fileName;
2214 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2216 document.visible = true;
2217 document.Activate();
2224 bool DontTerminateDebugSession(const char * title)
2226 if(debugger.isActive)
2228 if(MessageBox { type = yesNo, master = ide,
2229 contents = $"Do you want to terminate the debugging session in progress?",
2230 text = title }.Modal() == no)
2233 MessageBox msg { type = yesNo, master = ide,
2234 contents = "Do you want to terminate the debugging session in progress?",
2236 if(msg.Modal() == no)
2248 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2250 char extension[MAX_EXTENSION] = "";
2251 Window document = null;
2252 bool isProject = false;
2253 bool needFileModified = true;
2254 char winFilePath[MAX_LOCATION];
2255 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2256 Window currentDoc = activeClient;
2257 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2260 GetExtension(filePath, extension);
2264 strcpy(extension, type);
2266 if(strcmp(extension, ProjectExtension))
2268 for(document = firstChild; document; document = document.next)
2270 const char * fileName = document.fileName;
2271 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2273 document.visible = true;
2275 document.Activate();
2281 if(createIfFails == whatever)
2283 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2285 needFileModified = false;
2286 if(openMethod == normal)
2288 if(DontTerminateDebugSession($"Open Project"))
2297 Workspace workspace = null;
2299 if(FileExists(filePath))
2301 if(!strcmp(extension, ProjectExtension))
2303 char workspaceFile[MAX_LOCATION];
2304 strcpy(workspaceFile, filePath);
2305 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2306 workspace = LoadWorkspace(workspaceFile, filePath);
2308 else if(!strcmp(extension, WorkspaceExtension))
2309 workspace = LoadWorkspace(filePath, null);
2316 CreateProjectView(workspace, filePath);
2317 document = projectView;
2319 toolBox.visible = true;
2320 sheet.visible = true;
2321 projectView.MakeActive();
2323 workspace.ParseLoadedBreakpoints();
2324 workspace.DropInvalidBreakpoints(null);
2327 ide.projectView.ShowOutputBuildLog(true);
2329 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
2330 ide.projectView.DisplayCompiler(compiler, false);
2333 UpdateCompilerConfigs(false);
2336 char newWorkingDir[MAX_LOCATION];
2337 StripLastDirectory(filePath, newWorkingDir);
2338 ChangeFileDialogsDirectory(newWorkingDir, false);
2341 document.fileName = filePath;
2343 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2345 // this crashes on starting ide with epj file, solution please?
2346 // app.UpdateDisplay();
2348 workspace.OpenPreviouslyOpenedFiles(noParsing);
2349 workspace.holdTracking = true;
2350 ide.RepositionWindows(false);
2351 workspace.holdTracking = false;
2353 workspace.timer.Start();
2355 #if !defined(__WIN32__)
2356 // Valgrind Debug menu updates
2357 debugUseValgrindItem.checked = workspace.useValgrind;
2359 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2360 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2361 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2362 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2364 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2365 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2366 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2367 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2368 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2369 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2370 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2371 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2373 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2376 findInFilesDialog.mode = FindInFilesMode::project;
2377 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2380 char location[MAX_LOCATION];
2381 StripLastDirectory(ide.project.topNode.path, location);
2382 ChangeProjectFileDialogDirectory(location);
2389 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2391 ideProjectFileDialog.text = openProjectFileDialogTitle;
2392 if(ideProjectFileDialog.Modal() == cancel)
2394 filePath = ideProjectFileDialog.filePath;
2395 GetExtension(filePath, extension);
2406 else if(openMethod == add)
2411 char slashFilePath[MAX_LOCATION];
2412 GetSlashPathBuffer(slashFilePath, filePath);
2413 for(p : workspace.projects)
2415 if(!fstrcmp(p.filePath, slashFilePath))
2423 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2424 contents = $"This project is already present in workspace." }.Modal();
2428 prj = LoadProject(filePath, null);
2431 const char * activeConfigName = null;
2432 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
2433 prj.StartMonitoring();
2434 workspace.AddProject(prj, null);
2435 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2436 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2437 activeConfigName = toolBar.activeConfig.currentRow.string;
2438 if(activeConfigName)
2440 for(cfg : prj.configurations)
2442 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2450 projectView.AddNode(prj.topNode, null);
2451 workspace.modified = true;
2453 findInFilesDialog.AddProjectItem(prj);
2454 projectView.ShowOutputBuildLog(true);
2455 projectView.DisplayCompiler(compiler, false);
2456 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2460 char location[MAX_LOCATION];
2461 StripLastDirectory(prj.topNode.path, location);
2462 ChangeProjectFileDialogDirectory(location);
2465 // projectView is associated with the main project and not with the one just added but
2466 return projectView; // just to let the caller know something was opened
2474 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2475 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2476 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2478 if(FileExists(filePath))
2479 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2480 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2481 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2484 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2487 else if(!strcmp(extension, "3ds"))
2489 if(FileExists(filePath))
2490 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2491 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2492 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2496 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2499 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2500 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2501 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2502 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2503 !strcmp(extension, "js"))
2505 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2506 editor.updatingCode = true;
2507 if(editor.LoadFile(filePath))
2510 editor.visible = true;
2514 needFileModified = false;
2518 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2519 if(editor.LoadFile(filePath))
2522 editor.visible = true;
2526 needFileModified = false;
2529 if(document && (document._class == class(PictureEdit) ||
2530 document._class == class(ModelView)))
2535 document.fileName = filePath;
2536 if(workspace && !workspace.holdTracking)
2537 workspace.UpdateOpenedFileInfo(filePath, opened);
2541 if(!document && createIfFails != no)
2543 if(createIfFails != yes && !needFileModified &&
2544 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2545 createIfFails = yes;
2546 if(createIfFails == yes || createIfFails == whatever)
2548 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2550 document.fileName = filePath;
2556 if(projectView && document._class == class(CodeEditor) && workspace)
2557 workspace.RestorePreviouslyOpenedFileState((CodeEditor)document);
2559 if(needFileModified)
2560 document.OnFileModified = OnFileModified;
2561 document.NotifySaved = DocumentSaved;
2562 if(maximizeDoc && document.hasMaximize)
2563 document.state = maximized;
2566 ideSettings.AddRecentProject(document.fileName);
2568 ideSettings.AddRecentFile(document.fileName);
2569 ide.UpdateRecentMenus();
2570 ide.AdjustFileMenus();
2571 settingsContainer.Save();
2579 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2580 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2582 if(!parentClosing && ide.workspace)
2583 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2586 bool ModelView::ModelViewOnClose(bool parentClosing)
2588 if(!parentClosing && ide.workspace)
2589 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2592 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2594 if(!parentClosing && ide.workspace)
2595 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2600 void OnUnloadGraphics(Window window)
2602 display.ClearMaterials();
2603 display.ClearTextures();
2604 display.ClearMeshes();
2608 void UpdateStateLight(StatusField fld, bool on)
2610 fld.color = on ? lime : Color { 128,128,128 };
2611 fld.backColor = on ? dimGray : 0;
2615 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2617 UpdateStateLight(caps, app.GetKeyState(capsState));
2618 UpdateStateLight(num, app.GetKeyState(numState));
2622 bool OnKeyDown(Key key, unichar ch)
2626 case b: projectView.Update(null); break;
2627 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2628 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2633 bool OnKeyUp(Key key, unichar ch)
2637 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2638 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2643 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2646 projectView.GoToError(line, noParsing, objectFileExt);
2649 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2651 FileAttribs result { };
2652 FileAttribs fileAttribs;
2656 strcpy(selectedPath, prj.topNode.path);
2657 else if(dir && dir[0])
2658 strcpy(selectedPath, dir);
2660 selectedPath[0] = '\0';
2661 PathCat(selectedPath, filePath);
2663 if((fileAttribs = FileExists(selectedPath)).isFile)
2664 result = fileAttribs;
2668 for(p : workspace.projects)
2670 strcpy(selectedPath, p.topNode.path);
2671 PathCat(selectedPath, filePath);
2672 if((fileAttribs = FileExists(selectedPath)).isFile)
2675 result = fileAttribs;
2682 ProjectNode n = null;
2683 for(p : workspace.projects)
2685 if((n = p.topNode.Find(filePath, false)))
2687 n.GetFullFilePath(selectedPath);
2688 if((fileAttribs = FileExists(selectedPath)).isFile)
2691 result = fileAttribs;
2696 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2697 (fileAttribs = FileExists(selectedPath)).isFile)
2700 result = fileAttribs;
2708 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2711 const char *path = text;
2712 char *colon = strchr(text, ':');
2713 char filePath[MAX_LOCATION] = "";
2714 char completePath[MAX_LOCATION];
2715 int line = 0, col = 0;
2716 int len = strlen(text);
2718 FileAttribs fileAttribs;
2720 // support for valgrind output
2721 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2732 /*for(s=colon; *s; s++)
2741 //line = atoi(colon+1);
2743 // support for "Found n match(es) in "file/path";
2744 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)
2750 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2752 path = (colon - 1 > path) ? colon - 1 : path;
2753 colon = strstr(colon + 1, ":");
2755 if(*path == '*' && (s = strchr(path+1, '*')))
2757 while(isspace(*path)) path++;
2761 char * close = strchr(path, ')');
2765 strncpy(name, path+1, close - path - 1);
2766 name[close - path - 1] = '\0';
2767 for(p : ide.workspace.projects)
2769 if(!strcmp(p.name, name))
2779 prj = project ? project : (dir ? null : ide.project);
2782 strncpy(filePath, path, colon - path);
2783 filePath[colon - path] = '\0';
2784 line = atoi(colon + 1);
2785 colon = strstr(colon + 1, ":");
2787 col = atoi(colon + 1);
2789 else if(path - 1 >= text && *(path - 1) == '\"')
2791 colon = strchr(path, '\"');
2794 strncpy(filePath, path, colon - path);
2795 filePath[colon - path] = '\0';
2798 else if(path && !colon)
2800 strcpy(filePath, path);
2803 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2804 CodeLocationGoTo(completePath, fileAttribs, line, col);
2807 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2809 if(fileAttribs.isFile)
2811 char ext[MAX_EXTENSION];
2812 GetExtension(path, ext);
2814 if(binaryDocExt.Find(ext))
2816 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2817 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2819 char dirPath[MAX_LOCATION];
2820 StripLastDirectory(path, dirPath);
2825 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2826 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2828 EditBox editBox = codeEditor.editBox;
2829 editBox.GoToLineNum(line - 1);
2830 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2834 else if(fileAttribs.isDirectory)
2838 void OnRedraw(Surface surface)
2840 Bitmap bitmap = back.bitmap;
2842 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2845 void SheetSelected(SheetType sheetSelected)
2847 if(activeChild == sheet)
2849 if(sheetSelected == methods)
2851 viewPropertiesItem.accelerator = f4;
2852 viewPropertiesItem.parent = viewMenu;
2853 viewMethodsItem.parent = null;
2857 viewMethodsItem.accelerator = f4;
2858 viewMethodsItem.parent = viewMenu;
2859 viewPropertiesItem.parent = null;
2864 viewMethodsItem.parent = viewMenu;
2865 viewPropertiesItem.parent = viewMenu;
2866 if(sheetSelected == methods)
2868 viewMethodsItem.accelerator = f4;
2869 viewPropertiesItem.accelerator = 0;
2873 viewMethodsItem.accelerator = 0;
2874 viewPropertiesItem.accelerator = f4;
2879 void OnActivateClient(Window client, Window previous)
2881 //if(!client || client != previous)
2884 if(!client || client != previous)
2887 dataType = previous._class;
2888 if(previous && !strcmp(dataType.name, "CodeEditor"))
2890 ((CodeEditor)previous).UpdateFormCode();
2892 else if(previous && !strcmp(dataType.name, "Designer"))
2894 ((Designer)previous).codeEditor.UpdateFormCode();
2899 dataType = client._class;
2900 if(client && !strcmp(dataType.name, "CodeEditor"))
2902 CodeEditor codeEditor = (CodeEditor)client;
2903 SetPrivateModule(codeEditor.privateModule);
2904 SetCurrentContext(codeEditor.globalContext);
2905 SetTopContext(codeEditor.globalContext);
2906 SetGlobalContext(codeEditor.globalContext);
2908 SetDefines(&codeEditor.defines);
2909 SetImports(&codeEditor.imports);
2911 SetActiveDesigner(codeEditor.designer);
2913 sheet.codeEditor = codeEditor;
2914 toolBox.codeEditor = codeEditor;
2916 viewDesignerItem.parent = viewMenu;
2917 if(activeChild != codeEditor)
2919 viewCodeItem.parent = viewMenu;
2920 viewDesignerItem.accelerator = 0;
2921 viewCodeItem.accelerator = f8;
2925 viewCodeItem.parent = null;
2926 viewDesignerItem.accelerator = f8;
2929 else if(client && !strcmp(dataType.name, "Designer"))
2931 CodeEditor codeEditor = ((Designer)client).codeEditor;
2934 SetPrivateModule(codeEditor.privateModule);
2935 SetCurrentContext(codeEditor.globalContext);
2936 SetTopContext(codeEditor.globalContext);
2937 SetGlobalContext(codeEditor.globalContext);
2938 SetDefines(&codeEditor.defines);
2939 SetImports(&codeEditor.imports);
2943 SetPrivateModule(null);
2944 SetCurrentContext(null);
2945 SetTopContext(null);
2946 SetGlobalContext(null);
2951 SetActiveDesigner((Designer)client);
2953 sheet.codeEditor = codeEditor;
2954 toolBox.codeEditor = codeEditor;
2956 viewCodeItem.parent = viewMenu;
2957 if(activeChild != client)
2959 viewDesignerItem.parent = viewMenu;
2960 viewDesignerItem.accelerator = f8;
2961 viewCodeItem.accelerator = 0;
2965 viewDesignerItem.parent = null;
2966 viewCodeItem.accelerator = f8;
2971 if(!client && !projectView && sheet.visible)
2974 sheet.visible = false;
2975 toolBox.visible = false;
2978 sheet.codeEditor = null;
2979 toolBox.codeEditor = null;
2980 SetActiveDesigner(null);
2982 viewDesignerItem.parent = null;
2983 viewCodeItem.parent = null;
2986 SheetSelected(sheet.sheetSelected);
2989 projectCompileItem = null;
2994 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
2996 CodeEditor codeEditor = (CodeEditor)client;
2997 EditBox editBox = codeEditor.editBox;
2999 statusBar.AddField(pos);
3001 caps = { width = 40, text = $"CAPS" };
3002 statusBar.AddField(caps);
3003 UpdateStateLight(caps, app.GetKeyState(capsState));
3005 ovr = { width = 36, text = $"OVR" };
3006 statusBar.AddField(ovr);
3007 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3009 num = { width = 36, text = $"NUM" };
3010 statusBar.AddField(num);
3011 UpdateStateLight(num, app.GetKeyState(numState));
3013 //statusBar.text = "Ready";
3015 if(projectView && projectView.project)
3017 bool isCObject = false;
3018 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3019 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3023 char nodeName[MAX_FILENAME];
3024 char name[MAX_FILENAME+96];
3026 ChangeExtension(node.name, "c", nodeName);
3027 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3028 projectCompileItem =
3030 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3032 bool NotifySelect(MenuItem selection, Modifiers mods)
3036 bool isCObject = false;
3037 bool isExcluded = false;
3038 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3042 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3045 List<ProjectNode> nodes { };
3047 projectView.Compile(node.project, nodes, false, false, isCObject ? cObject : normal);
3055 projectMenu.AddDynamic(projectCompileItem, ide, false);
3061 caps = ovr = num = null;
3066 bool OnClose(bool parentClosing)
3068 //return !projectView.buildInProgress;
3069 if(projectView && projectView.buildInProgress)
3071 if(DontTerminateDebugSession($"Close IDE"))
3073 if(findInFilesDialog)
3074 findInFilesDialog.SearchStop();
3077 workspace.timer.Stop();
3080 ideMainFrame.Destroy(0);
3087 bool passThrough = false;
3088 bool debugWorkDir = false;
3089 char * passDebugWorkDir = null;
3090 bool openAsText = false;
3091 DynamicString passArgs { };
3094 for(c = 1; c<app.argc; c++)
3098 const char * arg = app.argv[c];
3099 char * buf = new char[strlen(arg)*2+1];
3101 passArgs.concat(" ");
3103 passArgs.concat(buf);
3106 else if(debugWorkDir)
3108 passDebugWorkDir = CopyString(app.argv[c]);
3109 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3110 debugWorkDir = false;
3112 else if(!strcmp(app.argv[c], "-t"))
3114 else if(!strcmp(app.argv[c], "-no-parsing"))
3115 ide.noParsing = true;
3116 else if(!strcmp(app.argv[c], "-debug-start"))
3117 ide.debugStart = true;
3118 else if(!strcmp(app.argv[c], "-debug-hide-ide"))
3119 ide.debugHideIDE = true;
3120 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3121 debugWorkDir = true;
3122 else if(!strcmp(app.argv[c], "-@"))
3126 char fullPath[MAX_LOCATION];
3127 char parentPath[MAX_LOCATION];
3128 char ext[MAX_EXTENSION];
3130 FileAttribs dirAttribs;
3131 GetWorkingDir(fullPath, MAX_LOCATION);
3132 PathCat(fullPath, app.argv[c]);
3133 StripLastDirectory(fullPath, parentPath);
3134 GetExtension(app.argv[c], ext);
3135 isProject = !openAsText && !strcmpi(ext, "epj");
3137 if(isProject && c > 1 + (ide.debugStart ? 1 : 0) + (ide.debugHideIDE ? 1 : 0)) continue;
3139 // Create directory for projects (only)
3140 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3142 if(isProject && !FileExists(fullPath))
3144 char name[MAX_LOCATION];
3145 NewProjectDialog newProjectDialog;
3149 projectView.visible = false;
3150 if(!projectView.Destroy(0))
3154 newProjectDialog = { master = this };
3156 strcpy(name, app.argv[c]);
3157 StripExtension(name);
3158 GetLastDirectory(name, name);
3159 newProjectDialog.projectName.contents = name;
3160 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3161 newProjectDialog.locationEditBox.path = parentPath;
3162 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3164 incref newProjectDialog;
3165 newProjectDialog.Modal();
3168 ideSettings.AddRecentProject(projectView.fileName);
3169 ide.UpdateRecentMenus();
3170 settingsContainer.Save();
3172 delete newProjectDialog;
3173 // Open only one project
3177 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3179 else if(strstr(fullPath, "http://") == fullPath)
3180 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3183 if(passThrough && projectView && projectView.project && workspace)
3184 workspace.commandLineArgs = passArgs;
3185 if(passDebugWorkDir && projectView && projectView.project && workspace)
3187 workspace.debugDir = passDebugWorkDir;
3188 delete passDebugWorkDir;
3191 UpdateToolBarActiveConfigs(false);
3192 UpdateToolBarActiveCompilers();
3199 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3202 projectView.visible = false;
3203 projectView.Destroy(0);
3206 #ifdef GDB_DEBUG_GUI
3207 gdbDialog.Destroy(0);
3212 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3216 char * oldPaths[128];
3217 String oldList = new char[maxPathLen];
3218 Array<String> newExePaths { };
3219 //Map<String, bool> exePathExists { };
3221 #if defined(__unix__) || defined(__APPLE__)
3222 Array<String> newLibPaths { };
3223 Map<String, bool> libPathExists { };
3228 for(prj : workspace.projects)
3230 DirExpression targetDirExp;
3232 // SKIP FIRST PROJECT...
3233 if(prj == workspace.projects.firstIterator.data) continue;
3235 // NOTE: Right now the additional project config dir will be
3236 // obtained when the debugger is started, so toggling it
3237 // while building will change which library gets used.
3238 // To go with the initial state, e.g. when F5 was pressed,
3239 // we nould need to keep a list of all project's active
3240 // config upon startup.
3241 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3243 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3247 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3248 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3252 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3253 if(cfg.targetType == sharedLibrary && cfg.debug)
3257 if(targetDirExp.dir)
3259 char buffer[MAX_LOCATION];
3260 #if defined(__WIN32__)
3261 Array<String> paths = newExePaths;
3263 Array<String> paths = newLibPaths;
3265 GetSystemPathBuffer(buffer, prj.topNode.path);
3266 PathCat(buffer, targetDirExp.dir);
3269 if(!fstrcmp(p, buffer))
3276 paths.Add(CopyString(buffer));
3278 delete targetDirExp;
3282 for(item : compiler.executableDirs)
3284 DirExpression dirExpr { };
3285 dirExpr.Evaluate(item, null, compiler, null, 0);
3288 for(p : newExePaths)
3290 if(!fstrcmp(p, dirExpr.dir))
3297 newExePaths.Add(CopySystemPath(dirExpr.dir));
3301 GetEnvironment("PATH", oldList, maxPathLen);
3303 printf("Old value of PATH: %s\n", oldList);
3305 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3306 for(c = 0; c < count; c++)
3309 for(p : newExePaths)
3311 if(!fstrcmp(p, oldPaths[c]))
3318 newExePaths.Add(CopySystemPath(oldPaths[c]));
3322 for(path : newExePaths)
3323 len += strlen(path) + 1;
3324 newList = new char[len + 1];
3326 for(path : newExePaths)
3328 strcat(newList, path);
3329 strcat(newList, pathListSep);
3331 newList[len - 1] = '\0';
3332 SetEnvironment("PATH", newList);
3334 printf("New value of PATH: %s\n", newList);
3341 #if defined(__unix__) || defined(__APPLE__)
3343 for(item : compiler.libraryDirs)
3345 if(!libPathExists[item]) // fstrcmp should be used
3347 String s = CopyString(item);
3349 libPathExists[s] = true;
3353 #if defined(__APPLE__)
3354 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3356 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3359 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3361 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3362 for(c = 0; c < count; c++)
3364 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3366 String s = CopyString(oldPaths[c]);
3368 libPathExists[s] = true;
3373 for(path : newLibPaths)
3374 len += strlen(path) + 1;
3375 newList = new char[len + 1];
3377 for(path : newLibPaths)
3379 strcat(newList, path);
3380 strcat(newList, pathListSep);
3382 newList[len - 1] = '\0';
3383 #if defined(__APPLE__)
3384 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3386 SetEnvironment("LD_LIBRARY_PATH", newList);
3389 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3395 delete libPathExists;
3398 if(compiler.distccEnabled && compiler.distccHosts)
3399 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3404 void DestroyTemporaryProjectDir()
3406 if(tmpPrjDir && tmpPrjDir[0])
3408 if(FileExists(tmpPrjDir).isDirectory)
3409 DestroyDir(tmpPrjDir);
3410 property::tmpPrjDir = null;
3416 // Graphics Driver Menu
3419 app.currentSkin.selectionColor = selectionColor;
3420 app.currentSkin.selectionText = selectionText;
3424 driverItems = new MenuItem[app.numDrivers];
3425 for(c = 0; c < app.numDrivers; c++)
3427 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3428 driverItems[c].id = c;
3429 driverItems[c].isRadio = true;
3432 driverItems = new MenuItem[2];
3433 #if defined(__unix__)
3434 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3435 driverItems[0].id = 0;
3436 driverItems[0].isRadio = true;
3438 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3439 driverItems[0].id = 0;
3440 driverItems[0].isRadio = true;
3442 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3443 driverItems[1].id = 1;
3444 driverItems[1].isRadio = true;
3446 /* skinItems = new MenuItem[app.numSkins];
3447 for(c = 0; c < app.numSkins; c++)
3449 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3450 skinItems[c].id = c;
3451 skinItems[c].isRadio = true;
3454 ideFileDialog.master = this;
3455 ideProjectFileDialog.master = this;
3457 //SetDriverAndSkin();
3461 void UpdateRecentMenus()
3464 Menu fileMenu = menu.FindMenu($"File");
3465 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3466 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3467 char * itemPath = new char[MAX_LOCATION];
3468 char * itemName = new char[MAX_LOCATION+4];
3470 recentFiles.Clear();
3473 for(recent : ideSettings.recentFiles)
3475 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3476 MakeSystemPath(itemPath);
3477 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3478 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3482 recentProjects.Clear();
3484 for(recent : ideSettings.recentProjects)
3486 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3487 MakeSystemPath(itemPath);
3488 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3489 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3501 delete languageItems;
3505 documentor.Puts("Quit\n");
3512 void DestroyDir(char * path)
3514 RecursiveDeleteFolderFSI fsi { };
3519 #if defined(__WIN32__)
3520 define sdkDirName = "Ecere SDK";
3522 define sdkDirName = "ecere";
3525 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3528 char * v = new char[maxPathLen];
3532 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3533 StripLastDirectory(path, path);
3534 PathCat(path, subDir);
3535 if(name) PathCat(path, name);
3536 if(FileExists(path) & attribs) found = true;
3538 #if defined(__WIN32__)
3541 GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3544 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3545 PathCat(path, subDir);
3546 if(name) PathCat(path, name);
3547 if(FileExists(path) & attribs) found = true;
3552 GetEnvironment("AppData", v, maxPathLen);
3555 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3556 PathCat(path, sdkDirName);
3557 PathCat(path, subDir);
3558 if(name) PathCat(path, name);
3559 if(FileExists(path) & attribs) found = true;
3564 GetEnvironment("ProgramData", v, maxPathLen);
3567 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3568 PathCat(path, sdkDirName);
3569 PathCat(path, subDir);
3570 if(name) PathCat(path, name);
3571 if(FileExists(path) & attribs) found = true;
3576 GetEnvironment("ProgramFiles", v, maxPathLen);
3579 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3580 PathCat(path, sdkDirName);
3581 PathCat(path, subDir);
3582 if(name) PathCat(path, name);
3583 if(FileExists(path) & attribs) found = true;
3588 GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3591 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3592 PathCat(path, sdkDirName);
3593 PathCat(path, subDir);
3594 if(name) PathCat(path, name);
3595 if(FileExists(path) & attribs) found = true;
3600 GetEnvironment("SystemDrive", v, maxPathLen);
3603 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3604 PathCat(path, "Program Files");
3605 PathCat(path, sdkDirName);
3606 PathCat(path, subDir);
3607 if(name) PathCat(path, name);
3608 if(FileExists(path) & attribs) found = true;
3618 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3619 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3622 p = new char[MAX_LOCATION];
3624 strcat(p, "/usr/share");
3628 for(c=0; c<numTokens; c++)
3630 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3631 PathCat(path, sdkDirName);
3632 PathCat(path, subDir);
3634 PathCat(path, name);
3635 if(FileExists(path) & attribs)
3648 void FindAndShellOpenInstalledFolder(const char * name)
3650 char path[MAX_LOCATION];
3651 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3655 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3657 char path[MAX_LOCATION];
3658 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3662 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3664 bool preserveRootFolder;
3666 void OutFolder(const char * folderPath, bool isRoot)
3668 if(!(preserveRootFolder && isRoot))
3669 RemoveDir(folderPath);
3672 bool OnFile(const char * filePath)
3674 DeleteFile(filePath);
3679 class IDEApp : GuiApplication
3681 //driver = "Win32Console";
3682 // driver = "OpenGL";
3686 TempFile includeFile { };
3691 char ext[MAX_EXTENSION];
3692 SetLoggingMode(stdOut, null);
3693 //SetLoggingMode(debug, null);
3695 settingsContainer.Load();
3697 if(ideSettings.language)
3699 const String language = GetLanguageString();
3700 if(ideSettings.language.OnCompare(language))
3702 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3707 // First count files arg to decide whether to maximize
3709 bool passThrough = false, debugWorkDir = false;
3712 for(c = 1; c<app.argc; c++)
3715 else if(debugWorkDir)
3716 debugWorkDir = false;
3717 else if(!strcmp(app.argv[c], "-t"));
3718 else if(!strcmp(app.argv[c], "-no-parsing"));
3719 else if(!strcmp(app.argv[c], "-debug-start"));
3720 else if(!strcmp(app.argv[c], "-debug-hide-ide"));
3721 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3722 debugWorkDir = true;
3723 else if(!strcmp(app.argv[c], "-@"))
3730 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3732 app.driver = "OpenGL";
3733 ide.driverItems[1].checked = true;
3737 #if defined(__unix__) || defined(__APPLE__)
3738 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3740 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3742 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3746 char model[MAX_LOCATION];
3747 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3749 ide.duck.modelFile = model;
3750 ide.duck.parent = ideMainFrame;
3753 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3754 ide.debugRubberDuck.disabled = false;
3758 desktop.caption = titleECEREIDE;
3761 for(c = 1; c<app.argc; c++)
3763 char fullPath[MAX_LOCATION];
3764 GetWorkingDir(fullPath, MAX_LOCATION);
3765 PathCat(fullPath, app.argv[c]);
3766 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3770 // Default to language specified by environment if no language selected
3771 if(!ideSettings.language)
3773 ideSettings.language = GetLanguageString();
3774 settingsContainer.Save();
3777 // Default to home directory if no directory yet set up
3778 if(!ideSettings.ideProjectFileDialogLocation[0])
3781 char location[MAX_LOCATION];
3782 char * home = getenv("HOME");
3783 char * homeDrive = getenv("HOMEDRIVE");
3784 char * homePath = getenv("HOMEPATH");
3785 char * userProfile = getenv("USERPROFILE");
3786 char * systemDrive = getenv("SystemDrive");
3787 if(home && FileExists(home).isDirectory)
3789 strcpy(location, home);
3792 if(!found && homeDrive && homePath)
3794 strcpy(location, homeDrive);
3795 PathCat(location, homePath);
3796 if(FileExists(location).isDirectory)
3799 if(!found && FileExists(userProfile).isDirectory)
3801 strcpy(location, userProfile);
3804 if(!found && FileExists(systemDrive).isDirectory)
3806 strcpy(location, systemDrive);
3811 ideSettings.ideProjectFileDialogLocation = location;
3812 if(!ideSettings.ideFileDialogLocation[0])
3813 ideSettings.ideFileDialogLocation = location;
3817 if(!LoadIncludeFile())
3818 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3820 // Create language menu
3822 String language = ideSettings.language;
3826 ide.languageItems = new MenuItem[languages.count];
3829 ide.languageItems[i] =
3831 ide.languageMenu, l.name;
3832 bitmap = { l.bitmap };
3836 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3838 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3840 // Re-select previous selected language if aborted
3841 String language = ideSettings.language;
3845 if(((!language || !language[0]) && i == 0) ||
3846 (language && !strcmpi(l.code, language)))
3848 ide.languageItems[i].checked = true;
3860 // Try to find country-specific language first
3866 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3868 ide.languageItems[i].checked = true;
3876 // Try generalizing locale
3877 if(!found && language)
3880 char genericLocale[256];
3882 strncpy(genericLocale, language, sizeof(genericLocale));
3883 genericLocale[sizeof(genericLocale)-1] = 0;
3885 under = strchr(genericLocale, '_');
3888 if(!strcmpi(genericLocale, "zh"))
3889 strcpy(genericLocale, "zh_CN");
3890 if(strcmp(genericLocale, language))
3894 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3896 ide.languageItems[i].checked = true;
3906 ide.languageItems[0].checked = true;
3908 MenuDivider { ide.languageMenu };
3911 ide.languageMenu, "Help Translate";
3913 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3915 ShellOpen("http://translations.launchpad.net/ecere");
3921 ideMainFrame.Create();
3922 if(app.argFilesCount > 1)
3923 ide.MenuWindowTileVert(null, 0);
3927 bool Cycle(bool idle)
3931 if(ide.documentor.Peek())
3934 ide.documentor.GetLine(line, sizeof(line));
3935 if(!strcmpi(line, "Exited"))
3937 ide.documentor.CloseInput();
3938 ide.documentor.CloseOutput();
3939 ide.documentor.Wait();
3940 delete ide.documentor;
3943 if(ide.documentor && ide.documentor.eof)
3945 ide.documentor.CloseInput();
3946 ide.documentor.CloseOutput();
3947 ide.documentor.Wait();
3948 delete ide.documentor;
3954 bool LoadIncludeFile()
3956 bool result = false;
3957 File include = FileOpen(":crossplatform.mk", read);
3960 File f = includeFile;
3963 for(; !include.Eof(); )
3966 int count = include.Read(buffer, 1, 4096);
3967 f.Write(buffer, 1, count);
3977 IDEMainFrame ideMainFrame { };
3979 define app = ((IDEApp)__thisModule);
3981 define titleECEREIDE = $"Ecere IDE (Debug)";
3983 define titleECEREIDE = $"Ecere IDE";