2 public import static "ecere"
3 public import static "ec"
9 import "GlobalSettingsDialog"
10 import "NewProjectDialog"
11 import "FindInFilesDialog"
18 import "ProjectConfig"
20 import "NodeProperties"
21 import "ProjectSettings"
33 import "BreakpointsView"
34 import "CallStackView"
45 import "FileSystemIterator"
47 AVLTree<const String> binaryDocExt
49 "wav", "mp3", "flac", "ogg",
51 "avi", "mkv", "mpg", "mpeg",
52 "7z", "zip", "gz", "bz2", "xz", "rar", "z", "tar", "ear",
53 "pdf", "odp", "ods", "odt", "ppt", "doc", "xls", "pptx", "docx", "xlsx"
56 #if defined(__WIN32__)
57 define pathListSep = ";";
59 define pathListSep = ":";
62 define maxPathLen = 65 * MAX_LOCATION;
64 class PathBackup : struct
71 oldPath = new char[maxPathLen];
72 oldLDPath = new char[maxPathLen];
74 GetEnvironment("PATH", oldPath, maxPathLen);
75 #if defined(__APPLE__)
76 GetEnvironment("DYLD_LIBRARY_PATH", oldLDPath, maxPathLen);
78 GetEnvironment("LD_LIBRARY_PATH", oldLDPath, maxPathLen);
84 SetEnvironment("PATH", oldPath);
85 #if defined(__APPLE__)
86 SetEnvironment("DYLD_LIBRARY_PATH", oldLDPath);
88 SetEnvironment("LD_LIBRARY_PATH", oldLDPath);
95 enum OpenCreateIfFails { no, yes, something, whatever };
96 enum OpenMethod { normal, add };
98 static Array<FileFilter> fileFilters
100 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
101 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
102 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
103 { $"Text files (*.txt, *.text, *.nfo, *.info)", "txt, text, nfo, info" },
104 { $"Web files (*.html, *.htm, *.xhtml, *.css, *.php, *.js, *.jsi, *.rb, *.xml)", "html, htm, xhtml, css, php, js, jsi, rb, xml" },
105 { $"Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", "jpg, jpeg, bmp, pcx, png, gif" },
106 { $"3D Studio Model Files (*.3ds)", "3ds" },
107 { $"All files", null }
110 static Array<FileType> fileTypes
112 { $"Based on extension", null },
115 { $"3D Studio Model", "3ds" }
118 static Array<FileFilter> projectFilters
120 { $"Project Files (*.epj)", ProjectExtension }
123 static Array<FileType> projectTypes
125 { $"Project File", ProjectExtension }
128 static Array<FileFilter> findInFilesFileFilters
130 { $"eC Files (*.ec, *.eh)", "ec, eh" },
131 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
132 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
133 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
134 { $"Text files (*.txt)", "txt" },
135 { $"All files", null }
138 FileDialog ideFileDialog
140 type = multiOpen, text = $"Open";
141 types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType), filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter);
144 define openProjectFileDialogTitle = $"Open Project";
145 define addProjectFileDialogTitle = $"Open Additional Project";
146 FileDialog ideProjectFileDialog
149 types = projectTypes.array, sizeTypes = projectTypes.count * sizeof(FileType), filters = projectFilters.array, sizeFilters = projectFilters.count * sizeof(FileFilter);
152 GlobalSettingsDialog globalSettingsDialog
154 ideSettings = ideSettings;
155 settingsContainer = settingsContainer;
157 void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange)
159 switch(globalSettingsChange)
164 for(child = ide.firstChild; child; child = child.next)
166 if(child._class == class(CodeEditor))
168 CodeEditor codeEditor = (CodeEditor) child;
169 codeEditor.editBox.freeCaret = ideSettings.useFreeCaret;
170 // codeEditor.editBox.lineNumbers = ideSettings.showLineNumbers;
171 codeEditor.editBox.caretFollowsScrolling = ideSettings.caretFollowsScrolling;
172 codeEditor.OnPostCreate(); // Update editBox margin size
179 case compilerSettings:
181 ide.UpdateCompilerConfigs(true);
188 void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
193 lineY = (line - 1) * lineH;
194 if(lineY + lineH > scrollY && lineY + lineH < scrollY + boxH)
196 Bitmap bitmap = resource.bitmap;
198 surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
203 #define IDEItem(x) (&((IDEWorkSpace)0).x)
205 class IDEToolbar : ToolBar
209 ToolButton buttonNewFile { this, toolTip = $"New file", menuItemPtr = IDEItem(fileNewItem) };
211 ToolButton buttonOpenFile { this, toolTip = $"Open file", menuItemPtr = IDEItem(fileOpenItem) };
213 // ToolButton buttonCloseFile { this, toolTip = $"Close file", menuItemPtr = IDEItem(fileCloseItem) };
215 ToolButton buttonSaveFile { this, toolTip = $"Save file", menuItemPtr = IDEItem(fileSaveItem) };
217 ToolButton buttonSaveAllFile { this, toolTip = $"Save all", menuItemPtr = IDEItem(fileSaveAllItem) };
219 ToolSeparator separator1 { this };
228 // ToolSeparator separator2 { this };
232 ToolButton buttonNewProject { this, toolTip = $"New project", menuItemPtr = IDEItem(projectNewItem) };
234 ToolButton buttonOpenProject { this, toolTip = $"Open project", menuItemPtr = IDEItem(projectOpenItem) };
235 // Add project to workspace
236 ToolButton buttonAddProject { this, toolTip = $"Add project to workspace", menuItemPtr = IDEItem(projectAddItem), disabled = true; };
238 // ToolButton buttonCloseProject { this, toolTip = $"Close project", menuItemPtr = IDEItem(projectCloseItem), disabled = true; };
240 ToolSeparator separator3 { this };
242 // Build/Execution options
244 ToolButton buttonBuild { this, toolTip = $"Build project", menuItemPtr = IDEItem(projectBuildItem), disabled = true; };
246 ToolButton buttonReLink { this, toolTip = $"Relink project", menuItemPtr = IDEItem(projectLinkItem), disabled = true; };
248 ToolButton buttonRebuild { this, toolTip = $"Rebuild project", menuItemPtr = IDEItem(projectRebuildItem), disabled = true; };
250 ToolButton buttonClean { this, toolTip = $"Clean project", menuItemPtr = IDEItem(projectCleanItem), disabled = true; };
252 // ToolButton buttonRealClean { this, toolTip = $"Real clean project", menuItemPtr = IDEItem(projectRealCleanItem), disabled = true; };
253 // Regenerate Makefile
254 ToolButton buttonRegenerateMakefile { this, toolTip = $"Regenerate Makefile", menuItemPtr = IDEItem(projectRegenerateItem), disabled = true; };
255 // Compile actual file
257 ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem), disabled = true; };
258 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
259 ToolButton buttonInstall { this, toolTip = $"Install", menuItemPtr = IDEItem(projectInstallItem), disabled = true; };
262 ToolSeparator separator4 { this };
266 ToolButton buttonDebugStartResume { this, toolTip = $"Start", menuItemPtr = IDEItem(debugStartResumeItem), disabled = true; };
268 ToolButton buttonDebugRestart { this, toolTip = $"Restart", menuItemPtr = IDEItem(debugRestartItem), disabled = true; };
270 ToolButton buttonDebugPause { this, toolTip = $"Break", menuItemPtr = IDEItem(debugBreakItem), disabled = true; };
272 ToolButton buttonDebugStop { this, toolTip = $"Stop", menuItemPtr = IDEItem(debugStopItem), disabled = true; };
274 //ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem) };
276 ToolButton buttonDebugStepInto { this, toolTip = $"Step Into", menuItemPtr = IDEItem(debugStepIntoItem), disabled = true; };
278 ToolButton buttonDebugStepOver { this, toolTip = $"Step Over", menuItemPtr = IDEItem(debugStepOverItem), disabled = true; };
280 ToolButton buttonDebugStepOut { this, toolTip = $"Step Out", menuItemPtr = IDEItem(debugStepOutItem), disabled = true; };
282 ToolButton buttonDebugSkipStepOver { this, toolTip = $"Step Over Skipping Breakpoints", menuItemPtr = IDEItem(debugSkipStepOverItem), disabled = true; };
284 ToolSeparator separator5 { this };
286 Window spacer5 { this, size = { 4 } };
290 this, toolTip = $"Active Configuration(s)", size = { 160 }, disabled = true;
291 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
294 ide.workspace.SelectActiveConfig(row.string);
299 Window spacer6 { this, size = { 4 } };
301 DropBox activeCompiler
303 this, toolTip = $"Active Compiler", size = { 160 }, disabled = true;
304 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
306 if(ide.workspace && ide.projectView && row && strcmp(row.string, ide.workspace.compiler))
308 bool silent = ide.projectView.buildInProgress == none ? false : true;
309 CompilerConfig compiler = ideSettings.GetCompilerConfig(row.string);
310 ide.workspace.compiler = row.string;
311 ide.projectView.ShowOutputBuildLog(!silent);
313 ide.projectView.DisplayCompiler(compiler, false);
314 for(prj : ide.workspace.projects)
315 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
317 ide.workspace.Save();
323 DropBox activeBitDepth
325 this, toolTip = $"Active Bit Length", size = { 60 }, disabled = true;
326 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
328 if(ide.workspace && ide.projectView && row)
330 bool silent = ide.projectView.buildInProgress == none ? false : true;
331 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
332 ide.workspace.bitDepth = (int)row.tag;
333 ide.projectView.ShowOutputBuildLog(!silent);
335 ide.projectView.DisplayCompiler(compiler, false);
336 for(prj : ide.workspace.projects)
337 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
339 ide.workspace.Save();
345 Window spacer7 { this, size = { 4 } };
350 row = activeBitDepth.AddString("Auto");
352 activeBitDepth.AddString("32 bit").tag = 32;
353 activeBitDepth.AddString("64 bit").tag = 64;
354 activeBitDepth.currentRow = row;
358 class IDEMainFrame : Window
360 background = formColor;
361 borderStyle = sizable;
365 minClientSize = { 600, 300 };
367 icon = { ":icon.png" };
368 text = titleECEREIDE;
372 anchor = { top = 0, right = 0, bottom = 0 };
375 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
382 isActiveClient = true;
384 direction = vertical;
385 background = formColor;
386 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
394 ((IDEWorkSpace)master).toolBar = null;
397 IDEWorkSpace ideWorkSpace { stack, this, toolBar = toolBar };
400 define ide = ideMainFrame.ideWorkSpace;
402 class IDEWorkSpace : Window
404 background = Color { 85, 85, 85 };
407 hasVertScroll = true;
408 hasHorzScroll = true;
410 isActiveClient = true;
411 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
415 MenuItem * driverItems, * skinItems, * languageItems;
416 StatusField pos { width = 150 };
417 StatusField ovr, caps, num;
420 BitmapResource back { ":ecereBack.jpg", window = this };
421 BitmapResource bmpBp { ":codeMarks/breakpoint.png", window = this };
422 BitmapResource bmpBpDisabled { ":codeMarks/breakpointDisabled.png", window = this };
423 BitmapResource bmpBpHalf { ":codeMarks/breakpointHalf.png", window = this };
424 BitmapResource bmpBpHalfDisabled { ":codeMarks/breakpointHalfDisabled.png", window = this };
425 BitmapResource bmpCursor { ":codeMarks/cursor.png", window = this };
426 BitmapResource bmpCursorError { ":codeMarks/cursorError.png", window = this };
427 BitmapResource bmpTopFrame { ":codeMarks/topFrame.png", window = this };
428 BitmapResource bmpTopFrameError { ":codeMarks/topFrameError.png", window = this };
429 BitmapResource bmpTopFrameHalf { ":codeMarks/topFrameHalf.png", window = this };
430 BitmapResource bmpTopFrameHalfError { ":codeMarks/topFrameHalfError.png", window = this };
432 Debugger debugger { };
434 ProjectView projectView;
436 OutputView outputView
440 void OnGotoError(const char * line, bool noParsing)
442 ide.GoToError(line, noParsing);
445 void OnCodeLocationParseAndGoTo(const char * line)
447 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir);
450 bool OnKeyDown(Key key, unichar ch)
455 if(activeBox != findBox || !ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
456 ide.ShowCodeEditor();
460 OutputView::OnKeyDown(key, ch);
467 bool OnClose(bool parentClosing)
471 ide.RepositionWindows(false);
472 return parentClosing;
476 CallStackView callStackView
478 parent = this, font = { panelFont.faceName, panelFont.size };
480 void OnSelectFrame(int frameIndex)
482 ide.debugger.GoToStackFrameLine(frameIndex, true, true);
484 ide.debugger.SelectFrame(frameIndex);
487 void OnToggleBreakpoint()
489 Debugger debugger = ide.debugger;
490 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
492 int line = debugger.activeFrame.line;
493 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line);
496 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
497 if(codeEditor) { codeEditor.Update(null); Activate(); }
502 bool OnKeyDown(Key key, unichar ch)
506 case escape: ide.ShowCodeEditor(); break;
511 bool OnClose(bool parentClosing)
515 ide.RepositionWindows(false);
516 return parentClosing;
519 void OnRedraw(Surface surface)
521 Debugger debugger = ide.debugger;
522 Frame activeFrame = debugger.activeFrame;
526 int lineCursor, lineTopFrame;
527 int lineH, scrollY, boxH;
529 Breakpoint bp = null;
532 scrollY = editBox.scroll.y;
533 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
534 //activeThread = debugger.activeThread;
535 //hitThread = debugger.hitThread;
536 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
538 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
539 if(activeFrame.absoluteFile)
541 for(i : ide.workspace.breakpoints; i.type == user)
543 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
544 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
545 activeFrame.line == i.line)
553 DrawLineMarginIcon(surface,
554 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
555 lineCursor /*1*/, lineH, scrollY, boxH);
557 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
558 DrawLineMarginIcon(surface,
559 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
560 1, lineH, scrollY, boxH);
562 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
563 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
564 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
566 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
567 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
569 if(editBox.horzScroll && editBox.horzScroll.visible)
571 surface.SetBackground(control);
572 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
577 WatchesView watchesView { parent = this };
578 ThreadsView threadsView
580 parent = this, font = { panelFont.faceName, panelFont.size };
582 bool OnKeyDown(Key key, unichar ch)
586 case escape: ide.ShowCodeEditor(); break;
591 bool OnClose(bool parentClosing)
595 ide.RepositionWindows(false);
596 return parentClosing;
599 void OnSelectThread(int threadId)
602 ide.debugger.SelectThread(threadId);
605 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
608 Debugger debugger = ide.debugger;
609 *activeThread = debugger.activeThread;
610 *hitThread = debugger.hitThread;
611 *signalThread = debugger.signalThread;
616 BreakpointsView breakpointsView { parent = this };
618 ToolBox toolBox { parent = this, visible = false };
619 Sheet sheet { parent = this, visible = false };
622 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
624 Menu fileMenu { menu, $"File", f, hasMargin = true };
627 fileMenu, $"New", n, ctrlN;
628 bitmap = { ":actions/docNew.png" };
629 bool NotifySelect(MenuItem selection, Modifiers mods)
631 Window currentDoc = activeClient;
632 bool maximizeDoc = ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
633 Window document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, false);
634 RepositionWindows(false);
635 document.NotifySaved = DocumentSaved;
639 MenuItem fileOpenItem
641 fileMenu, $"Open...", o, ctrlO;
642 bitmap = { ":actions/docOpen.png" };
643 bool NotifySelect(MenuItem selection, Modifiers mods)
645 if(!projectView && ideSettings.ideFileDialogLocation)
646 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
649 if(ideFileDialog.Modal() == ok)
651 bool gotWhatWeWant = false;
653 int numSelections = ideFileDialog.numSelections;
654 const char * const * multiFilePaths = ideFileDialog.multiFilePaths;
656 for(c = 0; c < numSelections; c++)
658 if(OpenFile(multiFilePaths[c], false, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
659 gotWhatWeWant = true;
662 MessageBox { type = yesNo, master = this, text = $"Error opening file",
663 contents = $"Open a different file?" }.Modal() == no)
665 if(!projectView && gotWhatWeWant)
666 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
667 ide.RepositionWindows(false);
677 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
678 MenuDivider { fileMenu };
679 MenuItem fileSaveItem
681 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
683 // For the toolbar button; clients can still override that for the menu item
684 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
686 Window w = activeClient;
688 w.MenuFileSave(null, 0);
692 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
693 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
694 MenuDivider { fileMenu };
697 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
698 bool NotifySelect(MenuItem selection, Modifiers mods)
700 findInFilesDialog.replaceMode = false;
701 findInFilesDialog.Show();
705 MenuItem replaceInFiles
707 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
708 bool NotifySelect(MenuItem selection, Modifiers mods)
710 findInFilesDialog.replaceMode = true;
711 findInFilesDialog.Show();
715 MenuDivider { fileMenu };
716 MenuItem globalSettingsItem
718 fileMenu, $"Global Settings...", g;
719 bool NotifySelect(MenuItem selection, Modifiers mods)
721 globalSettingsDialog.master = this;
722 if(ide.workspace && ide.workspace.compiler)
723 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.compiler;
724 else if(ideSettings.defaultCompiler)
725 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
726 globalSettingsDialog.Modal();
730 MenuDivider { fileMenu };
731 Menu recentFiles { fileMenu, $"Recent Files", r };
732 Menu recentProjects { fileMenu, $"Recent Projects", p };
733 MenuDivider { fileMenu };
736 fileMenu, $"Exit", x, altF4;
738 bool NotifySelect(MenuItem selection, Modifiers mods)
740 ideMainFrame.Destroy(0);
745 bool FileRecentFile(MenuItem selection, Modifiers mods)
748 for(file : ideSettings.recentFiles)
750 if(id == selection.id)
753 char extension[MAX_EXTENSION] = "";
754 GetExtension(file, extension);
755 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
758 char * command = PrintString("ide ", isProjectFile ? "-t " : "", file);
764 OpenFile(file, false, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
765 ide.RepositionWindows(false);
774 bool FileRecentProject(MenuItem selection, Modifiers mods)
777 for(file : ideSettings.recentProjects)
779 if(id == selection.id)
783 char * command = PrintString("ide ", file);
788 OpenFile(file, false, true, null, no, normal, mods.ctrl && mods.shift);
796 MenuPlacement editMenu { menu, $"Edit", e };
798 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
799 MenuItem projectNewItem
801 projectMenu, $"New...", n, Key { n, true, true };
802 bitmap = { ":actions/projNew.png" };
803 bool NotifySelect(MenuItem selection, Modifiers mods)
805 if(!DontTerminateDebugSession($"New Project"))
808 NewProjectDialog newProjectDialog { master = this };
809 incref newProjectDialog;
810 result = newProjectDialog.Modal();
815 newProjectDialog.CreateNewProject();
818 ideSettings.AddRecentProject(projectView.fileName);
819 ide.UpdateRecentMenus();
820 settingsContainer.Save();
824 delete newProjectDialog;
829 MenuItem projectOpenItem
831 projectMenu, $"Open...", o, Key { o, true, true };
832 bitmap = { ":actions/projOpen.png" };
833 bool NotifySelect(MenuItem selection, Modifiers mods)
835 if(ideSettings.ideProjectFileDialogLocation)
836 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
838 ideProjectFileDialog.text = openProjectFileDialogTitle;
839 if(ideProjectFileDialog.Modal() == ok)
841 OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
842 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
847 MenuItem projectQuickItem
849 projectMenu, $"Quick...", q, f7, disabled = true;
850 bool NotifySelect(MenuItem selection, Modifiers mods)
853 QuickProjectDialog { this }.Modal();
857 MenuItem projectAddItem
859 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
860 bitmap = { ":actions/projAdd.png" };
862 bool NotifySelect(MenuItem selection, Modifiers mods)
864 if(ideSettings.ideProjectFileDialogLocation)
865 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
867 ideProjectFileDialog.text = addProjectFileDialogTitle;
870 if(ideProjectFileDialog.Modal() == ok)
872 if(OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
874 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
875 contents = $"Add a different project?" }.Modal() == no)
886 MenuItem projectCloseItem
888 projectMenu, $"Close", c, disabled = true;
889 bool NotifySelect(MenuItem selection, Modifiers mods)
893 if(!ide.DontTerminateDebugSession($"Project Close"))
899 MenuDivider { projectMenu };
900 MenuItem projectSettingsItem
902 projectMenu, $"Settings...", s, altF7, disabled = true;
903 bool NotifySelect(MenuItem selection, Modifiers mods)
905 projectView.MenuSettings(projectView.active ? selection : null, mods);
909 MenuDivider { projectMenu };
910 MenuItem projectBrowseFolderItem
912 projectMenu, $"Browse Project Folder", p, disabled = true;
913 bool NotifySelect(MenuItem selection, Modifiers mods)
916 projectView.MenuBrowseFolder(null, mods);
920 MenuDivider { projectMenu };
921 MenuItem projectRunItem
923 projectMenu, $"Run", r, ctrlF5, disabled = true;
924 bitmap = { ":actions/run.png" };
925 bool NotifySelect(MenuItem selection, Modifiers mods)
928 projectView.Run(null, mods);
932 MenuItem projectBuildItem
934 projectMenu, $"Build", b, f7, disabled = true;
935 bitmap = { ":actions/build.png" };
936 bool NotifySelect(MenuItem selection, Modifiers mods)
940 if(projectView.buildInProgress == none)
941 projectView.ProjectBuild(projectView.active ? selection : null, mods);
943 projectView.stopBuild = true;
948 MenuItem projectLinkItem
950 projectMenu, $"Relink", l, disabled = true;
951 bitmap = { ":actions/relink.png" };
952 bool NotifySelect(MenuItem selection, Modifiers mods)
955 projectView.ProjectLink(projectView.active ? selection : null, mods);
959 MenuItem projectRebuildItem
961 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
962 bitmap = { ":actions/rebuild.png" };
963 bool NotifySelect(MenuItem selection, Modifiers mods)
966 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
970 MenuItem projectCleanTargetItem
972 projectMenu, $"Clean Target", g, disabled = true;
973 bitmap = { ":actions/clean.png" };
974 bool NotifySelect(MenuItem selection, Modifiers mods)
979 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
984 MenuItem projectCleanItem
986 projectMenu, $"Clean", e, disabled = true;
987 bitmap = { ":actions/clean.png" };
988 bool NotifySelect(MenuItem selection, Modifiers mods)
993 projectView.ProjectClean(projectView.active ? selection : null, mods);
998 MenuItem projectRealCleanItem
1000 projectMenu, $"Real Clean", disabled = true;
1001 bitmap = { ":actions/clean.png" };
1002 bool NotifySelect(MenuItem selection, Modifiers mods)
1007 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1012 MenuItem projectRegenerateItem
1014 projectMenu, $"Regenerate Makefile", m, disabled = true;
1015 bitmap = { ":actions/regMakefile.png" };
1016 bool NotifySelect(MenuItem selection, Modifiers mods)
1019 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1023 MenuItem projectInstallItem
1025 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
1026 projectMenu, $"Install", t, disabled = true;
1028 bitmap = { ":status/software-update-available.png" };
1029 bool NotifySelect(MenuItem selection, Modifiers mods)
1032 projectView.ProjectInstall(projectView.active ? selection : null, mods);
1036 MenuItem projectCompileItem;
1037 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1038 MenuItem debugStartResumeItem
1040 debugMenu, $"Start", s, f5, disabled = true;
1041 bitmap = { ":actions/debug.png" };
1042 NotifySelect = MenuDebugStart;
1044 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1048 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1049 if(!projectView.DebugStart())
1050 debugStartResumeItem.disabled = false; // same exception
1054 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1057 projectView.DebugResume();
1060 MenuItem debugRestartItem
1062 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1063 bitmap = { ":actions/restart.png" };
1064 bool NotifySelect(MenuItem selection, Modifiers mods)
1067 projectView.DebugRestart();
1071 MenuItem debugBreakItem
1073 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1074 bitmap = { ":actions/pause.png" };
1075 bool NotifySelect(MenuItem selection, Modifiers mods)
1077 if(projectView && projectView.buildInProgress != none)
1080 projectView.DebugBreak();
1084 MenuItem debugStopItem
1086 debugMenu, $"Stop", p, shiftF5, disabled = true;
1087 bitmap = { ":actions/stopDebug.png" };
1088 bool NotifySelect(MenuItem selection, Modifiers mods)
1091 projectView.DebugStop();
1095 MenuDivider { debugMenu };
1099 // nonClient = true,
1106 anchor = { right = 0, bottom = 0 },
1108 isActiveClient = false,
1110 clickThrough = true,
1111 size = { 500, 500 };
1113 bool OnLoadGraphics()
1115 ModelView::OnLoadGraphics();
1116 camera.position.z /= 1.3;
1117 camera.orientation = Euler { yaw = 280, pitch = 20 };
1123 bool OnRightButtonDown(int x, int y, Modifiers mods)
1125 if(!displaySystem.flags.flipping) return true;
1126 MenuWindowMove(null, 0);
1130 bool OnRightButtonUp(int x, int y, Modifiers mods)
1132 position = position;
1137 MenuItem debugRubberDuck
1139 debugMenu, $"Rubber Duck", checkable = true, disabled = true;
1140 bool NotifySelect(MenuItem selection, Modifiers mods)
1142 if(selection.checked)
1150 MenuDivider { debugMenu };
1151 MenuItem debugUseValgrindItem
1153 debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
1154 bool NotifySelect(MenuItem selection, Modifiers mods)
1158 ide.workspace.useValgrind = selection.checked;
1159 ide.workspace.Save();
1161 ide.AdjustValgrindMenus();
1165 Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
1166 MenuItem debugValgrindNoLeakCheckItem { debugValgrindLeakCheckItem, $"No" , f, id = ValgrindLeakCheck::no , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1167 MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; };
1168 MenuItem debugValgrindYesLeakCheckItem { debugValgrindLeakCheckItem, $"Yes" , f, id = ValgrindLeakCheck::yes , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1169 MenuItem debugValgrindFullLeakCheckItem { debugValgrindLeakCheckItem, $"Full" , f, id = ValgrindLeakCheck::full , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1170 bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
1174 if(selection.checked)
1176 ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
1178 debugValgrindNoLeakCheckItem.checked = debugValgrindNoLeakCheckItem.id == vgLeakCheck;
1179 debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
1180 debugValgrindYesLeakCheckItem.checked = debugValgrindYesLeakCheckItem.id == vgLeakCheck;
1181 debugValgrindFullLeakCheckItem.checked = debugValgrindFullLeakCheckItem.id == vgLeakCheck;
1183 ide.workspace.vgLeakCheck = vgLeakCheck;
1184 ide.workspace.Save();
1187 selection.checked = true;
1191 Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
1192 MenuItem debugValgrindRSDefaultItem { debugValgrindRedzoneSizeItem, $"Default", f, id = -1, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; };
1193 MenuItem debugValgrindRS0Item { debugValgrindRedzoneSizeItem, "0" , f, id = 0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1194 MenuItem debugValgrindRS16Item { debugValgrindRedzoneSizeItem, "16" , f, id = 16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1195 MenuItem debugValgrindRS32Item { debugValgrindRedzoneSizeItem, "32" , f, id = 32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1196 MenuItem debugValgrindRS64Item { debugValgrindRedzoneSizeItem, "64" , f, id = 64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1197 MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, "128" , f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1198 MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, "256" , f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1199 MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, "512" , f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1200 bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
1204 if(selection.checked)
1206 int vgRedzoneSize = (int)selection.id;
1208 debugValgrindRSDefaultItem.checked = debugValgrindRSDefaultItem.id == vgRedzoneSize;
1209 debugValgrindRS0Item.checked = debugValgrindRS0Item.id == vgRedzoneSize;
1210 debugValgrindRS16Item.checked = debugValgrindRS16Item.id == vgRedzoneSize;
1211 debugValgrindRS32Item.checked = debugValgrindRS32Item.id == vgRedzoneSize;
1212 debugValgrindRS64Item.checked = debugValgrindRS64Item.id == vgRedzoneSize;
1213 debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
1214 debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
1215 debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
1217 ide.workspace.vgRedzoneSize = vgRedzoneSize;
1218 ide.workspace.Save();
1221 selection.checked = true;
1225 MenuItem debugValgrindTrackOriginsItem
1227 debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
1228 bool NotifySelect(MenuItem selection, Modifiers mods)
1232 ide.workspace.vgTrackOrigins = selection.checked;
1233 ide.workspace.Save();
1239 MenuDivider { debugMenu };
1240 MenuItem debugStepIntoItem
1242 debugMenu, $"Step Into", i, f11, disabled = true;
1243 bitmap = { ":actions/stepInto.png" };
1244 bool NotifySelect(MenuItem selection, Modifiers mods)
1246 if(projectView) projectView.DebugStepInto();
1250 MenuItem debugStepOverItem
1252 debugMenu, $"Step Over", v, f10, disabled = true;
1253 bitmap = { ":actions/stepOver.png" };
1254 bool NotifySelect(MenuItem selection, Modifiers mods)
1256 if(projectView) projectView.DebugStepOver(false);
1260 MenuItem debugSkipStepOverItem
1262 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1263 bitmap = { ":actions/stepOverSkipBreak.png" };
1264 bool NotifySelect(MenuItem selection, Modifiers mods)
1266 if(projectView) projectView.DebugStepOver(true);
1270 MenuItem debugStepOutItem
1272 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1273 bitmap = { ":actions/stepOut.png" };
1274 bool NotifySelect(MenuItem selection, Modifiers mods)
1276 if(projectView) projectView.DebugStepOut(false);
1280 MenuItem debugSkipStepOutItem
1282 debugMenu, $"Step Out Skipping Breakpoints", n, Key { f11, ctrl = true, shift = true }, disabled = true;
1283 bitmap = { ":actions/skipBreaks.png" };
1284 bool NotifySelect(MenuItem selection, Modifiers mods)
1286 if(projectView) projectView.DebugStepOut(true);
1291 MenuItem debugStepUntilItem
1293 debugMenu, $"Step Over Until Next Line", x, disabled = true;
1294 bool NotifySelect(MenuItem selection, Modifiers mods)
1296 if(projectView) projectView.DebugStepUntil(false);
1300 MenuItem debugSkipStepUntilItem
1302 debugMenu, $"Step Over Until Next Line Skipping Breakpoints", e, Key { f10, shift = true, alt = true }, disabled = true;
1303 bool NotifySelect(MenuItem selection, Modifiers mods)
1305 if(projectView) projectView.DebugStepUntil(true);
1310 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1311 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1312 MenuPlacement debugRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level", l };
1313 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", g };
1315 MenuPlacement debugBpRunToCursorItem { debugMenu, $"BP Run To Cursor" };
1316 MenuPlacement debugBpSkipRunToCursorItem { debugMenu, $"BP Run To Cursor Skipping Breakpoints" };
1317 MenuPlacement debugBpRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level" };
1318 MenuPlacement debugBpSkipRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level Skipping Breakpoints" };
1320 //MenuDivider { debugMenu };
1321 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1322 MenuPlacement imageMenu { menu, $"Image", i };
1323 Menu viewMenu { menu, $"View", v };
1324 MenuItem viewProjectItem
1326 viewMenu, $"Project View", j, alt0, disabled = true;
1327 bool NotifySelect(MenuItem selection, Modifiers mods)
1331 projectView.visible = true;
1332 projectView.Activate();
1337 MenuPlacement { viewMenu, $"View Designer" };
1338 MenuPlacement { viewMenu, $"View Code" };
1339 MenuPlacement { viewMenu, $"View Properties" };
1340 MenuPlacement { viewMenu, $"View Methods" };
1341 MenuItem viewDesignerItem
1343 viewMenu, $"View Designer", d, f8;
1344 bool NotifySelect(MenuItem selection, Modifiers mods)
1346 Window client = activeClient;
1347 Class dataType = client._class;
1348 if(!strcmp(dataType.name, "Designer"))
1350 client.visible = true;
1354 ((CodeEditor)client).ViewDesigner();
1358 MenuItem viewCodeItem
1360 viewMenu, $"View Code", c, f8;
1361 bool NotifySelect(MenuItem selection, Modifiers mods)
1363 Window client = activeClient;
1364 Class dataType = client._class;
1365 if(!strcmp(dataType.name, "Designer"))
1366 client = ((Designer)client).codeEditor;
1369 // Do this after so the caret isn't moved yet...
1370 client.visible = true;
1374 MenuItem viewPropertiesItem
1376 viewMenu, $"View Properties", p, f4;
1377 bool NotifySelect(MenuItem selection, Modifiers mods)
1379 sheet.visible = true;
1380 sheet.sheetSelected = properties;
1385 MenuItem viewMethodsItem
1387 viewMenu, $"View Methods", m, f4;
1388 bool NotifySelect(MenuItem selection, Modifiers mods)
1390 sheet.visible = true;
1391 sheet.sheetSelected = methods;
1396 MenuItem viewToolBoxItem
1398 viewMenu, $"View Toolbox", x, f12;
1399 bool NotifySelect(MenuItem selection, Modifiers mods)
1401 toolBox.visible = true;
1406 MenuItem viewOutputItem
1408 viewMenu, $"Output", o, alt2;
1409 bool NotifySelect(MenuItem selection, Modifiers mods)
1415 MenuItem viewWatchesItem
1417 viewMenu, $"Watches", w, alt3;
1418 bool NotifySelect(MenuItem selection, Modifiers mods)
1424 MenuItem viewThreadsItem
1426 viewMenu, $"Threads", t, alt4;
1427 bool NotifySelect(MenuItem selection, Modifiers mods)
1433 MenuItem viewBreakpointsItem
1435 viewMenu, $"Breakpoints", b, alt5;
1436 bool NotifySelect(MenuItem selection, Modifiers mods)
1438 breakpointsView.Show();
1442 MenuItem viewCallStackItem
1444 viewMenu, $"Call Stack", s, alt7;
1445 bool NotifySelect(MenuItem selection, Modifiers mods)
1447 callStackView.Show();
1451 MenuItem viewAllDebugViews
1453 viewMenu, $"All Debug Views", a, alt9;
1454 bool NotifySelect(MenuItem selection, Modifiers mods)
1459 callStackView.Show();
1460 breakpointsView.Show();
1464 #ifdef GDB_DEBUG_GUI
1465 MenuDivider { viewMenu };
1466 MenuItem viewGDBItem
1468 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1469 bool NotifySelect(MenuItem selection, Modifiers mods)
1476 MenuDivider { viewMenu };
1477 MenuItem viewColorPicker
1479 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1480 bool NotifySelect(MenuItem selection, Modifiers mods)
1482 ColorPicker colorPicker { master = this };
1483 colorPicker.Modal();
1487 MenuDivider { viewMenu };
1491 viewMenu, "Full Screen", f, checkable = true;
1493 bool NotifySelect(MenuItem selection, Modifiers mods)
1495 app.fullScreen ^= true;
1497 anchor = { 0, 0, 0, 0 };
1502 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1504 MenuDivider { viewMenu };
1506 Menu languageMenu { viewMenu, "Language", l };
1508 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1509 Menu windowMenu { menu, $"Window", w };
1510 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1511 MenuDivider { windowMenu };
1512 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1513 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1514 MenuDivider { windowMenu };
1515 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1516 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1517 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1518 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1519 MenuDivider { windowMenu };
1520 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1521 Menu helpMenu { menu, $"Help", h };
1524 helpMenu, $"API Reference", r, f1;
1525 bool NotifySelect(MenuItem selection, Modifiers mods)
1529 char * p = new char[MAX_LOCATION];
1531 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1532 PathCat(p, "documentor");
1533 #if defined(__WIN32__)
1534 ChangeExtension(p, "exe", p);
1536 if(!FileExists(p).isFile)
1537 strcpy(p, "documentor");
1539 documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
1544 Process_ShowWindows(documentor.GetProcessID());
1545 // documentor.Puts("Activate\n");
1550 MenuDivider { helpMenu };
1553 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1554 bool NotifySelect(MenuItem selection, Modifiers mods)
1556 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1560 MenuDivider { helpMenu };
1563 helpMenu, $"Documentation Folder", d;
1564 bool NotifySelect(MenuItem selection, Modifiers mods)
1566 FindAndShellOpenInstalledFolder("doc");
1572 helpMenu, $"Samples Folder", s;
1573 bool NotifySelect(MenuItem selection, Modifiers mods)
1575 FindAndShellOpenInstalledFolder("samples");
1581 helpMenu, $"Extras Folder", x;
1582 bool NotifySelect(MenuItem selection, Modifiers mods)
1584 FindAndShellOpenInstalledFolder("extras");
1588 MenuDivider { helpMenu };
1591 helpMenu, $"Community Forums", f;
1592 bool NotifySelect(MenuItem selection, Modifiers mods)
1594 ShellOpen("http://ecere.com/forums");
1598 MenuDivider { helpMenu };
1601 helpMenu, $"About...", a;
1602 bool NotifySelect(MenuItem selection, Modifiers mods)
1604 AboutIDE { master = this }.Modal();
1609 property ToolBox toolBox
1611 get { return toolBox; }
1614 property Sheet sheet
1616 get { return sheet; }
1619 property Project project
1621 get { return projectView ? projectView.project : null; }
1624 property Workspace workspace
1626 get { return projectView ? projectView.workspace : null; }
1629 FindInFilesDialog findInFilesDialog
1632 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1638 #ifdef GDB_DEBUG_GUI
1641 master = this, parent = this;
1642 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1644 void OnCommand(const char * string)
1647 ide.debugger.SendGDBCommand(string);
1652 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1654 //app.driver = app.drivers[selection.id];
1655 #if defined(__unix__) || defined(__APPLE__)
1656 app.driver = selection.id ? "OpenGL" : "X";
1658 app.driver = selection.id ? "OpenGL" : "GDI";
1660 delete ideSettings.displayDriver;
1661 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1663 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1665 settingsContainer.Save();
1666 //SetDriverAndSkin();
1670 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1672 app.skin = app.skins[selection.id];
1677 void SetDriverAndSkin()
1680 for(c = 0; c < app.numSkins; c++)
1681 if(!strcmp(app.skins[c], app.skin))
1683 skinItems[c].checked = true;
1686 for(c = 0; c < app.numDrivers; c++)
1687 if(!strcmp(app.drivers[c], app.driver))
1689 driverItems[c].checked = true;
1694 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1696 Project project = workspace.projects.firstIterator.data;
1697 projectView = ProjectView
1700 fileName = fileName;
1702 void NotifyDestroyed(Window window, DialogResult result)
1705 text = titleECEREIDE;
1710 projectView.Create();
1711 RepositionWindows(false);
1713 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1714 projectView.workspace = workspace;
1715 projectView.project = project;
1716 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1720 ide.breakpointsView.LoadFromWorkspace();
1721 ide.watchesView.LoadFromWorkspace();
1723 findInFilesDialog.projectNodeField.userData = projectView;
1726 char fileName[MAX_LOCATION];
1727 strcpy(fileName, project.topNode.path);
1728 PathCat(fileName, project.topNode.name);
1735 projectView.visible = false;
1736 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1738 if(findInFilesDialog)
1740 char workingDir[MAX_LOCATION];
1741 GetWorkingDir(workingDir, MAX_LOCATION);
1742 findInFilesDialog.SearchStop();
1743 findInFilesDialog.currentDirectory = workingDir;
1745 sheet.visible = false;
1746 toolBox.visible = false;
1747 outputView.visible = false;
1748 ideMainFrame.text = titleECEREIDE;
1755 void RepositionWindows(bool expand)
1760 bool callStackVisible = expand ? false : callStackView.visible;
1761 bool threadsVisible = expand ? false : threadsView.visible;
1762 bool watchesVisible = expand ? false : watchesView.visible;
1763 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1764 bool toolBoxVisible = toolBox.visible;
1765 bool outputVisible = expand ? false : outputView.visible;
1766 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1767 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1769 for(child = firstChild; child; child = child.next)
1771 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1772 child._class == class(Sheet) || child._class == class(ProjectView))
1774 Anchor anchor = child.anchor;
1775 anchor.top = topDistance;
1776 anchor.bottom = bottomDistance;
1777 if(child._class == class(CodeEditor) || child._class == class(Designer))
1779 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1780 anchor.right = toolBoxVisible ? 150 : 0;
1783 child.anchor = anchor;
1787 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1788 child._class == class(BreakpointsView))
1789 child.visible = false;
1792 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1794 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1798 bool ShowCodeEditor()
1801 activeClient.Activate();
1802 else if(projectView)
1804 projectView.visible = true;
1805 projectView.Activate();
1807 else if(sheet.visible)
1810 outputView.visible = false;
1814 void DocumentSaved(Window document, const char * fileName)
1816 ideSettings.AddRecentFile(fileName);
1817 ide.UpdateRecentMenus();
1818 ide.AdjustFileMenus();
1819 settingsContainer.Save();
1822 bool Window::OnFileModified(FileChange fileChange, const char * param)
1825 sprintf(temp, $"The document %s was modified by another application.\n"
1826 "Would you like to reload it and lose your changes?", this.fileName);
1827 if(MessageBox { type = yesNo, master = this/*.parent*/,
1828 text = $"Document has been modified", contents = temp }.Modal() == yes)
1830 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1831 char * fileName = CopyString(this.fileName);
1832 WindowState state = this.state;
1833 Anchor anchor = this.anchor;
1834 Size size = this.size;
1836 this.modifiedDocument = false;
1838 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1841 this.anchor = anchor;
1843 this.SetState(state, true, 0);
1851 void UpdateMakefiles()
1855 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1856 for(prj : workspace.projects)
1857 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1862 void UpdateCompilerConfigs(bool mute)
1864 UpdateToolBarActiveCompilers();
1867 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1868 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1871 projectView.ShowOutputBuildLog(true);
1872 projectView.DisplayCompiler(compiler, false);
1874 for(prj : workspace.projects)
1875 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1880 void UpdateToolBarActiveCompilers()
1882 toolBar.activeCompiler.Clear();
1883 for(compiler : ideSettings.compilerConfigs)
1885 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1886 if(workspace && workspace.compiler && !strcmp(compiler.name, workspace.compiler))
1887 toolBar.activeCompiler.currentRow = row;
1889 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1890 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1893 void UpdateToolBarActiveConfigs(bool selectionOnly)
1895 bool commonSelected = false;
1896 DataRow row = toolBar.activeConfig.currentRow;
1898 row = toolBar.activeConfig.FindRow(1);
1901 toolBar.activeConfig.Clear();
1902 row = toolBar.activeConfig.AddString($"(Mixed)");
1907 char * configName = null;
1910 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1911 for(prj : workspace.projects)
1913 for(cfg : prj.configurations)
1916 configs[cfg.name] = 1;
1921 toolBar.activeConfig.AddString(&name);
1925 if(projectView && projectView.project)
1927 for(prj : workspace.projects)
1929 if(prj.config && prj.config.name)
1931 configName = prj.config.name;
1937 commonSelected = true;
1938 for(prj : workspace.projects)
1940 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1942 commonSelected = false;
1950 commonSelected = false;
1951 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1953 if(!strcmp(row.string, configName))
1955 toolBar.activeConfig.currentRow = row;
1956 commonSelected = true;
1963 toolBar.activeConfig.Sort(null, 0);
1965 toolBar.activeConfig.currentRow = row;
1970 bool unavailable = !project;
1972 projectAddItem.disabled = unavailable;
1973 toolBar.buttonAddProject.disabled = unavailable;
1975 projectSettingsItem.disabled = unavailable;
1977 projectBrowseFolderItem.disabled = unavailable;
1979 viewProjectItem.disabled = unavailable;
1981 toolBar.activeConfig.disabled = unavailable;
1982 toolBar.activeCompiler.disabled = unavailable;
1983 toolBar.activeBitDepth.disabled = unavailable;
1986 debugUseValgrindItem.disabled = unavailable;
1987 AdjustValgrindMenus();
1996 void AdjustValgrindMenus()
1998 bool unavailable = !project || !debugUseValgrindItem.checked;
1999 debugValgrindNoLeakCheckItem.disabled = unavailable;
2000 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2001 debugValgrindYesLeakCheckItem.disabled = unavailable;
2002 debugValgrindFullLeakCheckItem.disabled = unavailable;
2004 debugValgrindTrackOriginsItem.disabled = unavailable;
2006 debugValgrindRSDefaultItem.disabled = unavailable;
2007 debugValgrindRS0Item.disabled = unavailable;
2008 debugValgrindRS16Item.disabled = unavailable;
2009 debugValgrindRS32Item.disabled = unavailable;
2010 debugValgrindRS64Item.disabled = unavailable;
2011 debugValgrindRS128Item.disabled = unavailable;
2012 debugValgrindRS256Item.disabled = unavailable;
2013 debugValgrindRS512Item.disabled = unavailable;
2017 property bool hasOpenedCodeEditors
2022 for(w = firstChild; w; w = w.next)
2023 if(w._class == class(CodeEditor) &&
2024 w.isDocument && !w.closing && w.visible && w.created &&
2025 w.fileName && w.fileName[0])
2031 void AdjustFileMenus()
2033 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2035 projectQuickItem.disabled = unavailable;
2038 void AdjustBuildMenus()
2040 bool unavailable = project && projectView.buildInProgress;
2041 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2043 projectNewItem.disabled = unavailable;
2044 toolBar.buttonNewProject.disabled = unavailable;
2045 projectOpenItem.disabled = unavailable;
2046 toolBar.buttonOpenProject.disabled = unavailable;
2048 unavailable = !project || projectView.buildInProgress;
2050 projectCloseItem.disabled = unavailable;
2051 // toolBar.buttonCloseProject.disabled = unavailable;
2053 projectRunItem.disabled = naForRun;
2054 toolBar.buttonRun.disabled = naForRun;
2056 projectBuildItem.disabled = false;
2057 projectBuildItem.text = unavailable ? $"Stop Build" : $"Build";
2058 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2060 projectLinkItem.disabled = unavailable;
2061 toolBar.buttonReLink.disabled = unavailable;
2062 projectRebuildItem.disabled = unavailable;
2063 toolBar.buttonRebuild.disabled = unavailable;
2064 projectCleanItem.disabled = unavailable;
2065 toolBar.buttonClean.disabled = unavailable;
2066 projectCleanTargetItem.disabled = unavailable;
2067 projectRealCleanItem.disabled = unavailable;
2068 // toolBar.buttonRealClean.disabled = unavailable;
2069 projectRegenerateItem.disabled = unavailable;
2070 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2071 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2072 projectInstallItem.disabled = unavailable;
2073 toolBar.buttonInstall.disabled = unavailable;
2075 projectCompileItem.disabled = unavailable;
2077 AdjustPopupBuildMenus();
2080 void AdjustPopupBuildMenus()
2082 bool unavailable = !project || projectView.buildInProgress;
2084 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2087 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
2090 menu.disabled = false;
2091 menu.text = unavailable ? $"Stop Build" : $"Build";
2092 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2095 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0); if(menu) menu.disabled = unavailable;
2096 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0); if(menu) menu.disabled = unavailable;
2097 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0); if(menu) menu.disabled = unavailable;
2098 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0); if(menu) menu.disabled = unavailable;
2099 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0); if(menu) menu.disabled = unavailable;
2100 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
2101 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, 0); if(menu) menu.disabled = unavailable;
2102 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0); if(menu) menu.disabled = unavailable;
2103 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0); if(menu) menu.disabled = unavailable;
2104 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0); if(menu) menu.disabled = unavailable;
2105 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0); if(menu) menu.disabled = unavailable;
2106 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0); if(menu) menu.disabled = unavailable;
2107 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
2108 projectView.popupMenu.Update(null);
2112 property bool areDebugMenusUnavailable { get {
2114 project.GetTargetType(project.config) != executable ||
2115 projectView.buildInProgress == buildingMainProject;
2118 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2119 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2120 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2122 void AdjustDebugMenus()
2124 bool unavailable = areDebugMenusUnavailable;
2125 bool running = isDebuggerRunning;
2126 bool stopped = isDebuggerStopped;
2127 bool active = debugger.isActive;
2129 bool isNotRunning = unavailable || !running;
2130 bool isNotNotRunning = unavailable || running;
2131 bool isNotStopped = unavailable || !stopped;
2132 bool isNotActive = unavailable || !active;
2134 debugStartResumeItem.disabled = isNotNotRunning;
2135 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2136 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2139 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2140 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2143 debugBreakItem.disabled = isNotRunning;
2144 debugStopItem.disabled = isNotActive;
2145 debugRestartItem.disabled = isNotActive;
2148 toolBar.buttonDebugPause.disabled = isNotRunning;
2149 toolBar.buttonDebugStop.disabled = isNotActive;
2150 toolBar.buttonDebugRestart.disabled = isNotActive;
2153 debugStepIntoItem.disabled = isNotNotRunning;
2154 debugStepOverItem.disabled = isNotNotRunning;
2155 debugSkipStepOverItem.disabled = isNotNotRunning;
2156 debugStepOutItem.disabled = isNotStopped;
2157 debugSkipStepOutItem.disabled = isNotStopped;
2159 debugStepUntilItem.disabled = isNotStopped;
2160 debugSkipStepUntilItem.disabled = isNotStopped;
2164 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2165 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2166 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2167 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2168 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2170 if((Designer)GetActiveDesigner())
2172 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2174 codeEditor.AdjustDebugMenus();
2178 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2180 char tempString[MAX_LOCATION];
2181 strcpy(tempString, directory);
2182 if(saveSettings && !projectView)
2184 ideSettings.ideFileDialogLocation = directory;
2185 settingsContainer.Save();
2188 ideFileDialog.currentDirectory = tempString;
2189 codeEditorFileDialog.currentDirectory = tempString;
2190 codeEditorFormFileDialog.currentDirectory = tempString;
2193 void ChangeProjectFileDialogDirectory(char * directory)
2195 ideSettings.ideProjectFileDialogLocation = directory;
2196 settingsContainer.Save();
2199 Window FindWindow(const char * filePath)
2201 Window document = null;
2203 // TOCHECK: Do we need to change slashes here?
2204 for(document = firstChild; document; document = document.next)
2206 const char * fileName = document.fileName;
2207 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2209 document.visible = true;
2210 document.Activate();
2217 bool DontTerminateDebugSession(const char * title)
2219 if(debugger.isActive)
2221 if(MessageBox { type = yesNo, master = ide,
2222 contents = $"Do you want to terminate the debugging session in progress?",
2223 text = title }.Modal() == no)
2226 MessageBox msg { type = yesNo, master = ide,
2227 contents = "Do you want to terminate the debugging session in progress?",
2229 if(msg.Modal() == no)
2241 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2243 char extension[MAX_EXTENSION] = "";
2244 Window document = null;
2245 bool isProject = false;
2246 bool needFileModified = true;
2247 char winFilePath[MAX_LOCATION];
2248 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2249 Window currentDoc = activeClient;
2250 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2253 GetExtension(filePath, extension);
2257 strcpy(extension, type);
2259 if(strcmp(extension, ProjectExtension))
2261 for(document = firstChild; document; document = document.next)
2263 const char * fileName = document.fileName;
2264 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2266 document.visible = true;
2268 document.Activate();
2274 if(createIfFails == whatever)
2276 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2278 needFileModified = false;
2279 if(openMethod == normal)
2281 if(DontTerminateDebugSession($"Open Project"))
2290 Workspace workspace = null;
2292 if(FileExists(filePath))
2294 if(!strcmp(extension, ProjectExtension))
2296 char workspaceFile[MAX_LOCATION];
2297 strcpy(workspaceFile, filePath);
2298 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2299 workspace = LoadWorkspace(workspaceFile, filePath);
2301 else if(!strcmp(extension, WorkspaceExtension))
2302 workspace = LoadWorkspace(filePath, null);
2309 CreateProjectView(workspace, filePath);
2310 document = projectView;
2312 toolBox.visible = true;
2313 sheet.visible = true;
2314 projectView.MakeActive();
2316 workspace.ParseLoadedBreakpoints();
2317 workspace.DropInvalidBreakpoints(null);
2320 ide.projectView.ShowOutputBuildLog(true);
2322 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2323 ide.projectView.DisplayCompiler(compiler, false);
2326 UpdateCompilerConfigs(false);
2329 char newWorkingDir[MAX_LOCATION];
2330 StripLastDirectory(filePath, newWorkingDir);
2331 ChangeFileDialogsDirectory(newWorkingDir, false);
2334 document.fileName = filePath;
2336 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2338 // this crashes on starting ide with epj file, solution please?
2339 // app.UpdateDisplay();
2341 workspace.holdTracking = true;
2342 for(ofi : workspace.openedFiles)
2344 if(ofi.state != closed)
2346 Window file = OpenFile(ofi.path, false, true, null, no, normal, noParsing);
2349 char fileName[MAX_LOCATION];
2351 GetLastDirectory(ofi.path, fileName);
2352 node = projectView.project.topNode.Find(fileName, true);
2354 node.EnsureVisible();
2358 ide.RepositionWindows(false);
2359 workspace.holdTracking = false;
2361 workspace.timer.Start();
2363 #if !defined(__WIN32__)
2364 // Valgrind Debug menu updates
2365 debugUseValgrindItem.checked = workspace.useValgrind;
2367 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2368 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2369 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2370 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2372 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2373 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2374 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2375 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2376 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2377 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2378 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2379 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2381 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2384 findInFilesDialog.mode = FindInFilesMode::project;
2385 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2388 char location[MAX_LOCATION];
2389 StripLastDirectory(ide.project.topNode.path, location);
2390 ChangeProjectFileDialogDirectory(location);
2397 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2399 ideProjectFileDialog.text = openProjectFileDialogTitle;
2400 if(ideProjectFileDialog.Modal() == cancel)
2402 filePath = ideProjectFileDialog.filePath;
2403 GetExtension(filePath, extension);
2414 else if(openMethod == add)
2419 char slashFilePath[MAX_LOCATION];
2420 GetSlashPathBuffer(slashFilePath, filePath);
2421 for(p : workspace.projects)
2423 if(!fstrcmp(p.filePath, slashFilePath))
2431 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2432 contents = $"This project is already present in workspace." }.Modal();
2436 prj = LoadProject(filePath, null);
2439 const char * activeConfigName = null;
2440 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2441 prj.StartMonitoring();
2442 workspace.projects.Add(prj);
2443 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2444 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2445 activeConfigName = toolBar.activeConfig.currentRow.string;
2446 if(activeConfigName)
2448 for(cfg : prj.configurations)
2450 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2458 projectView.AddNode(prj.topNode, null);
2459 workspace.modified = true;
2461 findInFilesDialog.AddProjectItem(prj);
2462 projectView.ShowOutputBuildLog(true);
2463 projectView.DisplayCompiler(compiler, false);
2464 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2468 char location[MAX_LOCATION];
2469 StripLastDirectory(prj.topNode.path, location);
2470 ChangeProjectFileDialogDirectory(location);
2473 // projectView is associated with the main project and not with the one just added but
2474 return projectView; // just to let the caller know something was opened
2482 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2483 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2484 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2486 if(FileExists(filePath))
2487 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2488 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2489 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2492 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2495 else if(!strcmp(extension, "3ds"))
2497 if(FileExists(filePath))
2498 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2499 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2500 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2504 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2507 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2508 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2509 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2510 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2511 !strcmp(extension, "js"))
2513 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2514 editor.updatingCode = true;
2515 if(editor.LoadFile(filePath))
2518 editor.visible = true;
2522 needFileModified = false;
2526 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2527 if(editor.LoadFile(filePath))
2530 editor.visible = true;
2534 needFileModified = false;
2537 if(document && (document._class == class(PictureEdit) ||
2538 document._class == class(ModelView)))
2543 document.fileName = filePath;
2544 if(workspace && !workspace.holdTracking)
2545 workspace.UpdateOpenedFileInfo(filePath, opened);
2549 if(!document && createIfFails != no)
2551 if(createIfFails != yes && !needFileModified &&
2552 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2553 createIfFails = yes;
2554 if(createIfFails == yes || createIfFails == whatever)
2556 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2558 document.fileName = filePath;
2564 if(projectView && document._class == class(CodeEditor) && workspace)
2566 int lineNumber, position;
2568 CodeEditor editor = (CodeEditor)document;
2569 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2570 editor.openedFileInfo.holdTracking = true;
2571 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2572 position = Max(editor.openedFileInfo.position - 1, 0);
2573 if(editor.editBox.GoToLineNum(lineNumber))
2574 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2575 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2576 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2577 editor.editBox.scroll = scroll;
2578 editor.openedFileInfo.holdTracking = false;
2581 if(needFileModified)
2582 document.OnFileModified = OnFileModified;
2583 document.NotifySaved = DocumentSaved;
2584 if(maximizeDoc && document.hasMaximize)
2585 document.state = maximized;
2588 ideSettings.AddRecentProject(document.fileName);
2590 ideSettings.AddRecentFile(document.fileName);
2591 ide.UpdateRecentMenus();
2592 ide.AdjustFileMenus();
2593 settingsContainer.Save();
2601 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2602 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2604 if(!parentClosing && ide.workspace)
2605 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2608 bool ModelView::ModelViewOnClose(bool parentClosing)
2610 if(!parentClosing && ide.workspace)
2611 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2614 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2616 if(!parentClosing && ide.workspace)
2617 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2622 void OnUnloadGraphics(Window window)
2624 display.ClearMaterials();
2625 display.ClearTextures();
2626 display.ClearMeshes();
2630 void UpdateStateLight(StatusField fld, bool on)
2632 fld.color = on ? lime : Color { 128,128,128 };
2633 fld.backColor = on ? dimGray : 0;
2637 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2639 UpdateStateLight(caps, app.GetKeyState(capsState));
2640 UpdateStateLight(num, app.GetKeyState(numState));
2644 bool OnKeyDown(Key key, unichar ch)
2648 case b: projectView.Update(null); break;
2649 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2650 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2655 bool OnKeyUp(Key key, unichar ch)
2659 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2660 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2665 void GoToError(const char * line, bool noParsing)
2668 projectView.GoToError(line, noParsing);
2671 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath)
2673 FileAttribs result { };
2674 FileAttribs fileAttribs;
2678 strcpy(selectedPath, prj.topNode.path);
2679 else if(dir && dir[0])
2680 strcpy(selectedPath, dir);
2682 selectedPath[0] = '\0';
2683 PathCat(selectedPath, filePath);
2685 if((fileAttribs = FileExists(selectedPath)).isFile)
2686 result = fileAttribs;
2690 for(p : workspace.projects)
2692 strcpy(selectedPath, p.topNode.path);
2693 PathCat(selectedPath, filePath);
2694 if((fileAttribs = FileExists(selectedPath)).isFile)
2697 result = fileAttribs;
2704 ProjectNode n = null;
2705 for(p : workspace.projects)
2707 if((n = p.topNode.Find(filePath, false)))
2709 n.GetFullFilePath(selectedPath);
2710 if((fileAttribs = FileExists(selectedPath)).isFile)
2713 result = fileAttribs;
2718 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath)) && project &&
2719 (fileAttribs = FileExists(selectedPath)).isFile)
2722 result = fileAttribs;
2730 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
2733 const char *path = text;
2734 char *colon = strchr(text, ':');
2735 char filePath[MAX_LOCATION] = "";
2736 char completePath[MAX_LOCATION];
2737 int line = 0, col = 0;
2738 int len = strlen(text);
2740 FileAttribs fileAttribs;
2742 // support for valgrind output
2743 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2754 /*for(s=colon; *s; s++)
2763 //line = atoi(colon+1);
2765 // support for "Found n match(es) in "file/path";
2766 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)
2772 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2774 path = (colon - 1 > path) ? colon - 1 : path;
2775 colon = strstr(colon + 1, ":");
2777 if(*path == '*' && (s = strchr(path+1, '*')))
2779 while(isspace(*path)) path++;
2783 char * close = strchr(path, ')');
2787 strncpy(name, path+1, close - path - 1);
2788 name[close - path - 1] = '\0';
2789 for(p : ide.workspace.projects)
2791 if(!strcmp(p.name, name))
2801 prj = project ? project : (dir ? null : ide.project);
2804 strncpy(filePath, path, colon - path);
2805 filePath[colon - path] = '\0';
2806 line = atoi(colon + 1);
2807 colon = strstr(colon + 1, ":");
2809 col = atoi(colon + 1);
2811 else if(path - 1 >= text && *(path - 1) == '\"')
2813 colon = strchr(path, '\"');
2816 strncpy(filePath, path, colon - path);
2817 filePath[colon - path] = '\0';
2820 else if(path && !colon)
2822 strcpy(filePath, path);
2825 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath)))
2826 CodeLocationGoTo(completePath, fileAttribs, line, col);
2829 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2831 if(fileAttribs.isFile)
2833 char ext[MAX_EXTENSION];
2834 GetExtension(path, ext);
2836 if(binaryDocExt.Find(ext))
2838 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2840 char dirPath[MAX_LOCATION];
2841 StripLastDirectory(path, dirPath);
2846 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2847 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2849 EditBox editBox = codeEditor.editBox;
2850 editBox.GoToLineNum(line - 1);
2851 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2855 else if(fileAttribs.isDirectory)
2859 void OnRedraw(Surface surface)
2861 Bitmap bitmap = back.bitmap;
2863 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2866 void SheetSelected(SheetType sheetSelected)
2868 if(activeChild == sheet)
2870 if(sheetSelected == methods)
2872 viewPropertiesItem.accelerator = f4;
2873 viewPropertiesItem.parent = viewMenu;
2874 viewMethodsItem.parent = null;
2878 viewMethodsItem.accelerator = f4;
2879 viewMethodsItem.parent = viewMenu;
2880 viewPropertiesItem.parent = null;
2885 viewMethodsItem.parent = viewMenu;
2886 viewPropertiesItem.parent = viewMenu;
2887 if(sheetSelected == methods)
2889 viewMethodsItem.accelerator = f4;
2890 viewPropertiesItem.accelerator = 0;
2894 viewMethodsItem.accelerator = 0;
2895 viewPropertiesItem.accelerator = f4;
2900 void OnActivateClient(Window client, Window previous)
2902 //if(!client || client != previous)
2905 if(!client || client != previous)
2908 dataType = previous._class;
2909 if(previous && !strcmp(dataType.name, "CodeEditor"))
2911 ((CodeEditor)previous).UpdateFormCode();
2913 else if(previous && !strcmp(dataType.name, "Designer"))
2915 ((Designer)previous).codeEditor.UpdateFormCode();
2920 dataType = client._class;
2921 if(client && !strcmp(dataType.name, "CodeEditor"))
2923 CodeEditor codeEditor = (CodeEditor)client;
2924 SetPrivateModule(codeEditor.privateModule);
2925 SetCurrentContext(codeEditor.globalContext);
2926 SetTopContext(codeEditor.globalContext);
2927 SetGlobalContext(codeEditor.globalContext);
2929 SetDefines(&codeEditor.defines);
2930 SetImports(&codeEditor.imports);
2932 SetActiveDesigner(codeEditor.designer);
2934 sheet.codeEditor = codeEditor;
2935 toolBox.codeEditor = codeEditor;
2937 viewDesignerItem.parent = viewMenu;
2938 if(activeChild != codeEditor)
2940 viewCodeItem.parent = viewMenu;
2941 viewDesignerItem.accelerator = 0;
2942 viewCodeItem.accelerator = f8;
2946 viewCodeItem.parent = null;
2947 viewDesignerItem.accelerator = f8;
2950 else if(client && !strcmp(dataType.name, "Designer"))
2952 CodeEditor codeEditor = ((Designer)client).codeEditor;
2955 SetPrivateModule(codeEditor.privateModule);
2956 SetCurrentContext(codeEditor.globalContext);
2957 SetTopContext(codeEditor.globalContext);
2958 SetGlobalContext(codeEditor.globalContext);
2959 SetDefines(&codeEditor.defines);
2960 SetImports(&codeEditor.imports);
2964 SetPrivateModule(null);
2965 SetCurrentContext(null);
2966 SetTopContext(null);
2967 SetGlobalContext(null);
2972 SetActiveDesigner((Designer)client);
2974 sheet.codeEditor = codeEditor;
2975 toolBox.codeEditor = codeEditor;
2977 viewCodeItem.parent = viewMenu;
2978 if(activeChild != client)
2980 viewDesignerItem.parent = viewMenu;
2981 viewDesignerItem.accelerator = f8;
2982 viewCodeItem.accelerator = 0;
2986 viewDesignerItem.parent = null;
2987 viewCodeItem.accelerator = f8;
2992 if(!client && !projectView && sheet.visible)
2995 sheet.visible = false;
2996 toolBox.visible = false;
2999 sheet.codeEditor = null;
3000 toolBox.codeEditor = null;
3001 SetActiveDesigner(null);
3003 viewDesignerItem.parent = null;
3004 viewCodeItem.parent = null;
3007 SheetSelected(sheet.sheetSelected);
3010 projectCompileItem = null;
3015 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3017 CodeEditor codeEditor = (CodeEditor)client;
3018 EditBox editBox = codeEditor.editBox;
3020 statusBar.AddField(pos);
3022 caps = { width = 40, text = $"CAPS" };
3023 statusBar.AddField(caps);
3024 UpdateStateLight(caps, app.GetKeyState(capsState));
3026 ovr = { width = 36, text = $"OVR" };
3027 statusBar.AddField(ovr);
3028 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3030 num = { width = 36, text = $"NUM" };
3031 statusBar.AddField(num);
3032 UpdateStateLight(num, app.GetKeyState(numState));
3034 //statusBar.text = "Ready";
3036 if(projectView && projectView.project)
3038 bool isCObject = false;
3039 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3040 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3044 char nodeName[MAX_FILENAME];
3045 char name[MAX_FILENAME+96];
3047 ChangeExtension(node.name, "c", nodeName);
3048 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3049 projectCompileItem =
3051 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3053 bool NotifySelect(MenuItem selection, Modifiers mods)
3057 bool isCObject = false;
3058 bool isExcluded = false;
3059 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3063 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3066 List<ProjectNode> nodes { };
3068 projectView.Compile(node.project, nodes, mods.ctrl && mods.shift, isCObject ? cObject : normal);
3076 projectMenu.AddDynamic(projectCompileItem, ide, false);
3082 caps = ovr = num = null;
3087 bool OnClose(bool parentClosing)
3089 //return !projectView.buildInProgress;
3090 if(projectView && projectView.buildInProgress)
3092 if(DontTerminateDebugSession($"Close IDE"))
3094 if(findInFilesDialog)
3095 findInFilesDialog.SearchStop();
3098 workspace.timer.Stop();
3101 ideMainFrame.Destroy(0);
3108 bool passThrough = false;
3109 bool debugStart = false;
3110 bool debugWorkDir = false;
3111 char * passDebugWorkDir = null;
3112 bool openAsText = false;
3113 DynamicString passArgs { };
3116 for(c = 1; c<app.argc; c++)
3120 const char * arg = app.argv[c];
3121 char * buf = new char[strlen(arg)*2+1];
3123 passArgs.concat(" ");
3125 passArgs.concat(buf);
3128 else if(debugWorkDir)
3130 passDebugWorkDir = CopyString(app.argv[c]);
3131 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3132 debugWorkDir = false;
3134 else if(!strcmp(app.argv[c], "-t"))
3136 else if(!strcmp(app.argv[c], "-no-parsing"))
3137 ide.noParsing = true;
3138 else if(!strcmp(app.argv[c], "-debug-start"))
3140 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3141 debugWorkDir = true;
3142 else if(!strcmp(app.argv[c], "-@"))
3146 char fullPath[MAX_LOCATION];
3147 char parentPath[MAX_LOCATION];
3148 char ext[MAX_EXTENSION];
3150 FileAttribs dirAttribs;
3151 GetWorkingDir(fullPath, MAX_LOCATION);
3152 PathCat(fullPath, app.argv[c]);
3153 StripLastDirectory(fullPath, parentPath);
3154 GetExtension(app.argv[c], ext);
3155 isProject = !openAsText && !strcmpi(ext, "epj");
3157 if(isProject && c > (debugStart ? 2 : 1)) continue;
3159 // Create directory for projects (only)
3160 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3162 if(isProject && !FileExists(fullPath))
3164 char name[MAX_LOCATION];
3165 NewProjectDialog newProjectDialog;
3169 projectView.visible = false;
3170 if(!projectView.Destroy(0))
3174 newProjectDialog = { master = this };
3176 strcpy(name, app.argv[c]);
3177 StripExtension(name);
3178 GetLastDirectory(name, name);
3179 newProjectDialog.projectName.contents = name;
3180 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3181 newProjectDialog.locationEditBox.path = parentPath;
3182 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3184 incref newProjectDialog;
3185 newProjectDialog.Modal();
3188 ideSettings.AddRecentProject(projectView.fileName);
3189 ide.UpdateRecentMenus();
3190 settingsContainer.Save();
3192 delete newProjectDialog;
3193 // Open only one project
3197 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3199 else if(strstr(fullPath, "http://") == fullPath)
3200 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3203 if(passThrough && projectView && projectView.project && workspace)
3204 workspace.commandLineArgs = passArgs;
3205 if(passDebugWorkDir && projectView && projectView.project && workspace)
3207 workspace.debugDir = passDebugWorkDir;
3208 delete passDebugWorkDir;
3211 ;//MenuDebugStart(debugStartResumeItem, 0); // <-- how TODO this without getting into the app.Wait lock
3213 UpdateToolBarActiveConfigs(false);
3214 UpdateToolBarActiveCompilers();
3221 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3224 projectView.visible = false;
3225 projectView.Destroy(0);
3228 #ifdef GDB_DEBUG_GUI
3229 gdbDialog.Destroy(0);
3234 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3238 char * oldPaths[128];
3239 String oldList = new char[maxPathLen];
3240 Array<String> newExePaths { };
3241 //Map<String, bool> exePathExists { };
3243 #if defined(__unix__) || defined(__APPLE__)
3244 Array<String> newLibPaths { };
3245 Map<String, bool> libPathExists { };
3250 for(prj : workspace.projects)
3252 DirExpression targetDirExp;
3254 // SKIP FIRST PROJECT...
3255 if(prj == workspace.projects.firstIterator.data) continue;
3257 // NOTE: Right now the additional project config dir will be
3258 // obtained when the debugger is started, so toggling it
3259 // while building will change which library gets used.
3260 // To go with the initial state, e.g. when F5 was pressed,
3261 // we nould need to keep a list of all project's active
3262 // config upon startup.
3263 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3265 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3269 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3270 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3274 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3275 if(cfg.targetType == sharedLibrary && cfg.debug)
3279 if(targetDirExp.dir)
3281 char buffer[MAX_LOCATION];
3282 #if defined(__WIN32__)
3283 Array<String> paths = newExePaths;
3285 Array<String> paths = newLibPaths;
3287 GetSystemPathBuffer(buffer, prj.topNode.path);
3288 PathCat(buffer, targetDirExp.dir);
3291 if(!fstrcmp(p, buffer))
3298 paths.Add(CopyString(buffer));
3300 delete targetDirExp;
3304 for(item : compiler.executableDirs)
3307 for(p : newExePaths)
3309 if(!fstrcmp(p, item))
3316 newExePaths.Add(CopySystemPath(item));
3319 GetEnvironment("PATH", oldList, maxPathLen);
3321 printf("Old value of PATH: %s\n", oldList);
3323 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3324 for(c = 0; c < count; c++)
3327 for(p : newExePaths)
3329 if(!fstrcmp(p, oldPaths[c]))
3336 newExePaths.Add(CopySystemPath(oldPaths[c]));
3340 for(path : newExePaths)
3341 len += strlen(path) + 1;
3342 newList = new char[len + 1];
3344 for(path : newExePaths)
3346 strcat(newList, path);
3347 strcat(newList, pathListSep);
3349 newList[len - 1] = '\0';
3350 SetEnvironment("PATH", newList);
3352 printf("New value of PATH: %s\n", newList);
3359 #if defined(__unix__) || defined(__APPLE__)
3361 for(item : compiler.libraryDirs)
3363 if(!libPathExists[item]) // fstrcmp should be used
3365 String s = CopyString(item);
3367 libPathExists[s] = true;
3371 #if defined(__APPLE__)
3372 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3374 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3377 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3379 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3380 for(c = 0; c < count; c++)
3382 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3384 String s = CopyString(oldPaths[c]);
3386 libPathExists[s] = true;
3391 for(path : newLibPaths)
3392 len += strlen(path) + 1;
3393 newList = new char[len + 1];
3395 for(path : newLibPaths)
3397 strcat(newList, path);
3398 strcat(newList, pathListSep);
3400 newList[len - 1] = '\0';
3401 #if defined(__APPLE__)
3402 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3404 SetEnvironment("LD_LIBRARY_PATH", newList);
3407 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3413 delete libPathExists;
3416 if(compiler.distccEnabled && compiler.distccHosts)
3417 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3422 void DestroyTemporaryProjectDir()
3424 if(tmpPrjDir && tmpPrjDir[0])
3426 if(FileExists(tmpPrjDir).isDirectory)
3427 DestroyDir(tmpPrjDir);
3428 property::tmpPrjDir = null;
3434 // Graphics Driver Menu
3437 app.currentSkin.selectionColor = selectionColor;
3438 app.currentSkin.selectionText = selectionText;
3442 driverItems = new MenuItem[app.numDrivers];
3443 for(c = 0; c < app.numDrivers; c++)
3445 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3446 driverItems[c].id = c;
3447 driverItems[c].isRadio = true;
3450 driverItems = new MenuItem[2];
3451 #if defined(__unix__)
3452 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3453 driverItems[0].id = 0;
3454 driverItems[0].isRadio = true;
3456 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3457 driverItems[0].id = 0;
3458 driverItems[0].isRadio = true;
3460 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3461 driverItems[1].id = 1;
3462 driverItems[1].isRadio = true;
3464 /* skinItems = new MenuItem[app.numSkins];
3465 for(c = 0; c < app.numSkins; c++)
3467 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3468 skinItems[c].id = c;
3469 skinItems[c].isRadio = true;
3472 ideFileDialog.master = this;
3473 ideProjectFileDialog.master = this;
3475 //SetDriverAndSkin();
3479 void UpdateRecentMenus()
3482 Menu fileMenu = menu.FindMenu($"File");
3483 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3484 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3485 char * itemPath = new char[MAX_LOCATION];
3486 char * itemName = new char[MAX_LOCATION+4];
3488 recentFiles.Clear();
3491 for(recent : ideSettings.recentFiles)
3493 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3494 MakeSystemPath(itemPath);
3495 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3496 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3500 recentProjects.Clear();
3502 for(recent : ideSettings.recentProjects)
3504 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3505 MakeSystemPath(itemPath);
3506 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3507 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3519 delete languageItems;
3523 documentor.Puts("Quit\n");
3530 void DestroyDir(char * path)
3532 RecursiveDeleteFolderFSI fsi { };
3537 #if defined(__WIN32__)
3538 define sdkDirName = "Ecere SDK";
3540 define sdkDirName = "ecere";
3543 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3546 char * v = new char[maxPathLen];
3550 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3551 StripLastDirectory(path, path);
3552 PathCat(path, subDir);
3553 if(name) PathCat(path, name);
3554 if(FileExists(path) & attribs) found = true;
3556 #if defined(__WIN32__)
3559 GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3562 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3563 PathCat(path, subDir);
3564 if(name) PathCat(path, name);
3565 if(FileExists(path) & attribs) found = true;
3570 GetEnvironment("AppData", v, maxPathLen);
3573 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3574 PathCat(path, sdkDirName);
3575 PathCat(path, subDir);
3576 if(name) PathCat(path, name);
3577 if(FileExists(path) & attribs) found = true;
3582 GetEnvironment("ProgramData", v, maxPathLen);
3585 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3586 PathCat(path, sdkDirName);
3587 PathCat(path, subDir);
3588 if(name) PathCat(path, name);
3589 if(FileExists(path) & attribs) found = true;
3594 GetEnvironment("ProgramFiles", v, maxPathLen);
3597 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3598 PathCat(path, sdkDirName);
3599 PathCat(path, subDir);
3600 if(name) PathCat(path, name);
3601 if(FileExists(path) & attribs) found = true;
3606 GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3609 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3610 PathCat(path, sdkDirName);
3611 PathCat(path, subDir);
3612 if(name) PathCat(path, name);
3613 if(FileExists(path) & attribs) found = true;
3618 GetEnvironment("SystemDrive", v, maxPathLen);
3621 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3622 PathCat(path, "Program Files");
3623 PathCat(path, sdkDirName);
3624 PathCat(path, subDir);
3625 if(name) PathCat(path, name);
3626 if(FileExists(path) & attribs) found = true;
3635 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3636 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3637 for(c=0; c<numTokens; c++)
3639 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3640 PathCat(path, sdkDirName);
3641 PathCat(path, subDir);
3642 if(name) PathCat(path, name);
3643 if(FileExists(path) & attribs) found = true;
3651 void FindAndShellOpenInstalledFolder(const char * name)
3653 char path[MAX_LOCATION];
3654 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3658 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3660 char path[MAX_LOCATION];
3661 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3665 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3667 bool preserveRootFolder;
3669 void OutFolder(const char * folderPath, bool isRoot)
3671 if(!(preserveRootFolder && isRoot))
3672 RemoveDir(folderPath);
3675 bool OnFile(const char * filePath)
3677 DeleteFile(filePath);
3682 class IDEApp : GuiApplication
3684 //driver = "Win32Console";
3685 // driver = "OpenGL";
3689 TempFile includeFile { };
3694 char ext[MAX_EXTENSION];
3695 SetLoggingMode(stdOut, null);
3696 //SetLoggingMode(debug, null);
3698 settingsContainer.Load();
3700 if(ideSettings.language)
3702 const String language = GetLanguageString();
3703 if(ideSettings.language.OnCompare(language))
3705 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3710 // First count files arg to decide whether to maximize
3712 bool passThrough = false, debugWorkDir = false;
3715 for(c = 1; c<app.argc; c++)
3718 else if(debugWorkDir)
3719 debugWorkDir = false;
3720 else if(!strcmp(app.argv[c], "-t"));
3721 else if(!strcmp(app.argv[c], "-no-parsing"));
3722 else if(!strcmp(app.argv[c], "-debug-start"));
3723 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3724 debugWorkDir = true;
3725 else if(!strcmp(app.argv[c], "-@"))
3732 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3734 app.driver = "OpenGL";
3735 ide.driverItems[1].checked = true;
3739 #if defined(__unix__) || defined(__APPLE__)
3740 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3742 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3744 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3748 char model[MAX_LOCATION];
3749 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3751 ide.duck.modelFile = model;
3752 ide.duck.parent = ideMainFrame;
3755 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3756 ide.debugRubberDuck.disabled = false;
3760 desktop.caption = titleECEREIDE;
3763 for(c = 1; c<app.argc; c++)
3765 char fullPath[MAX_LOCATION];
3766 GetWorkingDir(fullPath, MAX_LOCATION);
3767 PathCat(fullPath, app.argv[c]);
3768 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3772 // Default to language specified by environment if no language selected
3773 if(!ideSettings.language)
3775 ideSettings.language = GetLanguageString();
3776 settingsContainer.Save();
3779 // Default to home directory if no directory yet set up
3780 if(!ideSettings.ideProjectFileDialogLocation[0])
3783 char location[MAX_LOCATION];
3784 char * home = getenv("HOME");
3785 char * homeDrive = getenv("HOMEDRIVE");
3786 char * homePath = getenv("HOMEPATH");
3787 char * userProfile = getenv("USERPROFILE");
3788 char * systemDrive = getenv("SystemDrive");
3789 if(home && FileExists(home).isDirectory)
3791 strcpy(location, home);
3794 if(!found && homeDrive && homePath)
3796 strcpy(location, homeDrive);
3797 PathCat(location, homePath);
3798 if(FileExists(location).isDirectory)
3801 if(!found && FileExists(userProfile).isDirectory)
3803 strcpy(location, userProfile);
3806 if(!found && FileExists(systemDrive).isDirectory)
3808 strcpy(location, systemDrive);
3813 ideSettings.ideProjectFileDialogLocation = location;
3814 if(!ideSettings.ideFileDialogLocation[0])
3815 ideSettings.ideFileDialogLocation = location;
3819 if(!LoadIncludeFile())
3820 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3822 // Create language menu
3824 String language = ideSettings.language;
3828 ide.languageItems = new MenuItem[languages.count];
3831 ide.languageItems[i] =
3833 ide.languageMenu, l.name;
3834 bitmap = { l.bitmap };
3838 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3840 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3842 // Re-select previous selected language if aborted
3843 String language = ideSettings.language;
3847 if(((!language || !language[0]) && i == 0) ||
3848 (language && !strcmpi(l.code, language)))
3850 ide.languageItems[i].checked = true;
3862 // Try to find country-specific language first
3868 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3870 ide.languageItems[i].checked = true;
3878 // Try generalizing locale
3879 if(!found && language)
3882 char genericLocale[256];
3884 strncpy(genericLocale, language, sizeof(genericLocale));
3885 genericLocale[sizeof(genericLocale)-1] = 0;
3887 under = strchr(genericLocale, '_');
3890 if(!strcmpi(genericLocale, "zh"))
3891 strcpy(genericLocale, "zh_CN");
3892 if(strcmp(genericLocale, language))
3896 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3898 ide.languageItems[i].checked = true;
3908 ide.languageItems[0].checked = true;
3910 MenuDivider { ide.languageMenu };
3913 ide.languageMenu, "Help Translate";
3915 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3917 ShellOpen("http://translations.launchpad.net/ecere");
3923 ideMainFrame.Create();
3924 if(app.argFilesCount > 1)
3925 ide.MenuWindowTileVert(null, 0);
3929 bool Cycle(bool idle)
3933 if(ide.documentor.Peek())
3936 ide.documentor.GetLine(line, sizeof(line));
3937 if(!strcmpi(line, "Exited"))
3939 ide.documentor.CloseInput();
3940 ide.documentor.CloseOutput();
3941 ide.documentor.Wait();
3942 delete ide.documentor;
3945 if(ide.documentor && ide.documentor.eof)
3947 ide.documentor.CloseInput();
3948 ide.documentor.CloseOutput();
3949 ide.documentor.Wait();
3950 delete ide.documentor;
3956 bool LoadIncludeFile()
3958 bool result = false;
3959 File include = FileOpen(":crossplatform.mk", read);
3962 File f = includeFile;
3965 for(; !include.Eof(); )
3968 int count = include.Read(buffer, 1, 4096);
3969 f.Write(buffer, 1, count);
3979 IDEMainFrame ideMainFrame { };
3981 define app = ((IDEApp)__thisModule);
3983 define titleECEREIDE = $"Ecere IDE (Debug)";
3985 define titleECEREIDE = $"Ecere IDE";