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);
1639 #ifdef GDB_DEBUG_GUI
1642 master = this, parent = this;
1643 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1645 void OnCommand(const char * string)
1648 ide.debugger.SendGDBCommand(string);
1653 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1655 //app.driver = app.drivers[selection.id];
1656 #if defined(__unix__) || defined(__APPLE__)
1657 app.driver = selection.id ? "OpenGL" : "X";
1659 app.driver = selection.id ? "OpenGL" : "GDI";
1661 delete ideSettings.displayDriver;
1662 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1664 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1666 settingsContainer.Save();
1667 //SetDriverAndSkin();
1671 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1673 app.skin = app.skins[selection.id];
1678 void SetDriverAndSkin()
1681 for(c = 0; c < app.numSkins; c++)
1682 if(!strcmp(app.skins[c], app.skin))
1684 skinItems[c].checked = true;
1687 for(c = 0; c < app.numDrivers; c++)
1688 if(!strcmp(app.drivers[c], app.driver))
1690 driverItems[c].checked = true;
1695 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1697 Project project = workspace.projects.firstIterator.data;
1698 projectView = ProjectView
1701 fileName = fileName;
1703 void NotifyDestroyed(Window window, DialogResult result)
1706 text = titleECEREIDE;
1711 projectView.Create();
1712 RepositionWindows(false);
1714 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1715 projectView.workspace = workspace;
1716 projectView.project = project;
1717 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1721 ide.breakpointsView.LoadFromWorkspace();
1722 ide.watchesView.LoadFromWorkspace();
1724 findInFilesDialog.projectNodeField.userData = projectView;
1727 char fileName[MAX_LOCATION];
1728 strcpy(fileName, project.topNode.path);
1729 PathCat(fileName, project.topNode.name);
1736 projectView.visible = false;
1737 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1739 if(findInFilesDialog)
1741 char workingDir[MAX_LOCATION];
1742 GetWorkingDir(workingDir, MAX_LOCATION);
1743 findInFilesDialog.SearchStop();
1744 findInFilesDialog.currentDirectory = workingDir;
1746 sheet.visible = false;
1747 toolBox.visible = false;
1748 outputView.visible = false;
1749 ideMainFrame.text = titleECEREIDE;
1756 void RepositionWindows(bool expand)
1761 bool callStackVisible = expand ? false : callStackView.visible;
1762 bool threadsVisible = expand ? false : threadsView.visible;
1763 bool watchesVisible = expand ? false : watchesView.visible;
1764 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1765 bool toolBoxVisible = toolBox.visible;
1766 bool outputVisible = expand ? false : outputView.visible;
1767 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1768 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1770 for(child = firstChild; child; child = child.next)
1772 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1773 child._class == class(Sheet) || child._class == class(ProjectView))
1775 Anchor anchor = child.anchor;
1776 anchor.top = topDistance;
1777 anchor.bottom = bottomDistance;
1778 if(child._class == class(CodeEditor) || child._class == class(Designer))
1780 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1781 anchor.right = toolBoxVisible ? 150 : 0;
1784 child.anchor = anchor;
1788 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1789 child._class == class(BreakpointsView))
1790 child.visible = false;
1793 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1795 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1799 bool ShowCodeEditor()
1802 activeClient.Activate();
1803 else if(projectView)
1805 projectView.visible = true;
1806 projectView.Activate();
1808 else if(sheet.visible)
1811 outputView.visible = false;
1815 void DocumentSaved(Window document, const char * fileName)
1817 ideSettings.AddRecentFile(fileName);
1818 ide.UpdateRecentMenus();
1819 ide.AdjustFileMenus();
1820 settingsContainer.Save();
1823 bool Window::OnFileModified(FileChange fileChange, const char * param)
1826 sprintf(temp, $"The document %s was modified by another application.\n"
1827 "Would you like to reload it and lose your changes?", this.fileName);
1828 if(MessageBox { type = yesNo, master = this/*.parent*/,
1829 text = $"Document has been modified", contents = temp }.Modal() == yes)
1831 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1832 char * fileName = CopyString(this.fileName);
1833 WindowState state = this.state;
1834 Anchor anchor = this.anchor;
1835 Size size = this.size;
1837 this.modifiedDocument = false;
1839 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1842 this.anchor = anchor;
1844 this.SetState(state, true, 0);
1852 void UpdateMakefiles()
1856 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1857 for(prj : workspace.projects)
1858 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1863 void UpdateCompilerConfigs(bool mute)
1865 UpdateToolBarActiveCompilers();
1868 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1869 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1872 projectView.ShowOutputBuildLog(true);
1873 projectView.DisplayCompiler(compiler, false);
1875 for(prj : workspace.projects)
1876 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1881 void UpdateToolBarActiveCompilers()
1883 toolBar.activeCompiler.Clear();
1884 for(compiler : ideSettings.compilerConfigs)
1886 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1887 if(workspace && workspace.compiler && !strcmp(compiler.name, workspace.compiler))
1888 toolBar.activeCompiler.currentRow = row;
1890 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1891 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1892 toolBar.activeBitDepth.SelectRow(toolBar.activeBitDepth.FindRow(workspace ? workspace.bitDepth : 0));
1895 void UpdateToolBarActiveConfigs(bool selectionOnly)
1897 bool commonSelected = false;
1898 DataRow row = toolBar.activeConfig.currentRow;
1900 row = toolBar.activeConfig.FindRow(1);
1903 toolBar.activeConfig.Clear();
1904 row = toolBar.activeConfig.AddString($"(Mixed)");
1909 char * configName = null;
1912 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1913 for(prj : workspace.projects)
1915 for(cfg : prj.configurations)
1918 configs[cfg.name] = 1;
1923 toolBar.activeConfig.AddString(&name);
1927 if(projectView && projectView.project)
1929 for(prj : workspace.projects)
1931 if(prj.config && prj.config.name)
1933 configName = prj.config.name;
1939 commonSelected = true;
1940 for(prj : workspace.projects)
1942 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1944 commonSelected = false;
1952 commonSelected = false;
1953 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1955 if(!strcmp(row.string, configName))
1957 toolBar.activeConfig.currentRow = row;
1958 commonSelected = true;
1965 toolBar.activeConfig.Sort(null, 0);
1967 toolBar.activeConfig.currentRow = row;
1972 bool unavailable = !project;
1974 projectAddItem.disabled = unavailable;
1975 toolBar.buttonAddProject.disabled = unavailable;
1977 projectSettingsItem.disabled = unavailable;
1979 projectBrowseFolderItem.disabled = unavailable;
1981 viewProjectItem.disabled = unavailable;
1983 toolBar.activeConfig.disabled = unavailable;
1984 toolBar.activeCompiler.disabled = unavailable;
1985 toolBar.activeBitDepth.disabled = unavailable;
1988 debugUseValgrindItem.disabled = unavailable;
1989 AdjustValgrindMenus();
1998 void AdjustValgrindMenus()
2000 bool unavailable = !project || !debugUseValgrindItem.checked;
2001 debugValgrindNoLeakCheckItem.disabled = unavailable;
2002 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2003 debugValgrindYesLeakCheckItem.disabled = unavailable;
2004 debugValgrindFullLeakCheckItem.disabled = unavailable;
2006 debugValgrindTrackOriginsItem.disabled = unavailable;
2008 debugValgrindRSDefaultItem.disabled = unavailable;
2009 debugValgrindRS0Item.disabled = unavailable;
2010 debugValgrindRS16Item.disabled = unavailable;
2011 debugValgrindRS32Item.disabled = unavailable;
2012 debugValgrindRS64Item.disabled = unavailable;
2013 debugValgrindRS128Item.disabled = unavailable;
2014 debugValgrindRS256Item.disabled = unavailable;
2015 debugValgrindRS512Item.disabled = unavailable;
2019 property bool hasOpenedCodeEditors
2024 for(w = firstChild; w; w = w.next)
2025 if(w._class == class(CodeEditor) &&
2026 w.isDocument && !w.closing && w.visible && w.created &&
2027 w.fileName && w.fileName[0])
2033 void AdjustFileMenus()
2035 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2037 projectQuickItem.disabled = unavailable;
2040 void AdjustBuildMenus()
2042 bool unavailable = project && projectView.buildInProgress;
2043 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2045 projectNewItem.disabled = unavailable;
2046 toolBar.buttonNewProject.disabled = unavailable;
2047 projectOpenItem.disabled = unavailable;
2048 toolBar.buttonOpenProject.disabled = unavailable;
2050 unavailable = !project || projectView.buildInProgress;
2052 projectCloseItem.disabled = unavailable;
2053 // toolBar.buttonCloseProject.disabled = unavailable;
2055 projectRunItem.disabled = naForRun;
2056 toolBar.buttonRun.disabled = naForRun;
2058 projectBuildItem.disabled = false;
2059 projectBuildItem.text = unavailable ? $"Stop Build" : $"Build";
2060 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2062 projectLinkItem.disabled = unavailable;
2063 toolBar.buttonReLink.disabled = unavailable;
2064 projectRebuildItem.disabled = unavailable;
2065 toolBar.buttonRebuild.disabled = unavailable;
2066 projectCleanItem.disabled = unavailable;
2067 toolBar.buttonClean.disabled = unavailable;
2068 projectCleanTargetItem.disabled = unavailable;
2069 projectRealCleanItem.disabled = unavailable;
2070 // toolBar.buttonRealClean.disabled = unavailable;
2071 projectRegenerateItem.disabled = unavailable;
2072 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2073 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2074 projectInstallItem.disabled = unavailable;
2075 toolBar.buttonInstall.disabled = unavailable;
2077 projectCompileItem.disabled = unavailable;
2079 AdjustPopupBuildMenus();
2082 void AdjustPopupBuildMenus()
2084 bool unavailable = !project || projectView.buildInProgress;
2086 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2089 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
2092 menu.disabled = false;
2093 menu.text = unavailable ? $"Stop Build" : $"Build";
2094 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2097 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0); if(menu) menu.disabled = unavailable;
2098 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0); if(menu) menu.disabled = unavailable;
2099 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0); if(menu) menu.disabled = unavailable;
2100 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0); if(menu) menu.disabled = unavailable;
2101 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0); if(menu) menu.disabled = unavailable;
2102 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
2103 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, 0); if(menu) menu.disabled = unavailable;
2104 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0); if(menu) menu.disabled = unavailable;
2105 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0); if(menu) menu.disabled = unavailable;
2106 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0); if(menu) menu.disabled = unavailable;
2107 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0); if(menu) menu.disabled = unavailable;
2108 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0); if(menu) menu.disabled = unavailable;
2109 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
2110 projectView.popupMenu.Update(null);
2114 property bool areDebugMenusUnavailable { get {
2116 project.GetTargetType(project.config) != executable ||
2117 projectView.buildInProgress == buildingMainProject;
2120 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2121 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2122 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2124 void AdjustDebugMenus()
2126 bool unavailable = areDebugMenusUnavailable;
2127 bool running = isDebuggerRunning;
2128 bool stopped = isDebuggerStopped;
2129 bool active = debugger.isActive;
2131 bool isNotRunning = unavailable || !running;
2132 bool isNotNotRunning = unavailable || running;
2133 bool isNotStopped = unavailable || !stopped;
2134 bool isNotActive = unavailable || !active;
2136 debugStartResumeItem.disabled = isNotNotRunning;
2137 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2138 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2141 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2142 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2145 debugBreakItem.disabled = isNotRunning;
2146 debugStopItem.disabled = isNotActive;
2147 debugRestartItem.disabled = isNotActive;
2150 toolBar.buttonDebugPause.disabled = isNotRunning;
2151 toolBar.buttonDebugStop.disabled = isNotActive;
2152 toolBar.buttonDebugRestart.disabled = isNotActive;
2155 debugStepIntoItem.disabled = isNotNotRunning;
2156 debugStepOverItem.disabled = isNotNotRunning;
2157 debugSkipStepOverItem.disabled = isNotNotRunning;
2158 debugStepOutItem.disabled = isNotStopped;
2159 debugSkipStepOutItem.disabled = isNotStopped;
2161 debugStepUntilItem.disabled = isNotStopped;
2162 debugSkipStepUntilItem.disabled = isNotStopped;
2166 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2167 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2168 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2169 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2170 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2172 if((Designer)GetActiveDesigner())
2174 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2176 codeEditor.AdjustDebugMenus();
2180 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2182 char tempString[MAX_LOCATION];
2183 strcpy(tempString, directory);
2184 if(saveSettings && !projectView)
2186 ideSettings.ideFileDialogLocation = directory;
2187 settingsContainer.Save();
2190 ideFileDialog.currentDirectory = tempString;
2191 codeEditorFileDialog.currentDirectory = tempString;
2192 codeEditorFormFileDialog.currentDirectory = tempString;
2195 void ChangeProjectFileDialogDirectory(char * directory)
2197 ideSettings.ideProjectFileDialogLocation = directory;
2198 settingsContainer.Save();
2201 Window FindWindow(const char * filePath)
2203 Window document = null;
2205 // TOCHECK: Do we need to change slashes here?
2206 for(document = firstChild; document; document = document.next)
2208 const char * fileName = document.fileName;
2209 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2211 document.visible = true;
2212 document.Activate();
2219 bool DontTerminateDebugSession(const char * title)
2221 if(debugger.isActive)
2223 if(MessageBox { type = yesNo, master = ide,
2224 contents = $"Do you want to terminate the debugging session in progress?",
2225 text = title }.Modal() == no)
2228 MessageBox msg { type = yesNo, master = ide,
2229 contents = "Do you want to terminate the debugging session in progress?",
2231 if(msg.Modal() == no)
2243 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2245 char extension[MAX_EXTENSION] = "";
2246 Window document = null;
2247 bool isProject = false;
2248 bool needFileModified = true;
2249 char winFilePath[MAX_LOCATION];
2250 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2251 Window currentDoc = activeClient;
2252 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2255 GetExtension(filePath, extension);
2259 strcpy(extension, type);
2261 if(strcmp(extension, ProjectExtension))
2263 for(document = firstChild; document; document = document.next)
2265 const char * fileName = document.fileName;
2266 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2268 document.visible = true;
2270 document.Activate();
2276 if(createIfFails == whatever)
2278 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2280 needFileModified = false;
2281 if(openMethod == normal)
2283 if(DontTerminateDebugSession($"Open Project"))
2292 Workspace workspace = null;
2294 if(FileExists(filePath))
2296 if(!strcmp(extension, ProjectExtension))
2298 char workspaceFile[MAX_LOCATION];
2299 strcpy(workspaceFile, filePath);
2300 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2301 workspace = LoadWorkspace(workspaceFile, filePath);
2303 else if(!strcmp(extension, WorkspaceExtension))
2304 workspace = LoadWorkspace(filePath, null);
2311 CreateProjectView(workspace, filePath);
2312 document = projectView;
2314 toolBox.visible = true;
2315 sheet.visible = true;
2316 projectView.MakeActive();
2318 workspace.ParseLoadedBreakpoints();
2319 workspace.DropInvalidBreakpoints(null);
2322 ide.projectView.ShowOutputBuildLog(true);
2324 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2325 ide.projectView.DisplayCompiler(compiler, false);
2328 UpdateCompilerConfigs(false);
2331 char newWorkingDir[MAX_LOCATION];
2332 StripLastDirectory(filePath, newWorkingDir);
2333 ChangeFileDialogsDirectory(newWorkingDir, false);
2336 document.fileName = filePath;
2338 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2340 // this crashes on starting ide with epj file, solution please?
2341 // app.UpdateDisplay();
2343 workspace.holdTracking = true;
2344 for(ofi : workspace.openedFiles)
2346 if(ofi.state != closed)
2348 Window file = OpenFile(ofi.path, false, true, null, no, normal, noParsing);
2351 char fileName[MAX_LOCATION];
2353 GetLastDirectory(ofi.path, fileName);
2354 node = projectView.project.topNode.Find(fileName, true);
2356 node.EnsureVisible();
2360 ide.RepositionWindows(false);
2361 workspace.holdTracking = false;
2363 workspace.timer.Start();
2365 #if !defined(__WIN32__)
2366 // Valgrind Debug menu updates
2367 debugUseValgrindItem.checked = workspace.useValgrind;
2369 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2370 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2371 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2372 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2374 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2375 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2376 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2377 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2378 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2379 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2380 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2381 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2383 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2386 findInFilesDialog.mode = FindInFilesMode::project;
2387 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2390 char location[MAX_LOCATION];
2391 StripLastDirectory(ide.project.topNode.path, location);
2392 ChangeProjectFileDialogDirectory(location);
2399 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2401 ideProjectFileDialog.text = openProjectFileDialogTitle;
2402 if(ideProjectFileDialog.Modal() == cancel)
2404 filePath = ideProjectFileDialog.filePath;
2405 GetExtension(filePath, extension);
2416 else if(openMethod == add)
2421 char slashFilePath[MAX_LOCATION];
2422 GetSlashPathBuffer(slashFilePath, filePath);
2423 for(p : workspace.projects)
2425 if(!fstrcmp(p.filePath, slashFilePath))
2433 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2434 contents = $"This project is already present in workspace." }.Modal();
2438 prj = LoadProject(filePath, null);
2441 const char * activeConfigName = null;
2442 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2443 prj.StartMonitoring();
2444 workspace.projects.Add(prj);
2445 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2446 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2447 activeConfigName = toolBar.activeConfig.currentRow.string;
2448 if(activeConfigName)
2450 for(cfg : prj.configurations)
2452 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2460 projectView.AddNode(prj.topNode, null);
2461 workspace.modified = true;
2463 findInFilesDialog.AddProjectItem(prj);
2464 projectView.ShowOutputBuildLog(true);
2465 projectView.DisplayCompiler(compiler, false);
2466 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2470 char location[MAX_LOCATION];
2471 StripLastDirectory(prj.topNode.path, location);
2472 ChangeProjectFileDialogDirectory(location);
2475 // projectView is associated with the main project and not with the one just added but
2476 return projectView; // just to let the caller know something was opened
2484 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2485 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2486 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2488 if(FileExists(filePath))
2489 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2490 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2491 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2494 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2497 else if(!strcmp(extension, "3ds"))
2499 if(FileExists(filePath))
2500 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2501 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2502 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2506 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2509 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2510 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2511 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2512 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2513 !strcmp(extension, "js"))
2515 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2516 editor.updatingCode = true;
2517 if(editor.LoadFile(filePath))
2520 editor.visible = true;
2524 needFileModified = false;
2528 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2529 if(editor.LoadFile(filePath))
2532 editor.visible = true;
2536 needFileModified = false;
2539 if(document && (document._class == class(PictureEdit) ||
2540 document._class == class(ModelView)))
2545 document.fileName = filePath;
2546 if(workspace && !workspace.holdTracking)
2547 workspace.UpdateOpenedFileInfo(filePath, opened);
2551 if(!document && createIfFails != no)
2553 if(createIfFails != yes && !needFileModified &&
2554 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2555 createIfFails = yes;
2556 if(createIfFails == yes || createIfFails == whatever)
2558 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2560 document.fileName = filePath;
2566 if(projectView && document._class == class(CodeEditor) && workspace)
2568 int lineNumber, position;
2570 CodeEditor editor = (CodeEditor)document;
2571 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2572 editor.openedFileInfo.holdTracking = true;
2573 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2574 position = Max(editor.openedFileInfo.position - 1, 0);
2575 if(editor.editBox.GoToLineNum(lineNumber))
2576 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2577 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2578 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2579 editor.editBox.scroll = scroll;
2580 editor.openedFileInfo.holdTracking = false;
2583 if(needFileModified)
2584 document.OnFileModified = OnFileModified;
2585 document.NotifySaved = DocumentSaved;
2586 if(maximizeDoc && document.hasMaximize)
2587 document.state = maximized;
2590 ideSettings.AddRecentProject(document.fileName);
2592 ideSettings.AddRecentFile(document.fileName);
2593 ide.UpdateRecentMenus();
2594 ide.AdjustFileMenus();
2595 settingsContainer.Save();
2603 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2604 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2606 if(!parentClosing && ide.workspace)
2607 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2610 bool ModelView::ModelViewOnClose(bool parentClosing)
2612 if(!parentClosing && ide.workspace)
2613 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2616 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2618 if(!parentClosing && ide.workspace)
2619 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2624 void OnUnloadGraphics(Window window)
2626 display.ClearMaterials();
2627 display.ClearTextures();
2628 display.ClearMeshes();
2632 void UpdateStateLight(StatusField fld, bool on)
2634 fld.color = on ? lime : Color { 128,128,128 };
2635 fld.backColor = on ? dimGray : 0;
2639 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2641 UpdateStateLight(caps, app.GetKeyState(capsState));
2642 UpdateStateLight(num, app.GetKeyState(numState));
2646 bool OnKeyDown(Key key, unichar ch)
2650 case b: projectView.Update(null); break;
2651 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2652 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2657 bool OnKeyUp(Key key, unichar ch)
2661 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2662 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2667 void GoToError(const char * line, bool noParsing)
2670 projectView.GoToError(line, noParsing);
2673 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath)
2675 FileAttribs result { };
2676 FileAttribs fileAttribs;
2680 strcpy(selectedPath, prj.topNode.path);
2681 else if(dir && dir[0])
2682 strcpy(selectedPath, dir);
2684 selectedPath[0] = '\0';
2685 PathCat(selectedPath, filePath);
2687 if((fileAttribs = FileExists(selectedPath)).isFile)
2688 result = fileAttribs;
2692 for(p : workspace.projects)
2694 strcpy(selectedPath, p.topNode.path);
2695 PathCat(selectedPath, filePath);
2696 if((fileAttribs = FileExists(selectedPath)).isFile)
2699 result = fileAttribs;
2706 ProjectNode n = null;
2707 for(p : workspace.projects)
2709 if((n = p.topNode.Find(filePath, false)))
2711 n.GetFullFilePath(selectedPath);
2712 if((fileAttribs = FileExists(selectedPath)).isFile)
2715 result = fileAttribs;
2720 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath)) && project &&
2721 (fileAttribs = FileExists(selectedPath)).isFile)
2724 result = fileAttribs;
2732 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
2735 const char *path = text;
2736 char *colon = strchr(text, ':');
2737 char filePath[MAX_LOCATION] = "";
2738 char completePath[MAX_LOCATION];
2739 int line = 0, col = 0;
2740 int len = strlen(text);
2742 FileAttribs fileAttribs;
2744 // support for valgrind output
2745 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2756 /*for(s=colon; *s; s++)
2765 //line = atoi(colon+1);
2767 // support for "Found n match(es) in "file/path";
2768 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)
2774 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2776 path = (colon - 1 > path) ? colon - 1 : path;
2777 colon = strstr(colon + 1, ":");
2779 if(*path == '*' && (s = strchr(path+1, '*')))
2781 while(isspace(*path)) path++;
2785 char * close = strchr(path, ')');
2789 strncpy(name, path+1, close - path - 1);
2790 name[close - path - 1] = '\0';
2791 for(p : ide.workspace.projects)
2793 if(!strcmp(p.name, name))
2803 prj = project ? project : (dir ? null : ide.project);
2806 strncpy(filePath, path, colon - path);
2807 filePath[colon - path] = '\0';
2808 line = atoi(colon + 1);
2809 colon = strstr(colon + 1, ":");
2811 col = atoi(colon + 1);
2813 else if(path - 1 >= text && *(path - 1) == '\"')
2815 colon = strchr(path, '\"');
2818 strncpy(filePath, path, colon - path);
2819 filePath[colon - path] = '\0';
2822 else if(path && !colon)
2824 strcpy(filePath, path);
2827 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath)))
2828 CodeLocationGoTo(completePath, fileAttribs, line, col);
2831 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2833 if(fileAttribs.isFile)
2835 char ext[MAX_EXTENSION];
2836 GetExtension(path, ext);
2838 if(binaryDocExt.Find(ext))
2840 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2842 char dirPath[MAX_LOCATION];
2843 StripLastDirectory(path, dirPath);
2848 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2849 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2851 EditBox editBox = codeEditor.editBox;
2852 editBox.GoToLineNum(line - 1);
2853 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2857 else if(fileAttribs.isDirectory)
2861 void OnRedraw(Surface surface)
2863 Bitmap bitmap = back.bitmap;
2865 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2868 void SheetSelected(SheetType sheetSelected)
2870 if(activeChild == sheet)
2872 if(sheetSelected == methods)
2874 viewPropertiesItem.accelerator = f4;
2875 viewPropertiesItem.parent = viewMenu;
2876 viewMethodsItem.parent = null;
2880 viewMethodsItem.accelerator = f4;
2881 viewMethodsItem.parent = viewMenu;
2882 viewPropertiesItem.parent = null;
2887 viewMethodsItem.parent = viewMenu;
2888 viewPropertiesItem.parent = viewMenu;
2889 if(sheetSelected == methods)
2891 viewMethodsItem.accelerator = f4;
2892 viewPropertiesItem.accelerator = 0;
2896 viewMethodsItem.accelerator = 0;
2897 viewPropertiesItem.accelerator = f4;
2902 void OnActivateClient(Window client, Window previous)
2904 //if(!client || client != previous)
2907 if(!client || client != previous)
2910 dataType = previous._class;
2911 if(previous && !strcmp(dataType.name, "CodeEditor"))
2913 ((CodeEditor)previous).UpdateFormCode();
2915 else if(previous && !strcmp(dataType.name, "Designer"))
2917 ((Designer)previous).codeEditor.UpdateFormCode();
2922 dataType = client._class;
2923 if(client && !strcmp(dataType.name, "CodeEditor"))
2925 CodeEditor codeEditor = (CodeEditor)client;
2926 SetPrivateModule(codeEditor.privateModule);
2927 SetCurrentContext(codeEditor.globalContext);
2928 SetTopContext(codeEditor.globalContext);
2929 SetGlobalContext(codeEditor.globalContext);
2931 SetDefines(&codeEditor.defines);
2932 SetImports(&codeEditor.imports);
2934 SetActiveDesigner(codeEditor.designer);
2936 sheet.codeEditor = codeEditor;
2937 toolBox.codeEditor = codeEditor;
2939 viewDesignerItem.parent = viewMenu;
2940 if(activeChild != codeEditor)
2942 viewCodeItem.parent = viewMenu;
2943 viewDesignerItem.accelerator = 0;
2944 viewCodeItem.accelerator = f8;
2948 viewCodeItem.parent = null;
2949 viewDesignerItem.accelerator = f8;
2952 else if(client && !strcmp(dataType.name, "Designer"))
2954 CodeEditor codeEditor = ((Designer)client).codeEditor;
2957 SetPrivateModule(codeEditor.privateModule);
2958 SetCurrentContext(codeEditor.globalContext);
2959 SetTopContext(codeEditor.globalContext);
2960 SetGlobalContext(codeEditor.globalContext);
2961 SetDefines(&codeEditor.defines);
2962 SetImports(&codeEditor.imports);
2966 SetPrivateModule(null);
2967 SetCurrentContext(null);
2968 SetTopContext(null);
2969 SetGlobalContext(null);
2974 SetActiveDesigner((Designer)client);
2976 sheet.codeEditor = codeEditor;
2977 toolBox.codeEditor = codeEditor;
2979 viewCodeItem.parent = viewMenu;
2980 if(activeChild != client)
2982 viewDesignerItem.parent = viewMenu;
2983 viewDesignerItem.accelerator = f8;
2984 viewCodeItem.accelerator = 0;
2988 viewDesignerItem.parent = null;
2989 viewCodeItem.accelerator = f8;
2994 if(!client && !projectView && sheet.visible)
2997 sheet.visible = false;
2998 toolBox.visible = false;
3001 sheet.codeEditor = null;
3002 toolBox.codeEditor = null;
3003 SetActiveDesigner(null);
3005 viewDesignerItem.parent = null;
3006 viewCodeItem.parent = null;
3009 SheetSelected(sheet.sheetSelected);
3012 projectCompileItem = null;
3017 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3019 CodeEditor codeEditor = (CodeEditor)client;
3020 EditBox editBox = codeEditor.editBox;
3022 statusBar.AddField(pos);
3024 caps = { width = 40, text = $"CAPS" };
3025 statusBar.AddField(caps);
3026 UpdateStateLight(caps, app.GetKeyState(capsState));
3028 ovr = { width = 36, text = $"OVR" };
3029 statusBar.AddField(ovr);
3030 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3032 num = { width = 36, text = $"NUM" };
3033 statusBar.AddField(num);
3034 UpdateStateLight(num, app.GetKeyState(numState));
3036 //statusBar.text = "Ready";
3038 if(projectView && projectView.project)
3040 bool isCObject = false;
3041 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3042 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3046 char nodeName[MAX_FILENAME];
3047 char name[MAX_FILENAME+96];
3049 ChangeExtension(node.name, "c", nodeName);
3050 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3051 projectCompileItem =
3053 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3055 bool NotifySelect(MenuItem selection, Modifiers mods)
3059 bool isCObject = false;
3060 bool isExcluded = false;
3061 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3065 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3068 List<ProjectNode> nodes { };
3070 projectView.Compile(node.project, nodes, mods.ctrl && mods.shift, isCObject ? cObject : normal);
3078 projectMenu.AddDynamic(projectCompileItem, ide, false);
3084 caps = ovr = num = null;
3089 bool OnClose(bool parentClosing)
3091 //return !projectView.buildInProgress;
3092 if(projectView && projectView.buildInProgress)
3094 if(DontTerminateDebugSession($"Close IDE"))
3096 if(findInFilesDialog)
3097 findInFilesDialog.SearchStop();
3100 workspace.timer.Stop();
3103 ideMainFrame.Destroy(0);
3110 bool passThrough = false;
3111 bool debugWorkDir = false;
3112 char * passDebugWorkDir = null;
3113 bool openAsText = false;
3114 DynamicString passArgs { };
3117 for(c = 1; c<app.argc; c++)
3121 const char * arg = app.argv[c];
3122 char * buf = new char[strlen(arg)*2+1];
3124 passArgs.concat(" ");
3126 passArgs.concat(buf);
3129 else if(debugWorkDir)
3131 passDebugWorkDir = CopyString(app.argv[c]);
3132 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3133 debugWorkDir = false;
3135 else if(!strcmp(app.argv[c], "-t"))
3137 else if(!strcmp(app.argv[c], "-no-parsing"))
3138 ide.noParsing = true;
3139 else if(!strcmp(app.argv[c], "-debug-start"))
3140 ide.debugStart = true;
3141 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3142 debugWorkDir = true;
3143 else if(!strcmp(app.argv[c], "-@"))
3147 char fullPath[MAX_LOCATION];
3148 char parentPath[MAX_LOCATION];
3149 char ext[MAX_EXTENSION];
3151 FileAttribs dirAttribs;
3152 GetWorkingDir(fullPath, MAX_LOCATION);
3153 PathCat(fullPath, app.argv[c]);
3154 StripLastDirectory(fullPath, parentPath);
3155 GetExtension(app.argv[c], ext);
3156 isProject = !openAsText && !strcmpi(ext, "epj");
3158 if(isProject && c > 1 + (ide.debugStart ? 1 : 0)) continue;
3160 // Create directory for projects (only)
3161 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3163 if(isProject && !FileExists(fullPath))
3165 char name[MAX_LOCATION];
3166 NewProjectDialog newProjectDialog;
3170 projectView.visible = false;
3171 if(!projectView.Destroy(0))
3175 newProjectDialog = { master = this };
3177 strcpy(name, app.argv[c]);
3178 StripExtension(name);
3179 GetLastDirectory(name, name);
3180 newProjectDialog.projectName.contents = name;
3181 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3182 newProjectDialog.locationEditBox.path = parentPath;
3183 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3185 incref newProjectDialog;
3186 newProjectDialog.Modal();
3189 ideSettings.AddRecentProject(projectView.fileName);
3190 ide.UpdateRecentMenus();
3191 settingsContainer.Save();
3193 delete newProjectDialog;
3194 // Open only one project
3198 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3200 else if(strstr(fullPath, "http://") == fullPath)
3201 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3204 if(passThrough && projectView && projectView.project && workspace)
3205 workspace.commandLineArgs = passArgs;
3206 if(passDebugWorkDir && projectView && projectView.project && workspace)
3208 workspace.debugDir = passDebugWorkDir;
3209 delete passDebugWorkDir;
3212 UpdateToolBarActiveConfigs(false);
3213 UpdateToolBarActiveCompilers();
3220 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3223 projectView.visible = false;
3224 projectView.Destroy(0);
3227 #ifdef GDB_DEBUG_GUI
3228 gdbDialog.Destroy(0);
3233 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3237 char * oldPaths[128];
3238 String oldList = new char[maxPathLen];
3239 Array<String> newExePaths { };
3240 //Map<String, bool> exePathExists { };
3242 #if defined(__unix__) || defined(__APPLE__)
3243 Array<String> newLibPaths { };
3244 Map<String, bool> libPathExists { };
3249 for(prj : workspace.projects)
3251 DirExpression targetDirExp;
3253 // SKIP FIRST PROJECT...
3254 if(prj == workspace.projects.firstIterator.data) continue;
3256 // NOTE: Right now the additional project config dir will be
3257 // obtained when the debugger is started, so toggling it
3258 // while building will change which library gets used.
3259 // To go with the initial state, e.g. when F5 was pressed,
3260 // we nould need to keep a list of all project's active
3261 // config upon startup.
3262 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3264 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3268 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3269 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3273 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3274 if(cfg.targetType == sharedLibrary && cfg.debug)
3278 if(targetDirExp.dir)
3280 char buffer[MAX_LOCATION];
3281 #if defined(__WIN32__)
3282 Array<String> paths = newExePaths;
3284 Array<String> paths = newLibPaths;
3286 GetSystemPathBuffer(buffer, prj.topNode.path);
3287 PathCat(buffer, targetDirExp.dir);
3290 if(!fstrcmp(p, buffer))
3297 paths.Add(CopyString(buffer));
3299 delete targetDirExp;
3303 for(item : compiler.executableDirs)
3306 for(p : newExePaths)
3308 if(!fstrcmp(p, item))
3315 newExePaths.Add(CopySystemPath(item));
3318 GetEnvironment("PATH", oldList, maxPathLen);
3320 printf("Old value of PATH: %s\n", oldList);
3322 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3323 for(c = 0; c < count; c++)
3326 for(p : newExePaths)
3328 if(!fstrcmp(p, oldPaths[c]))
3335 newExePaths.Add(CopySystemPath(oldPaths[c]));
3339 for(path : newExePaths)
3340 len += strlen(path) + 1;
3341 newList = new char[len + 1];
3343 for(path : newExePaths)
3345 strcat(newList, path);
3346 strcat(newList, pathListSep);
3348 newList[len - 1] = '\0';
3349 SetEnvironment("PATH", newList);
3351 printf("New value of PATH: %s\n", newList);
3358 #if defined(__unix__) || defined(__APPLE__)
3360 for(item : compiler.libraryDirs)
3362 if(!libPathExists[item]) // fstrcmp should be used
3364 String s = CopyString(item);
3366 libPathExists[s] = true;
3370 #if defined(__APPLE__)
3371 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3373 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3376 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3378 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3379 for(c = 0; c < count; c++)
3381 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3383 String s = CopyString(oldPaths[c]);
3385 libPathExists[s] = true;
3390 for(path : newLibPaths)
3391 len += strlen(path) + 1;
3392 newList = new char[len + 1];
3394 for(path : newLibPaths)
3396 strcat(newList, path);
3397 strcat(newList, pathListSep);
3399 newList[len - 1] = '\0';
3400 #if defined(__APPLE__)
3401 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3403 SetEnvironment("LD_LIBRARY_PATH", newList);
3406 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3412 delete libPathExists;
3415 if(compiler.distccEnabled && compiler.distccHosts)
3416 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3421 void DestroyTemporaryProjectDir()
3423 if(tmpPrjDir && tmpPrjDir[0])
3425 if(FileExists(tmpPrjDir).isDirectory)
3426 DestroyDir(tmpPrjDir);
3427 property::tmpPrjDir = null;
3433 // Graphics Driver Menu
3436 app.currentSkin.selectionColor = selectionColor;
3437 app.currentSkin.selectionText = selectionText;
3441 driverItems = new MenuItem[app.numDrivers];
3442 for(c = 0; c < app.numDrivers; c++)
3444 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3445 driverItems[c].id = c;
3446 driverItems[c].isRadio = true;
3449 driverItems = new MenuItem[2];
3450 #if defined(__unix__)
3451 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3452 driverItems[0].id = 0;
3453 driverItems[0].isRadio = true;
3455 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3456 driverItems[0].id = 0;
3457 driverItems[0].isRadio = true;
3459 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3460 driverItems[1].id = 1;
3461 driverItems[1].isRadio = true;
3463 /* skinItems = new MenuItem[app.numSkins];
3464 for(c = 0; c < app.numSkins; c++)
3466 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3467 skinItems[c].id = c;
3468 skinItems[c].isRadio = true;
3471 ideFileDialog.master = this;
3472 ideProjectFileDialog.master = this;
3474 //SetDriverAndSkin();
3478 void UpdateRecentMenus()
3481 Menu fileMenu = menu.FindMenu($"File");
3482 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3483 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3484 char * itemPath = new char[MAX_LOCATION];
3485 char * itemName = new char[MAX_LOCATION+4];
3487 recentFiles.Clear();
3490 for(recent : ideSettings.recentFiles)
3492 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3493 MakeSystemPath(itemPath);
3494 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3495 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3499 recentProjects.Clear();
3501 for(recent : ideSettings.recentProjects)
3503 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3504 MakeSystemPath(itemPath);
3505 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3506 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3518 delete languageItems;
3522 documentor.Puts("Quit\n");
3529 void DestroyDir(char * path)
3531 RecursiveDeleteFolderFSI fsi { };
3536 #if defined(__WIN32__)
3537 define sdkDirName = "Ecere SDK";
3539 define sdkDirName = "ecere";
3542 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3545 char * v = new char[maxPathLen];
3549 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3550 StripLastDirectory(path, path);
3551 PathCat(path, subDir);
3552 if(name) PathCat(path, name);
3553 if(FileExists(path) & attribs) found = true;
3555 #if defined(__WIN32__)
3558 GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3561 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3562 PathCat(path, subDir);
3563 if(name) PathCat(path, name);
3564 if(FileExists(path) & attribs) found = true;
3569 GetEnvironment("AppData", v, maxPathLen);
3572 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3573 PathCat(path, sdkDirName);
3574 PathCat(path, subDir);
3575 if(name) PathCat(path, name);
3576 if(FileExists(path) & attribs) found = true;
3581 GetEnvironment("ProgramData", v, maxPathLen);
3584 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3585 PathCat(path, sdkDirName);
3586 PathCat(path, subDir);
3587 if(name) PathCat(path, name);
3588 if(FileExists(path) & attribs) found = true;
3593 GetEnvironment("ProgramFiles", v, maxPathLen);
3596 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3597 PathCat(path, sdkDirName);
3598 PathCat(path, subDir);
3599 if(name) PathCat(path, name);
3600 if(FileExists(path) & attribs) found = true;
3605 GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3608 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3609 PathCat(path, sdkDirName);
3610 PathCat(path, subDir);
3611 if(name) PathCat(path, name);
3612 if(FileExists(path) & attribs) found = true;
3617 GetEnvironment("SystemDrive", v, maxPathLen);
3620 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3621 PathCat(path, "Program Files");
3622 PathCat(path, sdkDirName);
3623 PathCat(path, subDir);
3624 if(name) PathCat(path, name);
3625 if(FileExists(path) & attribs) found = true;
3634 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3635 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3636 for(c=0; c<numTokens; c++)
3638 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3639 PathCat(path, sdkDirName);
3640 PathCat(path, subDir);
3641 if(name) PathCat(path, name);
3642 if(FileExists(path) & attribs) found = true;
3650 void FindAndShellOpenInstalledFolder(const char * name)
3652 char path[MAX_LOCATION];
3653 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3657 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3659 char path[MAX_LOCATION];
3660 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3664 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3666 bool preserveRootFolder;
3668 void OutFolder(const char * folderPath, bool isRoot)
3670 if(!(preserveRootFolder && isRoot))
3671 RemoveDir(folderPath);
3674 bool OnFile(const char * filePath)
3676 DeleteFile(filePath);
3681 class IDEApp : GuiApplication
3683 //driver = "Win32Console";
3684 // driver = "OpenGL";
3688 TempFile includeFile { };
3693 char ext[MAX_EXTENSION];
3694 SetLoggingMode(stdOut, null);
3695 //SetLoggingMode(debug, null);
3697 settingsContainer.Load();
3699 if(ideSettings.language)
3701 const String language = GetLanguageString();
3702 if(ideSettings.language.OnCompare(language))
3704 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3709 // First count files arg to decide whether to maximize
3711 bool passThrough = false, debugWorkDir = false;
3714 for(c = 1; c<app.argc; c++)
3717 else if(debugWorkDir)
3718 debugWorkDir = false;
3719 else if(!strcmp(app.argv[c], "-t"));
3720 else if(!strcmp(app.argv[c], "-no-parsing"));
3721 else if(!strcmp(app.argv[c], "-debug-start"));
3722 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3723 debugWorkDir = true;
3724 else if(!strcmp(app.argv[c], "-@"))
3731 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3733 app.driver = "OpenGL";
3734 ide.driverItems[1].checked = true;
3738 #if defined(__unix__) || defined(__APPLE__)
3739 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3741 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3743 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3747 char model[MAX_LOCATION];
3748 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3750 ide.duck.modelFile = model;
3751 ide.duck.parent = ideMainFrame;
3754 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3755 ide.debugRubberDuck.disabled = false;
3759 desktop.caption = titleECEREIDE;
3762 for(c = 1; c<app.argc; c++)
3764 char fullPath[MAX_LOCATION];
3765 GetWorkingDir(fullPath, MAX_LOCATION);
3766 PathCat(fullPath, app.argv[c]);
3767 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3771 // Default to language specified by environment if no language selected
3772 if(!ideSettings.language)
3774 ideSettings.language = GetLanguageString();
3775 settingsContainer.Save();
3778 // Default to home directory if no directory yet set up
3779 if(!ideSettings.ideProjectFileDialogLocation[0])
3782 char location[MAX_LOCATION];
3783 char * home = getenv("HOME");
3784 char * homeDrive = getenv("HOMEDRIVE");
3785 char * homePath = getenv("HOMEPATH");
3786 char * userProfile = getenv("USERPROFILE");
3787 char * systemDrive = getenv("SystemDrive");
3788 if(home && FileExists(home).isDirectory)
3790 strcpy(location, home);
3793 if(!found && homeDrive && homePath)
3795 strcpy(location, homeDrive);
3796 PathCat(location, homePath);
3797 if(FileExists(location).isDirectory)
3800 if(!found && FileExists(userProfile).isDirectory)
3802 strcpy(location, userProfile);
3805 if(!found && FileExists(systemDrive).isDirectory)
3807 strcpy(location, systemDrive);
3812 ideSettings.ideProjectFileDialogLocation = location;
3813 if(!ideSettings.ideFileDialogLocation[0])
3814 ideSettings.ideFileDialogLocation = location;
3818 if(!LoadIncludeFile())
3819 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3821 // Create language menu
3823 String language = ideSettings.language;
3827 ide.languageItems = new MenuItem[languages.count];
3830 ide.languageItems[i] =
3832 ide.languageMenu, l.name;
3833 bitmap = { l.bitmap };
3837 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3839 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3841 // Re-select previous selected language if aborted
3842 String language = ideSettings.language;
3846 if(((!language || !language[0]) && i == 0) ||
3847 (language && !strcmpi(l.code, language)))
3849 ide.languageItems[i].checked = true;
3861 // Try to find country-specific language first
3867 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3869 ide.languageItems[i].checked = true;
3877 // Try generalizing locale
3878 if(!found && language)
3881 char genericLocale[256];
3883 strncpy(genericLocale, language, sizeof(genericLocale));
3884 genericLocale[sizeof(genericLocale)-1] = 0;
3886 under = strchr(genericLocale, '_');
3889 if(!strcmpi(genericLocale, "zh"))
3890 strcpy(genericLocale, "zh_CN");
3891 if(strcmp(genericLocale, language))
3895 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3897 ide.languageItems[i].checked = true;
3907 ide.languageItems[0].checked = true;
3909 MenuDivider { ide.languageMenu };
3912 ide.languageMenu, "Help Translate";
3914 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3916 ShellOpen("http://translations.launchpad.net/ecere");
3922 ideMainFrame.Create();
3923 if(app.argFilesCount > 1)
3924 ide.MenuWindowTileVert(null, 0);
3928 bool Cycle(bool idle)
3932 if(ide.documentor.Peek())
3935 ide.documentor.GetLine(line, sizeof(line));
3936 if(!strcmpi(line, "Exited"))
3938 ide.documentor.CloseInput();
3939 ide.documentor.CloseOutput();
3940 ide.documentor.Wait();
3941 delete ide.documentor;
3944 if(ide.documentor && ide.documentor.eof)
3946 ide.documentor.CloseInput();
3947 ide.documentor.CloseOutput();
3948 ide.documentor.Wait();
3949 delete ide.documentor;
3955 bool LoadIncludeFile()
3957 bool result = false;
3958 File include = FileOpen(":crossplatform.mk", read);
3961 File f = includeFile;
3964 for(; !include.Eof(); )
3967 int count = include.Read(buffer, 1, 4096);
3968 f.Write(buffer, 1, count);
3978 IDEMainFrame ideMainFrame { };
3980 define app = ((IDEApp)__thisModule);
3982 define titleECEREIDE = $"Ecere IDE (Debug)";
3984 define titleECEREIDE = $"Ecere IDE";