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);
1894 void UpdateToolBarActiveConfigs(bool selectionOnly)
1896 bool commonSelected = false;
1897 DataRow row = toolBar.activeConfig.currentRow;
1899 row = toolBar.activeConfig.FindRow(1);
1902 toolBar.activeConfig.Clear();
1903 row = toolBar.activeConfig.AddString($"(Mixed)");
1908 char * configName = null;
1911 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1912 for(prj : workspace.projects)
1914 for(cfg : prj.configurations)
1917 configs[cfg.name] = 1;
1922 toolBar.activeConfig.AddString(&name);
1926 if(projectView && projectView.project)
1928 for(prj : workspace.projects)
1930 if(prj.config && prj.config.name)
1932 configName = prj.config.name;
1938 commonSelected = true;
1939 for(prj : workspace.projects)
1941 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1943 commonSelected = false;
1951 commonSelected = false;
1952 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1954 if(!strcmp(row.string, configName))
1956 toolBar.activeConfig.currentRow = row;
1957 commonSelected = true;
1964 toolBar.activeConfig.Sort(null, 0);
1966 toolBar.activeConfig.currentRow = row;
1971 bool unavailable = !project;
1973 projectAddItem.disabled = unavailable;
1974 toolBar.buttonAddProject.disabled = unavailable;
1976 projectSettingsItem.disabled = unavailable;
1978 projectBrowseFolderItem.disabled = unavailable;
1980 viewProjectItem.disabled = unavailable;
1982 toolBar.activeConfig.disabled = unavailable;
1983 toolBar.activeCompiler.disabled = unavailable;
1984 toolBar.activeBitDepth.disabled = unavailable;
1987 debugUseValgrindItem.disabled = unavailable;
1988 AdjustValgrindMenus();
1997 void AdjustValgrindMenus()
1999 bool unavailable = !project || !debugUseValgrindItem.checked;
2000 debugValgrindNoLeakCheckItem.disabled = unavailable;
2001 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2002 debugValgrindYesLeakCheckItem.disabled = unavailable;
2003 debugValgrindFullLeakCheckItem.disabled = unavailable;
2005 debugValgrindTrackOriginsItem.disabled = unavailable;
2007 debugValgrindRSDefaultItem.disabled = unavailable;
2008 debugValgrindRS0Item.disabled = unavailable;
2009 debugValgrindRS16Item.disabled = unavailable;
2010 debugValgrindRS32Item.disabled = unavailable;
2011 debugValgrindRS64Item.disabled = unavailable;
2012 debugValgrindRS128Item.disabled = unavailable;
2013 debugValgrindRS256Item.disabled = unavailable;
2014 debugValgrindRS512Item.disabled = unavailable;
2018 property bool hasOpenedCodeEditors
2023 for(w = firstChild; w; w = w.next)
2024 if(w._class == class(CodeEditor) &&
2025 w.isDocument && !w.closing && w.visible && w.created &&
2026 w.fileName && w.fileName[0])
2032 void AdjustFileMenus()
2034 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2036 projectQuickItem.disabled = unavailable;
2039 void AdjustBuildMenus()
2041 bool unavailable = project && projectView.buildInProgress;
2042 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2044 projectNewItem.disabled = unavailable;
2045 toolBar.buttonNewProject.disabled = unavailable;
2046 projectOpenItem.disabled = unavailable;
2047 toolBar.buttonOpenProject.disabled = unavailable;
2049 unavailable = !project || projectView.buildInProgress;
2051 projectCloseItem.disabled = unavailable;
2052 // toolBar.buttonCloseProject.disabled = unavailable;
2054 projectRunItem.disabled = naForRun;
2055 toolBar.buttonRun.disabled = naForRun;
2057 projectBuildItem.disabled = false;
2058 projectBuildItem.text = unavailable ? $"Stop Build" : $"Build";
2059 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2061 projectLinkItem.disabled = unavailable;
2062 toolBar.buttonReLink.disabled = unavailable;
2063 projectRebuildItem.disabled = unavailable;
2064 toolBar.buttonRebuild.disabled = unavailable;
2065 projectCleanItem.disabled = unavailable;
2066 toolBar.buttonClean.disabled = unavailable;
2067 projectCleanTargetItem.disabled = unavailable;
2068 projectRealCleanItem.disabled = unavailable;
2069 // toolBar.buttonRealClean.disabled = unavailable;
2070 projectRegenerateItem.disabled = unavailable;
2071 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2072 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2073 projectInstallItem.disabled = unavailable;
2074 toolBar.buttonInstall.disabled = unavailable;
2076 projectCompileItem.disabled = unavailable;
2078 AdjustPopupBuildMenus();
2081 void AdjustPopupBuildMenus()
2083 bool unavailable = !project || projectView.buildInProgress;
2085 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2088 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
2091 menu.disabled = false;
2092 menu.text = unavailable ? $"Stop Build" : $"Build";
2093 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2096 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0); if(menu) menu.disabled = unavailable;
2097 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0); if(menu) menu.disabled = unavailable;
2098 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0); if(menu) menu.disabled = unavailable;
2099 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0); if(menu) menu.disabled = unavailable;
2100 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0); if(menu) menu.disabled = unavailable;
2101 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
2102 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, 0); if(menu) menu.disabled = unavailable;
2103 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0); if(menu) menu.disabled = unavailable;
2104 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0); if(menu) menu.disabled = unavailable;
2105 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0); if(menu) menu.disabled = unavailable;
2106 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0); if(menu) menu.disabled = unavailable;
2107 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0); if(menu) menu.disabled = unavailable;
2108 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
2109 projectView.popupMenu.Update(null);
2113 property bool areDebugMenusUnavailable { get {
2115 project.GetTargetType(project.config) != executable ||
2116 projectView.buildInProgress == buildingMainProject;
2119 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2120 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2121 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2123 void AdjustDebugMenus()
2125 bool unavailable = areDebugMenusUnavailable;
2126 bool running = isDebuggerRunning;
2127 bool stopped = isDebuggerStopped;
2128 bool active = debugger.isActive;
2130 bool isNotRunning = unavailable || !running;
2131 bool isNotNotRunning = unavailable || running;
2132 bool isNotStopped = unavailable || !stopped;
2133 bool isNotActive = unavailable || !active;
2135 debugStartResumeItem.disabled = isNotNotRunning;
2136 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2137 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2140 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2141 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2144 debugBreakItem.disabled = isNotRunning;
2145 debugStopItem.disabled = isNotActive;
2146 debugRestartItem.disabled = isNotActive;
2149 toolBar.buttonDebugPause.disabled = isNotRunning;
2150 toolBar.buttonDebugStop.disabled = isNotActive;
2151 toolBar.buttonDebugRestart.disabled = isNotActive;
2154 debugStepIntoItem.disabled = isNotNotRunning;
2155 debugStepOverItem.disabled = isNotNotRunning;
2156 debugSkipStepOverItem.disabled = isNotNotRunning;
2157 debugStepOutItem.disabled = isNotStopped;
2158 debugSkipStepOutItem.disabled = isNotStopped;
2160 debugStepUntilItem.disabled = isNotStopped;
2161 debugSkipStepUntilItem.disabled = isNotStopped;
2165 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2166 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2167 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2168 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2169 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2171 if((Designer)GetActiveDesigner())
2173 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2175 codeEditor.AdjustDebugMenus();
2179 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2181 char tempString[MAX_LOCATION];
2182 strcpy(tempString, directory);
2183 if(saveSettings && !projectView)
2185 ideSettings.ideFileDialogLocation = directory;
2186 settingsContainer.Save();
2189 ideFileDialog.currentDirectory = tempString;
2190 codeEditorFileDialog.currentDirectory = tempString;
2191 codeEditorFormFileDialog.currentDirectory = tempString;
2194 void ChangeProjectFileDialogDirectory(char * directory)
2196 ideSettings.ideProjectFileDialogLocation = directory;
2197 settingsContainer.Save();
2200 Window FindWindow(const char * filePath)
2202 Window document = null;
2204 // TOCHECK: Do we need to change slashes here?
2205 for(document = firstChild; document; document = document.next)
2207 const char * fileName = document.fileName;
2208 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2210 document.visible = true;
2211 document.Activate();
2218 bool DontTerminateDebugSession(const char * title)
2220 if(debugger.isActive)
2222 if(MessageBox { type = yesNo, master = ide,
2223 contents = $"Do you want to terminate the debugging session in progress?",
2224 text = title }.Modal() == no)
2227 MessageBox msg { type = yesNo, master = ide,
2228 contents = "Do you want to terminate the debugging session in progress?",
2230 if(msg.Modal() == no)
2242 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2244 char extension[MAX_EXTENSION] = "";
2245 Window document = null;
2246 bool isProject = false;
2247 bool needFileModified = true;
2248 char winFilePath[MAX_LOCATION];
2249 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2250 Window currentDoc = activeClient;
2251 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2254 GetExtension(filePath, extension);
2258 strcpy(extension, type);
2260 if(strcmp(extension, ProjectExtension))
2262 for(document = firstChild; document; document = document.next)
2264 const char * fileName = document.fileName;
2265 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2267 document.visible = true;
2269 document.Activate();
2275 if(createIfFails == whatever)
2277 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2279 needFileModified = false;
2280 if(openMethod == normal)
2282 if(DontTerminateDebugSession($"Open Project"))
2291 Workspace workspace = null;
2293 if(FileExists(filePath))
2295 if(!strcmp(extension, ProjectExtension))
2297 char workspaceFile[MAX_LOCATION];
2298 strcpy(workspaceFile, filePath);
2299 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2300 workspace = LoadWorkspace(workspaceFile, filePath);
2302 else if(!strcmp(extension, WorkspaceExtension))
2303 workspace = LoadWorkspace(filePath, null);
2310 CreateProjectView(workspace, filePath);
2311 document = projectView;
2313 toolBox.visible = true;
2314 sheet.visible = true;
2315 projectView.MakeActive();
2317 workspace.ParseLoadedBreakpoints();
2318 workspace.DropInvalidBreakpoints(null);
2321 ide.projectView.ShowOutputBuildLog(true);
2323 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2324 ide.projectView.DisplayCompiler(compiler, false);
2327 UpdateCompilerConfigs(false);
2330 char newWorkingDir[MAX_LOCATION];
2331 StripLastDirectory(filePath, newWorkingDir);
2332 ChangeFileDialogsDirectory(newWorkingDir, false);
2335 document.fileName = filePath;
2337 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2339 // this crashes on starting ide with epj file, solution please?
2340 // app.UpdateDisplay();
2342 workspace.holdTracking = true;
2343 for(ofi : workspace.openedFiles)
2345 if(ofi.state != closed)
2347 Window file = OpenFile(ofi.path, false, true, null, no, normal, noParsing);
2350 char fileName[MAX_LOCATION];
2352 GetLastDirectory(ofi.path, fileName);
2353 node = projectView.project.topNode.Find(fileName, true);
2355 node.EnsureVisible();
2359 ide.RepositionWindows(false);
2360 workspace.holdTracking = false;
2362 workspace.timer.Start();
2364 #if !defined(__WIN32__)
2365 // Valgrind Debug menu updates
2366 debugUseValgrindItem.checked = workspace.useValgrind;
2368 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2369 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2370 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2371 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2373 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2374 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2375 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2376 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2377 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2378 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2379 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2380 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2382 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2385 findInFilesDialog.mode = FindInFilesMode::project;
2386 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2389 char location[MAX_LOCATION];
2390 StripLastDirectory(ide.project.topNode.path, location);
2391 ChangeProjectFileDialogDirectory(location);
2398 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2400 ideProjectFileDialog.text = openProjectFileDialogTitle;
2401 if(ideProjectFileDialog.Modal() == cancel)
2403 filePath = ideProjectFileDialog.filePath;
2404 GetExtension(filePath, extension);
2415 else if(openMethod == add)
2420 char slashFilePath[MAX_LOCATION];
2421 GetSlashPathBuffer(slashFilePath, filePath);
2422 for(p : workspace.projects)
2424 if(!fstrcmp(p.filePath, slashFilePath))
2432 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2433 contents = $"This project is already present in workspace." }.Modal();
2437 prj = LoadProject(filePath, null);
2440 const char * activeConfigName = null;
2441 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2442 prj.StartMonitoring();
2443 workspace.projects.Add(prj);
2444 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2445 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2446 activeConfigName = toolBar.activeConfig.currentRow.string;
2447 if(activeConfigName)
2449 for(cfg : prj.configurations)
2451 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2459 projectView.AddNode(prj.topNode, null);
2460 workspace.modified = true;
2462 findInFilesDialog.AddProjectItem(prj);
2463 projectView.ShowOutputBuildLog(true);
2464 projectView.DisplayCompiler(compiler, false);
2465 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2469 char location[MAX_LOCATION];
2470 StripLastDirectory(prj.topNode.path, location);
2471 ChangeProjectFileDialogDirectory(location);
2474 // projectView is associated with the main project and not with the one just added but
2475 return projectView; // just to let the caller know something was opened
2483 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2484 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2485 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2487 if(FileExists(filePath))
2488 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2489 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2490 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2493 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2496 else if(!strcmp(extension, "3ds"))
2498 if(FileExists(filePath))
2499 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2500 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2501 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2505 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2508 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2509 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2510 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2511 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2512 !strcmp(extension, "js"))
2514 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2515 editor.updatingCode = true;
2516 if(editor.LoadFile(filePath))
2519 editor.visible = true;
2523 needFileModified = false;
2527 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2528 if(editor.LoadFile(filePath))
2531 editor.visible = true;
2535 needFileModified = false;
2538 if(document && (document._class == class(PictureEdit) ||
2539 document._class == class(ModelView)))
2544 document.fileName = filePath;
2545 if(workspace && !workspace.holdTracking)
2546 workspace.UpdateOpenedFileInfo(filePath, opened);
2550 if(!document && createIfFails != no)
2552 if(createIfFails != yes && !needFileModified &&
2553 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2554 createIfFails = yes;
2555 if(createIfFails == yes || createIfFails == whatever)
2557 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2559 document.fileName = filePath;
2565 if(projectView && document._class == class(CodeEditor) && workspace)
2567 int lineNumber, position;
2569 CodeEditor editor = (CodeEditor)document;
2570 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2571 editor.openedFileInfo.holdTracking = true;
2572 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2573 position = Max(editor.openedFileInfo.position - 1, 0);
2574 if(editor.editBox.GoToLineNum(lineNumber))
2575 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2576 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2577 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2578 editor.editBox.scroll = scroll;
2579 editor.openedFileInfo.holdTracking = false;
2582 if(needFileModified)
2583 document.OnFileModified = OnFileModified;
2584 document.NotifySaved = DocumentSaved;
2585 if(maximizeDoc && document.hasMaximize)
2586 document.state = maximized;
2589 ideSettings.AddRecentProject(document.fileName);
2591 ideSettings.AddRecentFile(document.fileName);
2592 ide.UpdateRecentMenus();
2593 ide.AdjustFileMenus();
2594 settingsContainer.Save();
2602 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2603 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2605 if(!parentClosing && ide.workspace)
2606 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2609 bool ModelView::ModelViewOnClose(bool parentClosing)
2611 if(!parentClosing && ide.workspace)
2612 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2615 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2617 if(!parentClosing && ide.workspace)
2618 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2623 void OnUnloadGraphics(Window window)
2625 display.ClearMaterials();
2626 display.ClearTextures();
2627 display.ClearMeshes();
2631 void UpdateStateLight(StatusField fld, bool on)
2633 fld.color = on ? lime : Color { 128,128,128 };
2634 fld.backColor = on ? dimGray : 0;
2638 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2640 UpdateStateLight(caps, app.GetKeyState(capsState));
2641 UpdateStateLight(num, app.GetKeyState(numState));
2645 bool OnKeyDown(Key key, unichar ch)
2649 case b: projectView.Update(null); break;
2650 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2651 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2656 bool OnKeyUp(Key key, unichar ch)
2660 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2661 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2666 void GoToError(const char * line, bool noParsing)
2669 projectView.GoToError(line, noParsing);
2672 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath)
2674 FileAttribs result { };
2675 FileAttribs fileAttribs;
2679 strcpy(selectedPath, prj.topNode.path);
2680 else if(dir && dir[0])
2681 strcpy(selectedPath, dir);
2683 selectedPath[0] = '\0';
2684 PathCat(selectedPath, filePath);
2686 if((fileAttribs = FileExists(selectedPath)).isFile)
2687 result = fileAttribs;
2691 for(p : workspace.projects)
2693 strcpy(selectedPath, p.topNode.path);
2694 PathCat(selectedPath, filePath);
2695 if((fileAttribs = FileExists(selectedPath)).isFile)
2698 result = fileAttribs;
2705 ProjectNode n = null;
2706 for(p : workspace.projects)
2708 if((n = p.topNode.Find(filePath, false)))
2710 n.GetFullFilePath(selectedPath);
2711 if((fileAttribs = FileExists(selectedPath)).isFile)
2714 result = fileAttribs;
2719 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath)) && project &&
2720 (fileAttribs = FileExists(selectedPath)).isFile)
2723 result = fileAttribs;
2731 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
2734 const char *path = text;
2735 char *colon = strchr(text, ':');
2736 char filePath[MAX_LOCATION] = "";
2737 char completePath[MAX_LOCATION];
2738 int line = 0, col = 0;
2739 int len = strlen(text);
2741 FileAttribs fileAttribs;
2743 // support for valgrind output
2744 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2755 /*for(s=colon; *s; s++)
2764 //line = atoi(colon+1);
2766 // support for "Found n match(es) in "file/path";
2767 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)
2773 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2775 path = (colon - 1 > path) ? colon - 1 : path;
2776 colon = strstr(colon + 1, ":");
2778 if(*path == '*' && (s = strchr(path+1, '*')))
2780 while(isspace(*path)) path++;
2784 char * close = strchr(path, ')');
2788 strncpy(name, path+1, close - path - 1);
2789 name[close - path - 1] = '\0';
2790 for(p : ide.workspace.projects)
2792 if(!strcmp(p.name, name))
2802 prj = project ? project : (dir ? null : ide.project);
2805 strncpy(filePath, path, colon - path);
2806 filePath[colon - path] = '\0';
2807 line = atoi(colon + 1);
2808 colon = strstr(colon + 1, ":");
2810 col = atoi(colon + 1);
2812 else if(path - 1 >= text && *(path - 1) == '\"')
2814 colon = strchr(path, '\"');
2817 strncpy(filePath, path, colon - path);
2818 filePath[colon - path] = '\0';
2821 else if(path && !colon)
2823 strcpy(filePath, path);
2826 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath)))
2827 CodeLocationGoTo(completePath, fileAttribs, line, col);
2830 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2832 if(fileAttribs.isFile)
2834 char ext[MAX_EXTENSION];
2835 GetExtension(path, ext);
2837 if(binaryDocExt.Find(ext))
2839 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2841 char dirPath[MAX_LOCATION];
2842 StripLastDirectory(path, dirPath);
2847 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2848 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2850 EditBox editBox = codeEditor.editBox;
2851 editBox.GoToLineNum(line - 1);
2852 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2856 else if(fileAttribs.isDirectory)
2860 void OnRedraw(Surface surface)
2862 Bitmap bitmap = back.bitmap;
2864 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2867 void SheetSelected(SheetType sheetSelected)
2869 if(activeChild == sheet)
2871 if(sheetSelected == methods)
2873 viewPropertiesItem.accelerator = f4;
2874 viewPropertiesItem.parent = viewMenu;
2875 viewMethodsItem.parent = null;
2879 viewMethodsItem.accelerator = f4;
2880 viewMethodsItem.parent = viewMenu;
2881 viewPropertiesItem.parent = null;
2886 viewMethodsItem.parent = viewMenu;
2887 viewPropertiesItem.parent = viewMenu;
2888 if(sheetSelected == methods)
2890 viewMethodsItem.accelerator = f4;
2891 viewPropertiesItem.accelerator = 0;
2895 viewMethodsItem.accelerator = 0;
2896 viewPropertiesItem.accelerator = f4;
2901 void OnActivateClient(Window client, Window previous)
2903 //if(!client || client != previous)
2906 if(!client || client != previous)
2909 dataType = previous._class;
2910 if(previous && !strcmp(dataType.name, "CodeEditor"))
2912 ((CodeEditor)previous).UpdateFormCode();
2914 else if(previous && !strcmp(dataType.name, "Designer"))
2916 ((Designer)previous).codeEditor.UpdateFormCode();
2921 dataType = client._class;
2922 if(client && !strcmp(dataType.name, "CodeEditor"))
2924 CodeEditor codeEditor = (CodeEditor)client;
2925 SetPrivateModule(codeEditor.privateModule);
2926 SetCurrentContext(codeEditor.globalContext);
2927 SetTopContext(codeEditor.globalContext);
2928 SetGlobalContext(codeEditor.globalContext);
2930 SetDefines(&codeEditor.defines);
2931 SetImports(&codeEditor.imports);
2933 SetActiveDesigner(codeEditor.designer);
2935 sheet.codeEditor = codeEditor;
2936 toolBox.codeEditor = codeEditor;
2938 viewDesignerItem.parent = viewMenu;
2939 if(activeChild != codeEditor)
2941 viewCodeItem.parent = viewMenu;
2942 viewDesignerItem.accelerator = 0;
2943 viewCodeItem.accelerator = f8;
2947 viewCodeItem.parent = null;
2948 viewDesignerItem.accelerator = f8;
2951 else if(client && !strcmp(dataType.name, "Designer"))
2953 CodeEditor codeEditor = ((Designer)client).codeEditor;
2956 SetPrivateModule(codeEditor.privateModule);
2957 SetCurrentContext(codeEditor.globalContext);
2958 SetTopContext(codeEditor.globalContext);
2959 SetGlobalContext(codeEditor.globalContext);
2960 SetDefines(&codeEditor.defines);
2961 SetImports(&codeEditor.imports);
2965 SetPrivateModule(null);
2966 SetCurrentContext(null);
2967 SetTopContext(null);
2968 SetGlobalContext(null);
2973 SetActiveDesigner((Designer)client);
2975 sheet.codeEditor = codeEditor;
2976 toolBox.codeEditor = codeEditor;
2978 viewCodeItem.parent = viewMenu;
2979 if(activeChild != client)
2981 viewDesignerItem.parent = viewMenu;
2982 viewDesignerItem.accelerator = f8;
2983 viewCodeItem.accelerator = 0;
2987 viewDesignerItem.parent = null;
2988 viewCodeItem.accelerator = f8;
2993 if(!client && !projectView && sheet.visible)
2996 sheet.visible = false;
2997 toolBox.visible = false;
3000 sheet.codeEditor = null;
3001 toolBox.codeEditor = null;
3002 SetActiveDesigner(null);
3004 viewDesignerItem.parent = null;
3005 viewCodeItem.parent = null;
3008 SheetSelected(sheet.sheetSelected);
3011 projectCompileItem = null;
3016 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3018 CodeEditor codeEditor = (CodeEditor)client;
3019 EditBox editBox = codeEditor.editBox;
3021 statusBar.AddField(pos);
3023 caps = { width = 40, text = $"CAPS" };
3024 statusBar.AddField(caps);
3025 UpdateStateLight(caps, app.GetKeyState(capsState));
3027 ovr = { width = 36, text = $"OVR" };
3028 statusBar.AddField(ovr);
3029 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3031 num = { width = 36, text = $"NUM" };
3032 statusBar.AddField(num);
3033 UpdateStateLight(num, app.GetKeyState(numState));
3035 //statusBar.text = "Ready";
3037 if(projectView && projectView.project)
3039 bool isCObject = false;
3040 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3041 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3045 char nodeName[MAX_FILENAME];
3046 char name[MAX_FILENAME+96];
3048 ChangeExtension(node.name, "c", nodeName);
3049 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3050 projectCompileItem =
3052 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3054 bool NotifySelect(MenuItem selection, Modifiers mods)
3058 bool isCObject = false;
3059 bool isExcluded = false;
3060 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3064 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3067 List<ProjectNode> nodes { };
3069 projectView.Compile(node.project, nodes, mods.ctrl && mods.shift, isCObject ? cObject : normal);
3077 projectMenu.AddDynamic(projectCompileItem, ide, false);
3083 caps = ovr = num = null;
3088 bool OnClose(bool parentClosing)
3090 //return !projectView.buildInProgress;
3091 if(projectView && projectView.buildInProgress)
3093 if(DontTerminateDebugSession($"Close IDE"))
3095 if(findInFilesDialog)
3096 findInFilesDialog.SearchStop();
3099 workspace.timer.Stop();
3102 ideMainFrame.Destroy(0);
3109 bool passThrough = false;
3110 bool debugWorkDir = false;
3111 char * passDebugWorkDir = null;
3112 bool openAsText = false;
3113 DynamicString passArgs { };
3116 for(c = 1; c<app.argc; c++)
3120 const char * arg = app.argv[c];
3121 char * buf = new char[strlen(arg)*2+1];
3123 passArgs.concat(" ");
3125 passArgs.concat(buf);
3128 else if(debugWorkDir)
3130 passDebugWorkDir = CopyString(app.argv[c]);
3131 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3132 debugWorkDir = false;
3134 else if(!strcmp(app.argv[c], "-t"))
3136 else if(!strcmp(app.argv[c], "-no-parsing"))
3137 ide.noParsing = true;
3138 else if(!strcmp(app.argv[c], "-debug-start"))
3139 ide.debugStart = true;
3140 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3141 debugWorkDir = true;
3142 else if(!strcmp(app.argv[c], "-@"))
3146 char fullPath[MAX_LOCATION];
3147 char parentPath[MAX_LOCATION];
3148 char ext[MAX_EXTENSION];
3150 FileAttribs dirAttribs;
3151 GetWorkingDir(fullPath, MAX_LOCATION);
3152 PathCat(fullPath, app.argv[c]);
3153 StripLastDirectory(fullPath, parentPath);
3154 GetExtension(app.argv[c], ext);
3155 isProject = !openAsText && !strcmpi(ext, "epj");
3157 if(isProject && c > 1 + (ide.debugStart ? 1 : 0)) continue;
3159 // Create directory for projects (only)
3160 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3162 if(isProject && !FileExists(fullPath))
3164 char name[MAX_LOCATION];
3165 NewProjectDialog newProjectDialog;
3169 projectView.visible = false;
3170 if(!projectView.Destroy(0))
3174 newProjectDialog = { master = this };
3176 strcpy(name, app.argv[c]);
3177 StripExtension(name);
3178 GetLastDirectory(name, name);
3179 newProjectDialog.projectName.contents = name;
3180 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3181 newProjectDialog.locationEditBox.path = parentPath;
3182 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3184 incref newProjectDialog;
3185 newProjectDialog.Modal();
3188 ideSettings.AddRecentProject(projectView.fileName);
3189 ide.UpdateRecentMenus();
3190 settingsContainer.Save();
3192 delete newProjectDialog;
3193 // Open only one project
3197 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3199 else if(strstr(fullPath, "http://") == fullPath)
3200 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3203 if(passThrough && projectView && projectView.project && workspace)
3204 workspace.commandLineArgs = passArgs;
3205 if(passDebugWorkDir && projectView && projectView.project && workspace)
3207 workspace.debugDir = passDebugWorkDir;
3208 delete passDebugWorkDir;
3211 UpdateToolBarActiveConfigs(false);
3212 UpdateToolBarActiveCompilers();
3219 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3222 projectView.visible = false;
3223 projectView.Destroy(0);
3226 #ifdef GDB_DEBUG_GUI
3227 gdbDialog.Destroy(0);
3232 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3236 char * oldPaths[128];
3237 String oldList = new char[maxPathLen];
3238 Array<String> newExePaths { };
3239 //Map<String, bool> exePathExists { };
3241 #if defined(__unix__) || defined(__APPLE__)
3242 Array<String> newLibPaths { };
3243 Map<String, bool> libPathExists { };
3248 for(prj : workspace.projects)
3250 DirExpression targetDirExp;
3252 // SKIP FIRST PROJECT...
3253 if(prj == workspace.projects.firstIterator.data) continue;
3255 // NOTE: Right now the additional project config dir will be
3256 // obtained when the debugger is started, so toggling it
3257 // while building will change which library gets used.
3258 // To go with the initial state, e.g. when F5 was pressed,
3259 // we nould need to keep a list of all project's active
3260 // config upon startup.
3261 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3263 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3267 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3268 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3272 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3273 if(cfg.targetType == sharedLibrary && cfg.debug)
3277 if(targetDirExp.dir)
3279 char buffer[MAX_LOCATION];
3280 #if defined(__WIN32__)
3281 Array<String> paths = newExePaths;
3283 Array<String> paths = newLibPaths;
3285 GetSystemPathBuffer(buffer, prj.topNode.path);
3286 PathCat(buffer, targetDirExp.dir);
3289 if(!fstrcmp(p, buffer))
3296 paths.Add(CopyString(buffer));
3298 delete targetDirExp;
3302 for(item : compiler.executableDirs)
3305 for(p : newExePaths)
3307 if(!fstrcmp(p, item))
3314 newExePaths.Add(CopySystemPath(item));
3317 GetEnvironment("PATH", oldList, maxPathLen);
3319 printf("Old value of PATH: %s\n", oldList);
3321 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3322 for(c = 0; c < count; c++)
3325 for(p : newExePaths)
3327 if(!fstrcmp(p, oldPaths[c]))
3334 newExePaths.Add(CopySystemPath(oldPaths[c]));
3338 for(path : newExePaths)
3339 len += strlen(path) + 1;
3340 newList = new char[len + 1];
3342 for(path : newExePaths)
3344 strcat(newList, path);
3345 strcat(newList, pathListSep);
3347 newList[len - 1] = '\0';
3348 SetEnvironment("PATH", newList);
3350 printf("New value of PATH: %s\n", newList);
3357 #if defined(__unix__) || defined(__APPLE__)
3359 for(item : compiler.libraryDirs)
3361 if(!libPathExists[item]) // fstrcmp should be used
3363 String s = CopyString(item);
3365 libPathExists[s] = true;
3369 #if defined(__APPLE__)
3370 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3372 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3375 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3377 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3378 for(c = 0; c < count; c++)
3380 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3382 String s = CopyString(oldPaths[c]);
3384 libPathExists[s] = true;
3389 for(path : newLibPaths)
3390 len += strlen(path) + 1;
3391 newList = new char[len + 1];
3393 for(path : newLibPaths)
3395 strcat(newList, path);
3396 strcat(newList, pathListSep);
3398 newList[len - 1] = '\0';
3399 #if defined(__APPLE__)
3400 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3402 SetEnvironment("LD_LIBRARY_PATH", newList);
3405 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3411 delete libPathExists;
3414 if(compiler.distccEnabled && compiler.distccHosts)
3415 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3420 void DestroyTemporaryProjectDir()
3422 if(tmpPrjDir && tmpPrjDir[0])
3424 if(FileExists(tmpPrjDir).isDirectory)
3425 DestroyDir(tmpPrjDir);
3426 property::tmpPrjDir = null;
3432 // Graphics Driver Menu
3435 app.currentSkin.selectionColor = selectionColor;
3436 app.currentSkin.selectionText = selectionText;
3440 driverItems = new MenuItem[app.numDrivers];
3441 for(c = 0; c < app.numDrivers; c++)
3443 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3444 driverItems[c].id = c;
3445 driverItems[c].isRadio = true;
3448 driverItems = new MenuItem[2];
3449 #if defined(__unix__)
3450 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3451 driverItems[0].id = 0;
3452 driverItems[0].isRadio = true;
3454 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3455 driverItems[0].id = 0;
3456 driverItems[0].isRadio = true;
3458 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3459 driverItems[1].id = 1;
3460 driverItems[1].isRadio = true;
3462 /* skinItems = new MenuItem[app.numSkins];
3463 for(c = 0; c < app.numSkins; c++)
3465 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3466 skinItems[c].id = c;
3467 skinItems[c].isRadio = true;
3470 ideFileDialog.master = this;
3471 ideProjectFileDialog.master = this;
3473 //SetDriverAndSkin();
3477 void UpdateRecentMenus()
3480 Menu fileMenu = menu.FindMenu($"File");
3481 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3482 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3483 char * itemPath = new char[MAX_LOCATION];
3484 char * itemName = new char[MAX_LOCATION+4];
3486 recentFiles.Clear();
3489 for(recent : ideSettings.recentFiles)
3491 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3492 MakeSystemPath(itemPath);
3493 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3494 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3498 recentProjects.Clear();
3500 for(recent : ideSettings.recentProjects)
3502 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3503 MakeSystemPath(itemPath);
3504 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3505 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3517 delete languageItems;
3521 documentor.Puts("Quit\n");
3528 void DestroyDir(char * path)
3530 RecursiveDeleteFolderFSI fsi { };
3535 #if defined(__WIN32__)
3536 define sdkDirName = "Ecere SDK";
3538 define sdkDirName = "ecere";
3541 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3544 char * v = new char[maxPathLen];
3548 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3549 StripLastDirectory(path, path);
3550 PathCat(path, subDir);
3551 if(name) PathCat(path, name);
3552 if(FileExists(path) & attribs) found = true;
3554 #if defined(__WIN32__)
3557 GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3560 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3561 PathCat(path, subDir);
3562 if(name) PathCat(path, name);
3563 if(FileExists(path) & attribs) found = true;
3568 GetEnvironment("AppData", v, maxPathLen);
3571 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3572 PathCat(path, sdkDirName);
3573 PathCat(path, subDir);
3574 if(name) PathCat(path, name);
3575 if(FileExists(path) & attribs) found = true;
3580 GetEnvironment("ProgramData", v, maxPathLen);
3583 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3584 PathCat(path, sdkDirName);
3585 PathCat(path, subDir);
3586 if(name) PathCat(path, name);
3587 if(FileExists(path) & attribs) found = true;
3592 GetEnvironment("ProgramFiles", v, maxPathLen);
3595 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3596 PathCat(path, sdkDirName);
3597 PathCat(path, subDir);
3598 if(name) PathCat(path, name);
3599 if(FileExists(path) & attribs) found = true;
3604 GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3607 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3608 PathCat(path, sdkDirName);
3609 PathCat(path, subDir);
3610 if(name) PathCat(path, name);
3611 if(FileExists(path) & attribs) found = true;
3616 GetEnvironment("SystemDrive", v, maxPathLen);
3619 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3620 PathCat(path, "Program Files");
3621 PathCat(path, sdkDirName);
3622 PathCat(path, subDir);
3623 if(name) PathCat(path, name);
3624 if(FileExists(path) & attribs) found = true;
3633 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3634 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3635 for(c=0; c<numTokens; c++)
3637 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3638 PathCat(path, sdkDirName);
3639 PathCat(path, subDir);
3640 if(name) PathCat(path, name);
3641 if(FileExists(path) & attribs) found = true;
3649 void FindAndShellOpenInstalledFolder(const char * name)
3651 char path[MAX_LOCATION];
3652 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3656 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3658 char path[MAX_LOCATION];
3659 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3663 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3665 bool preserveRootFolder;
3667 void OutFolder(const char * folderPath, bool isRoot)
3669 if(!(preserveRootFolder && isRoot))
3670 RemoveDir(folderPath);
3673 bool OnFile(const char * filePath)
3675 DeleteFile(filePath);
3680 class IDEApp : GuiApplication
3682 //driver = "Win32Console";
3683 // driver = "OpenGL";
3687 TempFile includeFile { };
3692 char ext[MAX_EXTENSION];
3693 SetLoggingMode(stdOut, null);
3694 //SetLoggingMode(debug, null);
3696 settingsContainer.Load();
3698 if(ideSettings.language)
3700 const String language = GetLanguageString();
3701 if(ideSettings.language.OnCompare(language))
3703 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3708 // First count files arg to decide whether to maximize
3710 bool passThrough = false, debugWorkDir = false;
3713 for(c = 1; c<app.argc; c++)
3716 else if(debugWorkDir)
3717 debugWorkDir = false;
3718 else if(!strcmp(app.argv[c], "-t"));
3719 else if(!strcmp(app.argv[c], "-no-parsing"));
3720 else if(!strcmp(app.argv[c], "-debug-start"));
3721 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3722 debugWorkDir = true;
3723 else if(!strcmp(app.argv[c], "-@"))
3730 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3732 app.driver = "OpenGL";
3733 ide.driverItems[1].checked = true;
3737 #if defined(__unix__) || defined(__APPLE__)
3738 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3740 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3742 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3746 char model[MAX_LOCATION];
3747 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3749 ide.duck.modelFile = model;
3750 ide.duck.parent = ideMainFrame;
3753 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3754 ide.debugRubberDuck.disabled = false;
3758 desktop.caption = titleECEREIDE;
3761 for(c = 1; c<app.argc; c++)
3763 char fullPath[MAX_LOCATION];
3764 GetWorkingDir(fullPath, MAX_LOCATION);
3765 PathCat(fullPath, app.argv[c]);
3766 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3770 // Default to language specified by environment if no language selected
3771 if(!ideSettings.language)
3773 ideSettings.language = GetLanguageString();
3774 settingsContainer.Save();
3777 // Default to home directory if no directory yet set up
3778 if(!ideSettings.ideProjectFileDialogLocation[0])
3781 char location[MAX_LOCATION];
3782 char * home = getenv("HOME");
3783 char * homeDrive = getenv("HOMEDRIVE");
3784 char * homePath = getenv("HOMEPATH");
3785 char * userProfile = getenv("USERPROFILE");
3786 char * systemDrive = getenv("SystemDrive");
3787 if(home && FileExists(home).isDirectory)
3789 strcpy(location, home);
3792 if(!found && homeDrive && homePath)
3794 strcpy(location, homeDrive);
3795 PathCat(location, homePath);
3796 if(FileExists(location).isDirectory)
3799 if(!found && FileExists(userProfile).isDirectory)
3801 strcpy(location, userProfile);
3804 if(!found && FileExists(systemDrive).isDirectory)
3806 strcpy(location, systemDrive);
3811 ideSettings.ideProjectFileDialogLocation = location;
3812 if(!ideSettings.ideFileDialogLocation[0])
3813 ideSettings.ideFileDialogLocation = location;
3817 if(!LoadIncludeFile())
3818 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3820 // Create language menu
3822 String language = ideSettings.language;
3826 ide.languageItems = new MenuItem[languages.count];
3829 ide.languageItems[i] =
3831 ide.languageMenu, l.name;
3832 bitmap = { l.bitmap };
3836 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3838 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3840 // Re-select previous selected language if aborted
3841 String language = ideSettings.language;
3845 if(((!language || !language[0]) && i == 0) ||
3846 (language && !strcmpi(l.code, language)))
3848 ide.languageItems[i].checked = true;
3860 // Try to find country-specific language first
3866 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3868 ide.languageItems[i].checked = true;
3876 // Try generalizing locale
3877 if(!found && language)
3880 char genericLocale[256];
3882 strncpy(genericLocale, language, sizeof(genericLocale));
3883 genericLocale[sizeof(genericLocale)-1] = 0;
3885 under = strchr(genericLocale, '_');
3888 if(!strcmpi(genericLocale, "zh"))
3889 strcpy(genericLocale, "zh_CN");
3890 if(strcmp(genericLocale, language))
3894 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3896 ide.languageItems[i].checked = true;
3906 ide.languageItems[0].checked = true;
3908 MenuDivider { ide.languageMenu };
3911 ide.languageMenu, "Help Translate";
3913 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3915 ShellOpen("http://translations.launchpad.net/ecere");
3921 ideMainFrame.Create();
3922 if(app.argFilesCount > 1)
3923 ide.MenuWindowTileVert(null, 0);
3927 bool Cycle(bool idle)
3931 if(ide.documentor.Peek())
3934 ide.documentor.GetLine(line, sizeof(line));
3935 if(!strcmpi(line, "Exited"))
3937 ide.documentor.CloseInput();
3938 ide.documentor.CloseOutput();
3939 ide.documentor.Wait();
3940 delete ide.documentor;
3943 if(ide.documentor && ide.documentor.eof)
3945 ide.documentor.CloseInput();
3946 ide.documentor.CloseOutput();
3947 ide.documentor.Wait();
3948 delete ide.documentor;
3954 bool LoadIncludeFile()
3956 bool result = false;
3957 File include = FileOpen(":crossplatform.mk", read);
3960 File f = includeFile;
3963 for(; !include.Eof(); )
3966 int count = include.Read(buffer, 1, 4096);
3967 f.Write(buffer, 1, count);
3977 IDEMainFrame ideMainFrame { };
3979 define app = ((IDEApp)__thisModule);
3981 define titleECEREIDE = $"Ecere IDE (Debug)";
3983 define titleECEREIDE = $"Ecere IDE";