2 public import static "ecere"
3 public import static "ec"
9 import "GlobalSettingsDialog"
10 import "NewProjectDialog"
11 import "FindInFilesDialog"
18 import "ProjectConfig"
20 import "NodeProperties"
21 import "ProjectSettings"
33 import "BreakpointsView"
34 import "CallStackView"
45 import "FileSystemIterator"
47 AVLTree<const String> binaryDocExt
49 "wav", "mp3", "flac", "ogg",
51 "avi", "mkv", "mpg", "mpeg",
52 "7z", "zip", "gz", "bz2", "xz", "rar", "z", "tar", "ear",
53 "pdf", "odp", "ods", "odt", "ppt", "doc", "xls", "pptx", "docx", "xlsx"
56 #if defined(__WIN32__)
57 define pathListSep = ";";
59 define pathListSep = ":";
62 define maxPathLen = 65 * MAX_LOCATION;
64 class PathBackup : struct
71 oldPath = new char[maxPathLen];
72 oldLDPath = new char[maxPathLen];
74 GetEnvironment("PATH", oldPath, maxPathLen);
75 #if defined(__APPLE__)
76 GetEnvironment("DYLD_LIBRARY_PATH", oldLDPath, maxPathLen);
78 GetEnvironment("LD_LIBRARY_PATH", oldLDPath, maxPathLen);
84 SetEnvironment("PATH", oldPath);
85 #if defined(__APPLE__)
86 SetEnvironment("DYLD_LIBRARY_PATH", oldLDPath);
88 SetEnvironment("LD_LIBRARY_PATH", oldLDPath);
95 enum OpenCreateIfFails { no, yes, something, whatever };
96 enum OpenMethod { normal, add };
98 static Array<FileFilter> fileFilters
100 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
101 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
102 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
103 { $"Text files (*.txt, *.text, *.nfo, *.info)", "txt, text, nfo, info" },
104 { $"Web files (*.html, *.htm, *.xhtml, *.css, *.php, *.js, *.jsi, *.rb, *.xml)", "html, htm, xhtml, css, php, js, jsi, rb, xml" },
105 { $"Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", "jpg, jpeg, bmp, pcx, png, gif" },
106 { $"3D Studio Model Files (*.3ds)", "3ds" },
107 { $"All files", null }
110 static Array<FileType> fileTypes
112 { $"Based on extension", null },
115 { $"3D Studio Model", "3ds" }
118 static Array<FileFilter> projectFilters
120 { $"Project Files (*.epj)", ProjectExtension }
123 static Array<FileType> projectTypes
125 { $"Project File", ProjectExtension }
128 static Array<FileFilter> findInFilesFileFilters
130 { $"eC Files (*.ec, *.eh)", "ec, eh" },
131 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
132 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
133 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
134 { $"Text files (*.txt)", "txt" },
135 { $"All files", null }
138 FileDialog ideFileDialog
140 type = multiOpen, text = $"Open";
141 types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType), filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter);
144 define openProjectFileDialogTitle = $"Open Project";
145 define addProjectFileDialogTitle = $"Open Additional Project";
146 FileDialog ideProjectFileDialog
149 types = projectTypes.array, sizeTypes = projectTypes.count * sizeof(FileType), filters = projectFilters.array, sizeFilters = projectFilters.count * sizeof(FileFilter);
152 GlobalSettingsDialog globalSettingsDialog
154 ideSettings = ideSettings;
155 settingsContainer = settingsContainer;
157 void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange)
159 switch(globalSettingsChange)
164 for(child = ide.firstChild; child; child = child.next)
166 if(child._class == class(CodeEditor))
168 CodeEditor codeEditor = (CodeEditor) child;
169 codeEditor.editBox.freeCaret = ideSettings.useFreeCaret;
170 // codeEditor.editBox.lineNumbers = ideSettings.showLineNumbers;
171 codeEditor.editBox.caretFollowsScrolling = ideSettings.caretFollowsScrolling;
172 codeEditor.OnPostCreate(); // Update editBox margin size
179 case compilerSettings:
181 ide.UpdateCompilerConfigs(true);
188 void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
193 lineY = (line - 1) * lineH;
194 if(lineY + lineH > scrollY && lineY + lineH < scrollY + boxH)
196 Bitmap bitmap = resource.bitmap;
198 surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
203 #define IDEItem(x) (&((IDEWorkSpace)0).x)
205 class IDEToolbar : ToolBar
209 ToolButton buttonNewFile { this, toolTip = $"New file", menuItemPtr = IDEItem(fileNewItem) };
211 ToolButton buttonOpenFile { this, toolTip = $"Open file", menuItemPtr = IDEItem(fileOpenItem) };
213 // ToolButton buttonCloseFile { this, toolTip = $"Close file", menuItemPtr = IDEItem(fileCloseItem) };
215 ToolButton buttonSaveFile { this, toolTip = $"Save file", menuItemPtr = IDEItem(fileSaveItem) };
217 ToolButton buttonSaveAllFile { this, toolTip = $"Save all", menuItemPtr = IDEItem(fileSaveAllItem) };
219 ToolSeparator separator1 { this };
228 // ToolSeparator separator2 { this };
232 ToolButton buttonNewProject { this, toolTip = $"New project", menuItemPtr = IDEItem(projectNewItem) };
234 ToolButton buttonOpenProject { this, toolTip = $"Open project", menuItemPtr = IDEItem(projectOpenItem) };
235 // Add project to workspace
236 ToolButton buttonAddProject { this, toolTip = $"Add project to workspace", menuItemPtr = IDEItem(projectAddItem), disabled = true; };
238 // ToolButton buttonCloseProject { this, toolTip = $"Close project", menuItemPtr = IDEItem(projectCloseItem), disabled = true; };
240 ToolSeparator separator3 { this };
242 // Build/Execution options
244 ToolButton buttonBuild { this, toolTip = $"Build project", menuItemPtr = IDEItem(projectBuildItem), disabled = true; };
246 ToolButton buttonReLink { this, toolTip = $"Relink project", menuItemPtr = IDEItem(projectLinkItem), disabled = true; };
248 ToolButton buttonRebuild { this, toolTip = $"Rebuild project", menuItemPtr = IDEItem(projectRebuildItem), disabled = true; };
250 ToolButton buttonClean { this, toolTip = $"Clean project", menuItemPtr = IDEItem(projectCleanItem), disabled = true; };
252 // ToolButton buttonRealClean { this, toolTip = $"Real clean project", menuItemPtr = IDEItem(projectRealCleanItem), disabled = true; };
253 // Regenerate Makefile
254 ToolButton buttonRegenerateMakefile { this, toolTip = $"Regenerate Makefile", menuItemPtr = IDEItem(projectRegenerateItem), disabled = true; };
255 // Compile actual file
257 ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem), disabled = true; };
258 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
259 ToolButton buttonInstall { this, toolTip = $"Install", menuItemPtr = IDEItem(projectInstallItem), disabled = true; };
262 ToolSeparator separator4 { this };
266 ToolButton buttonDebugStartResume { this, toolTip = $"Start", menuItemPtr = IDEItem(debugStartResumeItem), disabled = true; };
268 ToolButton buttonDebugRestart { this, toolTip = $"Restart", menuItemPtr = IDEItem(debugRestartItem), disabled = true; };
270 ToolButton buttonDebugPause { this, toolTip = $"Break", menuItemPtr = IDEItem(debugBreakItem), disabled = true; };
272 ToolButton buttonDebugStop { this, toolTip = $"Stop", menuItemPtr = IDEItem(debugStopItem), disabled = true; };
274 //ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem) };
276 ToolButton buttonDebugStepInto { this, toolTip = $"Step Into", menuItemPtr = IDEItem(debugStepIntoItem), disabled = true; };
278 ToolButton buttonDebugStepOver { this, toolTip = $"Step Over", menuItemPtr = IDEItem(debugStepOverItem), disabled = true; };
280 ToolButton buttonDebugStepOut { this, toolTip = $"Step Out", menuItemPtr = IDEItem(debugStepOutItem), disabled = true; };
282 ToolButton buttonDebugSkipStepOver { this, toolTip = $"Step Over Skipping Breakpoints", menuItemPtr = IDEItem(debugSkipStepOverItem), disabled = true; };
284 ToolSeparator separator5 { this };
286 Window spacer5 { this, size = { 4 } };
290 this, toolTip = $"Active Configuration(s)", size = { 160 }, disabled = true;
291 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
294 ide.workspace.SelectActiveConfig(row.string);
299 Window spacer6 { this, size = { 4 } };
301 DropBox activeCompiler
303 this, toolTip = $"Active Compiler", size = { 160 }, disabled = true;
304 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
306 if(ide.workspace && ide.projectView && row && strcmp(row.string, ide.workspace.compiler))
308 bool silent = ide.projectView.buildInProgress == none ? false : true;
309 CompilerConfig compiler = ideSettings.GetCompilerConfig(row.string);
310 ide.workspace.compiler = row.string;
311 ide.projectView.ShowOutputBuildLog(!silent);
313 ide.projectView.DisplayCompiler(compiler, false);
314 for(prj : ide.workspace.projects)
315 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
317 ide.workspace.Save();
323 DropBox activeBitDepth
325 this, toolTip = $"Active Bit Length", size = { 60 }, disabled = true;
326 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
328 if(ide.workspace && ide.projectView && row)
330 bool silent = ide.projectView.buildInProgress == none ? false : true;
331 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
332 ide.workspace.bitDepth = (int)row.tag;
333 ide.projectView.ShowOutputBuildLog(!silent);
335 ide.projectView.DisplayCompiler(compiler, false);
336 for(prj : ide.workspace.projects)
337 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
339 ide.workspace.Save();
345 Window spacer7 { this, size = { 4 } };
350 row = activeBitDepth.AddString("Auto");
352 activeBitDepth.AddString("32 bit").tag = 32;
353 activeBitDepth.AddString("64 bit").tag = 64;
354 activeBitDepth.currentRow = row;
358 class IDEMainFrame : Window
360 background = formColor;
361 borderStyle = sizable;
365 minClientSize = { 600, 300 };
367 icon = { ":icon.png" };
368 text = titleECEREIDE;
372 anchor = { top = 0, right = 0, bottom = 0 };
375 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
382 isActiveClient = true;
384 direction = vertical;
385 background = formColor;
386 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
394 ((IDEWorkSpace)master).toolBar = null;
397 IDEWorkSpace ideWorkSpace { stack, this, toolBar = toolBar };
400 define ide = ideMainFrame.ideWorkSpace;
402 class IDEWorkSpace : Window
404 background = Color { 85, 85, 85 };
407 hasVertScroll = true;
408 hasHorzScroll = true;
410 isActiveClient = true;
411 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
415 MenuItem * driverItems, * skinItems, * languageItems;
416 StatusField pos { width = 150 };
417 StatusField ovr, caps, num;
420 BitmapResource back { ":ecereBack.jpg", window = this };
421 BitmapResource bmpBp { ":codeMarks/breakpoint.png", window = this };
422 BitmapResource bmpBpDisabled { ":codeMarks/breakpointDisabled.png", window = this };
423 BitmapResource bmpBpHalf { ":codeMarks/breakpointHalf.png", window = this };
424 BitmapResource bmpBpHalfDisabled { ":codeMarks/breakpointHalfDisabled.png", window = this };
425 BitmapResource bmpCursor { ":codeMarks/cursor.png", window = this };
426 BitmapResource bmpCursorError { ":codeMarks/cursorError.png", window = this };
427 BitmapResource bmpTopFrame { ":codeMarks/topFrame.png", window = this };
428 BitmapResource bmpTopFrameError { ":codeMarks/topFrameError.png", window = this };
429 BitmapResource bmpTopFrameHalf { ":codeMarks/topFrameHalf.png", window = this };
430 BitmapResource bmpTopFrameHalfError { ":codeMarks/topFrameHalfError.png", window = this };
432 Debugger debugger { };
434 ProjectView projectView;
436 OutputView outputView
440 void OnGotoError(const char * line, bool noParsing)
442 ide.GoToError(line, noParsing);
445 void OnCodeLocationParseAndGoTo(const char * line)
447 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir);
450 bool OnKeyDown(Key key, unichar ch)
455 if(activeBox != findBox || !ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
456 ide.ShowCodeEditor();
460 OutputView::OnKeyDown(key, ch);
467 bool OnClose(bool parentClosing)
471 ide.RepositionWindows(false);
472 return parentClosing;
476 CallStackView callStackView
478 parent = this, font = { panelFont.faceName, panelFont.size };
480 void OnSelectFrame(int frameIndex)
482 ide.debugger.GoToStackFrameLine(frameIndex, true, true);
484 ide.debugger.SelectFrame(frameIndex);
487 void OnToggleBreakpoint()
489 Debugger debugger = ide.debugger;
490 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
492 int line = debugger.activeFrame.line;
493 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line);
496 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
497 if(codeEditor) { codeEditor.Update(null); Activate(); }
502 bool OnKeyDown(Key key, unichar ch)
506 case escape: ide.ShowCodeEditor(); break;
511 bool OnClose(bool parentClosing)
515 ide.RepositionWindows(false);
516 return parentClosing;
519 void OnRedraw(Surface surface)
521 Debugger debugger = ide.debugger;
522 Frame activeFrame = debugger.activeFrame;
526 int lineCursor, lineTopFrame;
527 int lineH, scrollY, boxH;
529 Breakpoint bp = null;
532 scrollY = editBox.scroll.y;
533 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
534 //activeThread = debugger.activeThread;
535 //hitThread = debugger.hitThread;
536 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
538 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
539 if(activeFrame.absoluteFile)
541 for(i : ide.workspace.breakpoints; i.type == user)
543 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
544 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
545 activeFrame.line == i.line)
553 DrawLineMarginIcon(surface,
554 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
555 lineCursor /*1*/, lineH, scrollY, boxH);
557 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
558 DrawLineMarginIcon(surface,
559 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
560 1, lineH, scrollY, boxH);
562 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
563 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
564 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
566 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
567 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
569 if(editBox.horzScroll && editBox.horzScroll.visible)
571 surface.SetBackground(control);
572 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
577 WatchesView watchesView { parent = this };
578 ThreadsView threadsView
580 parent = this, font = { panelFont.faceName, panelFont.size };
582 bool OnKeyDown(Key key, unichar ch)
586 case escape: ide.ShowCodeEditor(); break;
591 bool OnClose(bool parentClosing)
595 ide.RepositionWindows(false);
596 return parentClosing;
599 void OnSelectThread(int threadId)
602 ide.debugger.SelectThread(threadId);
605 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
608 Debugger debugger = ide.debugger;
609 *activeThread = debugger.activeThread;
610 *hitThread = debugger.hitThread;
611 *signalThread = debugger.signalThread;
616 BreakpointsView breakpointsView { parent = this };
618 ToolBox toolBox { parent = this, visible = false };
619 Sheet sheet { parent = this, visible = false };
622 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
624 Menu fileMenu { menu, $"File", f, hasMargin = true };
627 fileMenu, $"New", n, ctrlN;
628 bitmap = { ":actions/docNew.png" };
629 bool NotifySelect(MenuItem selection, Modifiers mods)
631 Window currentDoc = activeClient;
632 bool maximizeDoc = ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
633 Window document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, false);
634 RepositionWindows(false);
635 document.NotifySaved = DocumentSaved;
639 MenuItem fileOpenItem
641 fileMenu, $"Open...", o, ctrlO;
642 bitmap = { ":actions/docOpen.png" };
643 bool NotifySelect(MenuItem selection, Modifiers mods)
645 if(!projectView && ideSettings.ideFileDialogLocation)
646 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
649 if(ideFileDialog.Modal() == ok)
651 bool gotWhatWeWant = false;
653 int numSelections = ideFileDialog.numSelections;
654 const char * const * multiFilePaths = ideFileDialog.multiFilePaths;
656 for(c = 0; c < numSelections; c++)
658 if(OpenFile(multiFilePaths[c], false, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
659 gotWhatWeWant = true;
662 MessageBox { type = yesNo, master = this, text = $"Error opening file",
663 contents = $"Open a different file?" }.Modal() == no)
665 if(!projectView && gotWhatWeWant)
666 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
667 ide.RepositionWindows(false);
677 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
678 MenuDivider { fileMenu };
679 MenuItem fileSaveItem
681 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
683 // For the toolbar button; clients can still override that for the menu item
684 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
686 Window w = activeClient;
688 w.MenuFileSave(null, 0);
692 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
693 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
694 MenuDivider { fileMenu };
697 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
698 bool NotifySelect(MenuItem selection, Modifiers mods)
700 findInFilesDialog.replaceMode = false;
701 findInFilesDialog.Show();
705 MenuItem replaceInFiles
707 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
708 bool NotifySelect(MenuItem selection, Modifiers mods)
710 findInFilesDialog.replaceMode = true;
711 findInFilesDialog.Show();
715 MenuDivider { fileMenu };
716 MenuItem globalSettingsItem
718 fileMenu, $"Global Settings...", g;
719 bool NotifySelect(MenuItem selection, Modifiers mods)
721 globalSettingsDialog.master = this;
722 if(ide.workspace && ide.workspace.compiler)
723 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.compiler;
724 else if(ideSettings.defaultCompiler)
725 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
726 globalSettingsDialog.Modal();
730 MenuDivider { fileMenu };
731 Menu recentFiles { fileMenu, $"Recent Files", r };
732 Menu recentProjects { fileMenu, $"Recent Projects", p };
733 MenuDivider { fileMenu };
736 fileMenu, $"Exit", x, altF4;
738 bool NotifySelect(MenuItem selection, Modifiers mods)
740 ideMainFrame.Destroy(0);
745 bool FileRecentFile(MenuItem selection, Modifiers mods)
748 for(file : ideSettings.recentFiles)
750 if(id == selection.id)
753 char extension[MAX_EXTENSION] = "";
754 GetExtension(file, extension);
755 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
758 char * command = PrintString("ide ", isProjectFile ? "-t " : "", file);
764 OpenFile(file, false, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
765 ide.RepositionWindows(false);
774 bool FileRecentProject(MenuItem selection, Modifiers mods)
777 for(file : ideSettings.recentProjects)
779 if(id == selection.id)
783 char * command = PrintString("ide ", file);
788 OpenFile(file, false, true, null, no, normal, mods.ctrl && mods.shift);
796 MenuPlacement editMenu { menu, $"Edit", e };
798 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
799 MenuItem projectNewItem
801 projectMenu, $"New...", n, Key { n, true, true };
802 bitmap = { ":actions/projNew.png" };
803 bool NotifySelect(MenuItem selection, Modifiers mods)
805 if(!DontTerminateDebugSession($"New Project"))
808 NewProjectDialog newProjectDialog { master = this };
809 incref newProjectDialog;
810 result = newProjectDialog.Modal();
815 newProjectDialog.CreateNewProject();
818 ideSettings.AddRecentProject(projectView.fileName);
819 ide.UpdateRecentMenus();
820 settingsContainer.Save();
824 delete newProjectDialog;
829 MenuItem projectOpenItem
831 projectMenu, $"Open...", o, Key { o, true, true };
832 bitmap = { ":actions/projOpen.png" };
833 bool NotifySelect(MenuItem selection, Modifiers mods)
835 if(ideSettings.ideProjectFileDialogLocation)
836 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
838 ideProjectFileDialog.text = openProjectFileDialogTitle;
839 if(ideProjectFileDialog.Modal() == ok)
841 OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
842 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
847 MenuItem projectQuickItem
849 projectMenu, $"Quick...", q, f7, disabled = true;
850 bool NotifySelect(MenuItem selection, Modifiers mods)
853 QuickProjectDialog { this }.Modal();
857 MenuItem projectAddItem
859 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
860 bitmap = { ":actions/projAdd.png" };
862 bool NotifySelect(MenuItem selection, Modifiers mods)
864 if(ideSettings.ideProjectFileDialogLocation)
865 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
867 ideProjectFileDialog.text = addProjectFileDialogTitle;
870 if(ideProjectFileDialog.Modal() == ok)
872 if(OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
874 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
875 contents = $"Add a different project?" }.Modal() == no)
886 MenuItem projectCloseItem
888 projectMenu, $"Close", c, disabled = true;
889 bool NotifySelect(MenuItem selection, Modifiers mods)
893 if(!ide.DontTerminateDebugSession($"Project Close"))
899 MenuDivider { projectMenu };
900 MenuItem projectSettingsItem
902 projectMenu, $"Settings...", s, altF7, disabled = true;
903 bool NotifySelect(MenuItem selection, Modifiers mods)
905 projectView.MenuSettings(projectView.active ? selection : null, mods);
909 MenuDivider { projectMenu };
910 MenuItem projectBrowseFolderItem
912 projectMenu, $"Browse Project Folder", p, disabled = true;
913 bool NotifySelect(MenuItem selection, Modifiers mods)
916 projectView.MenuBrowseFolder(null, mods);
920 MenuDivider { projectMenu };
921 MenuItem projectRunItem
923 projectMenu, $"Run", r, ctrlF5, disabled = true;
924 bitmap = { ":actions/run.png" };
925 bool NotifySelect(MenuItem selection, Modifiers mods)
928 projectView.Run(null, mods);
932 MenuItem projectBuildItem
934 projectMenu, $"Build", b, f7, disabled = true;
935 bitmap = { ":actions/build.png" };
936 bool NotifySelect(MenuItem selection, Modifiers mods)
940 if(projectView.buildInProgress == none)
941 projectView.ProjectBuild(projectView.active ? selection : null, mods);
943 projectView.stopBuild = true;
948 MenuItem projectLinkItem
950 projectMenu, $"Relink", l, disabled = true;
951 bitmap = { ":actions/relink.png" };
952 bool NotifySelect(MenuItem selection, Modifiers mods)
955 projectView.ProjectLink(projectView.active ? selection : null, mods);
959 MenuItem projectRebuildItem
961 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
962 bitmap = { ":actions/rebuild.png" };
963 bool NotifySelect(MenuItem selection, Modifiers mods)
966 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
970 MenuItem projectCleanTargetItem
972 projectMenu, $"Clean Target", g, disabled = true;
973 bitmap = { ":actions/clean.png" };
974 bool NotifySelect(MenuItem selection, Modifiers mods)
979 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
984 MenuItem projectCleanItem
986 projectMenu, $"Clean", e, disabled = true;
987 bitmap = { ":actions/clean.png" };
988 bool NotifySelect(MenuItem selection, Modifiers mods)
993 projectView.ProjectClean(projectView.active ? selection : null, mods);
998 MenuItem projectRealCleanItem
1000 projectMenu, $"Real Clean", disabled = true;
1001 bitmap = { ":actions/clean.png" };
1002 bool NotifySelect(MenuItem selection, Modifiers mods)
1007 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1012 MenuItem projectRegenerateItem
1014 projectMenu, $"Regenerate Makefile", m, disabled = true;
1015 bitmap = { ":actions/regMakefile.png" };
1016 bool NotifySelect(MenuItem selection, Modifiers mods)
1019 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1023 MenuItem projectInstallItem
1025 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
1026 projectMenu, $"Install", t, disabled = true;
1028 bitmap = { ":status/software-update-available.png" };
1029 bool NotifySelect(MenuItem selection, Modifiers mods)
1032 projectView.ProjectInstall(projectView.active ? selection : null, mods);
1036 MenuItem projectCompileItem;
1037 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1038 MenuItem debugStartResumeItem
1040 debugMenu, $"Start", s, f5, disabled = true;
1041 bitmap = { ":actions/debug.png" };
1042 NotifySelect = MenuDebugStart;
1044 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1048 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1049 if(!projectView.DebugStart())
1050 debugStartResumeItem.disabled = false; // same exception
1054 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1057 projectView.DebugResume();
1060 MenuItem debugRestartItem
1062 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1063 bitmap = { ":actions/restart.png" };
1064 bool NotifySelect(MenuItem selection, Modifiers mods)
1067 projectView.DebugRestart();
1071 MenuItem debugBreakItem
1073 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1074 bitmap = { ":actions/pause.png" };
1075 bool NotifySelect(MenuItem selection, Modifiers mods)
1077 if(projectView && projectView.buildInProgress != none)
1080 projectView.DebugBreak();
1084 MenuItem debugStopItem
1086 debugMenu, $"Stop", p, shiftF5, disabled = true;
1087 bitmap = { ":actions/stopDebug.png" };
1088 bool NotifySelect(MenuItem selection, Modifiers mods)
1091 projectView.DebugStop();
1095 MenuDivider { debugMenu };
1099 // nonClient = true,
1106 anchor = { right = 0, bottom = 0 },
1108 isActiveClient = false,
1110 clickThrough = true,
1111 size = { 500, 500 };
1113 bool OnLoadGraphics()
1115 ModelView::OnLoadGraphics();
1116 camera.position.z /= 1.3;
1117 camera.orientation = Euler { yaw = 280, pitch = 20 };
1123 bool OnRightButtonDown(int x, int y, Modifiers mods)
1125 if(!displaySystem.flags.flipping) return true;
1126 MenuWindowMove(null, 0);
1130 bool OnRightButtonUp(int x, int y, Modifiers mods)
1132 position = position;
1137 MenuItem debugRubberDuck
1139 debugMenu, $"Rubber Duck", checkable = true, disabled = true;
1140 bool NotifySelect(MenuItem selection, Modifiers mods)
1142 if(selection.checked)
1150 MenuDivider { debugMenu };
1151 MenuItem debugUseValgrindItem
1153 debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
1154 bool NotifySelect(MenuItem selection, Modifiers mods)
1158 ide.workspace.useValgrind = selection.checked;
1159 ide.workspace.Save();
1161 ide.AdjustValgrindMenus();
1165 Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
1166 MenuItem debugValgrindNoLeakCheckItem { debugValgrindLeakCheckItem, $"No" , f, id = ValgrindLeakCheck::no , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1167 MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; };
1168 MenuItem debugValgrindYesLeakCheckItem { debugValgrindLeakCheckItem, $"Yes" , f, id = ValgrindLeakCheck::yes , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1169 MenuItem debugValgrindFullLeakCheckItem { debugValgrindLeakCheckItem, $"Full" , f, id = ValgrindLeakCheck::full , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1170 bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
1174 if(selection.checked)
1176 ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
1178 debugValgrindNoLeakCheckItem.checked = debugValgrindNoLeakCheckItem.id == vgLeakCheck;
1179 debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
1180 debugValgrindYesLeakCheckItem.checked = debugValgrindYesLeakCheckItem.id == vgLeakCheck;
1181 debugValgrindFullLeakCheckItem.checked = debugValgrindFullLeakCheckItem.id == vgLeakCheck;
1183 ide.workspace.vgLeakCheck = vgLeakCheck;
1184 ide.workspace.Save();
1187 selection.checked = true;
1191 Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
1192 MenuItem debugValgrindRSDefaultItem { debugValgrindRedzoneSizeItem, $"Default", f, id = -1, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; };
1193 MenuItem debugValgrindRS0Item { debugValgrindRedzoneSizeItem, "0" , f, id = 0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1194 MenuItem debugValgrindRS16Item { debugValgrindRedzoneSizeItem, "16" , f, id = 16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1195 MenuItem debugValgrindRS32Item { debugValgrindRedzoneSizeItem, "32" , f, id = 32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1196 MenuItem debugValgrindRS64Item { debugValgrindRedzoneSizeItem, "64" , f, id = 64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1197 MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, "128" , f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1198 MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, "256" , f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1199 MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, "512" , f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1200 bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
1204 if(selection.checked)
1206 int vgRedzoneSize = (int)selection.id;
1208 debugValgrindRSDefaultItem.checked = debugValgrindRSDefaultItem.id == vgRedzoneSize;
1209 debugValgrindRS0Item.checked = debugValgrindRS0Item.id == vgRedzoneSize;
1210 debugValgrindRS16Item.checked = debugValgrindRS16Item.id == vgRedzoneSize;
1211 debugValgrindRS32Item.checked = debugValgrindRS32Item.id == vgRedzoneSize;
1212 debugValgrindRS64Item.checked = debugValgrindRS64Item.id == vgRedzoneSize;
1213 debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
1214 debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
1215 debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
1217 ide.workspace.vgRedzoneSize = vgRedzoneSize;
1218 ide.workspace.Save();
1221 selection.checked = true;
1225 MenuItem debugValgrindTrackOriginsItem
1227 debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
1228 bool NotifySelect(MenuItem selection, Modifiers mods)
1232 ide.workspace.vgTrackOrigins = selection.checked;
1233 ide.workspace.Save();
1239 MenuDivider { debugMenu };
1240 MenuItem debugStepIntoItem
1242 debugMenu, $"Step Into", i, f11, disabled = true;
1243 bitmap = { ":actions/stepInto.png" };
1244 bool NotifySelect(MenuItem selection, Modifiers mods)
1246 if(projectView) projectView.DebugStepInto();
1250 MenuItem debugStepOverItem
1252 debugMenu, $"Step Over", v, f10, disabled = true;
1253 bitmap = { ":actions/stepOver.png" };
1254 bool NotifySelect(MenuItem selection, Modifiers mods)
1256 if(projectView) projectView.DebugStepOver(false);
1260 MenuItem debugSkipStepOverItem
1262 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1263 bitmap = { ":actions/stepOverSkipBreak.png" };
1264 bool NotifySelect(MenuItem selection, Modifiers mods)
1266 if(projectView) projectView.DebugStepOver(true);
1270 MenuItem debugStepOutItem
1272 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1273 bitmap = { ":actions/stepOut.png" };
1274 bool NotifySelect(MenuItem selection, Modifiers mods)
1276 if(projectView) projectView.DebugStepOut(false);
1280 MenuItem debugSkipStepOutItem
1282 debugMenu, $"Step Out Skipping Breakpoints", n, Key { f11, ctrl = true, shift = true }, disabled = true;
1283 bitmap = { ":actions/skipBreaks.png" };
1284 bool NotifySelect(MenuItem selection, Modifiers mods)
1286 if(projectView) projectView.DebugStepOut(true);
1291 MenuItem debugStepUntilItem
1293 debugMenu, $"Step Over Until Next Line", x, disabled = true;
1294 bool NotifySelect(MenuItem selection, Modifiers mods)
1296 if(projectView) projectView.DebugStepUntil(false);
1300 MenuItem debugSkipStepUntilItem
1302 debugMenu, $"Step Over Until Next Line Skipping Breakpoints", e, Key { f10, shift = true, alt = true }, disabled = true;
1303 bool NotifySelect(MenuItem selection, Modifiers mods)
1305 if(projectView) projectView.DebugStepUntil(true);
1310 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1311 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1312 MenuPlacement debugRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level", l };
1313 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", g };
1315 MenuPlacement debugBpRunToCursorItem { debugMenu, $"BP Run To Cursor" };
1316 MenuPlacement debugBpSkipRunToCursorItem { debugMenu, $"BP Run To Cursor Skipping Breakpoints" };
1317 MenuPlacement debugBpRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level" };
1318 MenuPlacement debugBpSkipRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level Skipping Breakpoints" };
1320 //MenuDivider { debugMenu };
1321 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1322 MenuPlacement imageMenu { menu, $"Image", i };
1323 Menu viewMenu { menu, $"View", v };
1324 MenuItem viewProjectItem
1326 viewMenu, $"Project View", j, alt0, disabled = true;
1327 bool NotifySelect(MenuItem selection, Modifiers mods)
1331 projectView.visible = true;
1332 projectView.Activate();
1337 MenuPlacement { viewMenu, $"View Designer" };
1338 MenuPlacement { viewMenu, $"View Code" };
1339 MenuPlacement { viewMenu, $"View Properties" };
1340 MenuPlacement { viewMenu, $"View Methods" };
1341 MenuItem viewDesignerItem
1343 viewMenu, $"View Designer", d, f8;
1344 bool NotifySelect(MenuItem selection, Modifiers mods)
1346 Window client = activeClient;
1347 Class dataType = client._class;
1348 if(!strcmp(dataType.name, "Designer"))
1350 client.visible = true;
1354 ((CodeEditor)client).ViewDesigner();
1358 MenuItem viewCodeItem
1360 viewMenu, $"View Code", c, f8;
1361 bool NotifySelect(MenuItem selection, Modifiers mods)
1363 Window client = activeClient;
1364 Class dataType = client._class;
1365 if(!strcmp(dataType.name, "Designer"))
1366 client = ((Designer)client).codeEditor;
1369 // Do this after so the caret isn't moved yet...
1370 client.visible = true;
1374 MenuItem viewPropertiesItem
1376 viewMenu, $"View Properties", p, f4;
1377 bool NotifySelect(MenuItem selection, Modifiers mods)
1379 sheet.visible = true;
1380 sheet.sheetSelected = properties;
1385 MenuItem viewMethodsItem
1387 viewMenu, $"View Methods", m, f4;
1388 bool NotifySelect(MenuItem selection, Modifiers mods)
1390 sheet.visible = true;
1391 sheet.sheetSelected = methods;
1396 MenuItem viewToolBoxItem
1398 viewMenu, $"View Toolbox", x, f12;
1399 bool NotifySelect(MenuItem selection, Modifiers mods)
1401 toolBox.visible = true;
1406 MenuItem viewOutputItem
1408 viewMenu, $"Output", o, alt2;
1409 bool NotifySelect(MenuItem selection, Modifiers mods)
1415 MenuItem viewWatchesItem
1417 viewMenu, $"Watches", w, alt3;
1418 bool NotifySelect(MenuItem selection, Modifiers mods)
1424 MenuItem viewThreadsItem
1426 viewMenu, $"Threads", t, alt4;
1427 bool NotifySelect(MenuItem selection, Modifiers mods)
1433 MenuItem viewBreakpointsItem
1435 viewMenu, $"Breakpoints", b, alt5;
1436 bool NotifySelect(MenuItem selection, Modifiers mods)
1438 breakpointsView.Show();
1442 MenuItem viewCallStackItem
1444 viewMenu, $"Call Stack", s, alt7;
1445 bool NotifySelect(MenuItem selection, Modifiers mods)
1447 callStackView.Show();
1451 MenuItem viewAllDebugViews
1453 viewMenu, $"All Debug Views", a, alt9;
1454 bool NotifySelect(MenuItem selection, Modifiers mods)
1459 callStackView.Show();
1460 breakpointsView.Show();
1464 #ifdef GDB_DEBUG_GUI
1465 MenuDivider { viewMenu };
1466 MenuItem viewGDBItem
1468 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1469 bool NotifySelect(MenuItem selection, Modifiers mods)
1476 MenuDivider { viewMenu };
1477 MenuItem viewColorPicker
1479 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1480 bool NotifySelect(MenuItem selection, Modifiers mods)
1482 ColorPicker colorPicker { master = this };
1483 colorPicker.Modal();
1487 MenuDivider { viewMenu };
1491 viewMenu, "Full Screen", f, checkable = true;
1493 bool NotifySelect(MenuItem selection, Modifiers mods)
1495 app.fullScreen ^= true;
1497 anchor = { 0, 0, 0, 0 };
1502 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1504 MenuDivider { viewMenu };
1506 Menu languageMenu { viewMenu, "Language", l };
1508 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1509 Menu windowMenu { menu, $"Window", w };
1510 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1511 MenuDivider { windowMenu };
1512 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1513 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1514 MenuDivider { windowMenu };
1515 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1516 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1517 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1518 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1519 MenuDivider { windowMenu };
1520 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1521 Menu helpMenu { menu, $"Help", h };
1524 helpMenu, $"API Reference", r, f1;
1525 bool NotifySelect(MenuItem selection, Modifiers mods)
1529 char * p = new char[MAX_LOCATION];
1531 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1532 PathCat(p, "documentor");
1533 #if defined(__WIN32__)
1534 ChangeExtension(p, "exe", p);
1536 if(!FileExists(p).isFile)
1537 strcpy(p, "documentor");
1539 documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
1544 Process_ShowWindows(documentor.GetProcessID());
1545 // documentor.Puts("Activate\n");
1550 MenuDivider { helpMenu };
1553 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1554 bool NotifySelect(MenuItem selection, Modifiers mods)
1556 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1560 MenuDivider { helpMenu };
1563 helpMenu, $"Documentation Folder", d;
1564 bool NotifySelect(MenuItem selection, Modifiers mods)
1566 FindAndShellOpenInstalledFolder("doc");
1572 helpMenu, $"Samples Folder", s;
1573 bool NotifySelect(MenuItem selection, Modifiers mods)
1575 FindAndShellOpenInstalledFolder("samples");
1581 helpMenu, $"Extras Folder", x;
1582 bool NotifySelect(MenuItem selection, Modifiers mods)
1584 FindAndShellOpenInstalledFolder("extras");
1588 MenuDivider { helpMenu };
1591 helpMenu, $"Community Forums", f;
1592 bool NotifySelect(MenuItem selection, Modifiers mods)
1594 ShellOpen("http://ecere.com/forums");
1598 MenuDivider { helpMenu };
1601 helpMenu, $"About...", a;
1602 bool NotifySelect(MenuItem selection, Modifiers mods)
1604 AboutIDE { master = this }.Modal();
1609 property ToolBox toolBox
1611 get { return toolBox; }
1614 property Sheet sheet
1616 get { return sheet; }
1619 property Project project
1621 get { return projectView ? projectView.project : null; }
1624 property Workspace workspace
1626 get { return projectView ? projectView.workspace : null; }
1629 FindInFilesDialog findInFilesDialog
1632 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1638 #ifdef GDB_DEBUG_GUI
1641 master = this, parent = this;
1642 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1644 void OnCommand(const char * string)
1647 ide.debugger.SendGDBCommand(string);
1652 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1654 //app.driver = app.drivers[selection.id];
1655 #if defined(__unix__) || defined(__APPLE__)
1656 app.driver = selection.id ? "OpenGL" : "X";
1658 app.driver = selection.id ? "OpenGL" : "GDI";
1660 delete ideSettings.displayDriver;
1661 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1663 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1665 settingsContainer.Save();
1666 //SetDriverAndSkin();
1670 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1672 app.skin = app.skins[selection.id];
1677 void SetDriverAndSkin()
1680 for(c = 0; c < app.numSkins; c++)
1681 if(!strcmp(app.skins[c], app.skin))
1683 skinItems[c].checked = true;
1686 for(c = 0; c < app.numDrivers; c++)
1687 if(!strcmp(app.drivers[c], app.driver))
1689 driverItems[c].checked = true;
1694 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1696 Project project = workspace.projects.firstIterator.data;
1697 projectView = ProjectView
1700 fileName = fileName;
1702 void NotifyDestroyed(Window window, DialogResult result)
1705 text = titleECEREIDE;
1710 projectView.Create();
1711 RepositionWindows(false);
1713 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1714 projectView.workspace = workspace;
1715 projectView.project = project;
1716 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1720 ide.breakpointsView.LoadFromWorkspace();
1721 ide.watchesView.LoadFromWorkspace();
1723 findInFilesDialog.projectNodeField.userData = projectView;
1726 char fileName[MAX_LOCATION];
1727 strcpy(fileName, project.topNode.path);
1728 PathCat(fileName, project.topNode.name);
1735 projectView.visible = false;
1736 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1738 if(findInFilesDialog)
1740 char workingDir[MAX_LOCATION];
1741 GetWorkingDir(workingDir, MAX_LOCATION);
1742 findInFilesDialog.SearchStop();
1743 findInFilesDialog.currentDirectory = workingDir;
1745 sheet.visible = false;
1746 toolBox.visible = false;
1747 outputView.visible = false;
1748 ideMainFrame.text = titleECEREIDE;
1755 void RepositionWindows(bool expand)
1760 bool callStackVisible = expand ? false : callStackView.visible;
1761 bool threadsVisible = expand ? false : threadsView.visible;
1762 bool watchesVisible = expand ? false : watchesView.visible;
1763 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1764 bool toolBoxVisible = toolBox.visible;
1765 bool outputVisible = expand ? false : outputView.visible;
1766 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1767 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1769 for(child = firstChild; child; child = child.next)
1771 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1772 child._class == class(Sheet) || child._class == class(ProjectView))
1774 Anchor anchor = child.anchor;
1775 anchor.top = topDistance;
1776 anchor.bottom = bottomDistance;
1777 if(child._class == class(CodeEditor) || child._class == class(Designer))
1779 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1780 anchor.right = toolBoxVisible ? 150 : 0;
1782 child.anchor = anchor;
1786 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1787 child._class == class(BreakpointsView))
1788 child.visible = false;
1791 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1793 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1797 bool ShowCodeEditor()
1800 activeClient.Activate();
1801 else if(projectView)
1803 projectView.visible = true;
1804 projectView.Activate();
1806 else if(sheet.visible)
1809 outputView.visible = false;
1813 void DocumentSaved(Window document, const char * fileName)
1815 ideSettings.AddRecentFile(fileName);
1816 ide.UpdateRecentMenus();
1817 ide.AdjustFileMenus();
1818 settingsContainer.Save();
1821 bool Window::OnFileModified(FileChange fileChange, const char * param)
1824 sprintf(temp, $"The document %s was modified by another application.\n"
1825 "Would you like to reload it and lose your changes?", this.fileName);
1826 if(MessageBox { type = yesNo, master = this/*.parent*/,
1827 text = $"Document has been modified", contents = temp }.Modal() == yes)
1829 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1830 char * fileName = CopyString(this.fileName);
1831 WindowState state = this.state;
1832 Anchor anchor = this.anchor;
1833 Size size = this.size;
1835 this.modifiedDocument = false;
1837 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1840 this.anchor = anchor;
1842 this.SetState(state, true, 0);
1850 void UpdateMakefiles()
1854 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1855 for(prj : workspace.projects)
1856 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1861 void UpdateCompilerConfigs(bool mute)
1863 UpdateToolBarActiveCompilers();
1866 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1867 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
1870 projectView.ShowOutputBuildLog(true);
1871 projectView.DisplayCompiler(compiler, false);
1873 for(prj : workspace.projects)
1874 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1879 void UpdateToolBarActiveCompilers()
1881 toolBar.activeCompiler.Clear();
1882 for(compiler : ideSettings.compilerConfigs)
1884 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1885 if(workspace && workspace.compiler && !strcmp(compiler.name, workspace.compiler))
1886 toolBar.activeCompiler.currentRow = row;
1888 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1889 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1892 void UpdateToolBarActiveConfigs(bool selectionOnly)
1894 bool commonSelected = false;
1895 DataRow row = toolBar.activeConfig.currentRow;
1897 row = toolBar.activeConfig.FindRow(1);
1900 toolBar.activeConfig.Clear();
1901 row = toolBar.activeConfig.AddString($"(Mixed)");
1906 char * configName = null;
1909 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1910 for(prj : workspace.projects)
1912 for(cfg : prj.configurations)
1915 configs[cfg.name] = 1;
1920 toolBar.activeConfig.AddString(&name);
1924 if(projectView && projectView.project)
1926 for(prj : workspace.projects)
1928 if(prj.config && prj.config.name)
1930 configName = prj.config.name;
1936 commonSelected = true;
1937 for(prj : workspace.projects)
1939 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1941 commonSelected = false;
1949 commonSelected = false;
1950 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1952 if(!strcmp(row.string, configName))
1954 toolBar.activeConfig.currentRow = row;
1955 commonSelected = true;
1962 toolBar.activeConfig.Sort(null, 0);
1964 toolBar.activeConfig.currentRow = row;
1969 bool unavailable = !project;
1971 projectAddItem.disabled = unavailable;
1972 toolBar.buttonAddProject.disabled = unavailable;
1974 projectSettingsItem.disabled = unavailable;
1976 projectBrowseFolderItem.disabled = unavailable;
1978 viewProjectItem.disabled = unavailable;
1980 toolBar.activeConfig.disabled = unavailable;
1981 toolBar.activeCompiler.disabled = unavailable;
1982 toolBar.activeBitDepth.disabled = unavailable;
1985 debugUseValgrindItem.disabled = unavailable;
1986 AdjustValgrindMenus();
1995 void AdjustValgrindMenus()
1997 bool unavailable = !project || !debugUseValgrindItem.checked;
1998 debugValgrindNoLeakCheckItem.disabled = unavailable;
1999 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2000 debugValgrindYesLeakCheckItem.disabled = unavailable;
2001 debugValgrindFullLeakCheckItem.disabled = unavailable;
2003 debugValgrindTrackOriginsItem.disabled = unavailable;
2005 debugValgrindRSDefaultItem.disabled = unavailable;
2006 debugValgrindRS0Item.disabled = unavailable;
2007 debugValgrindRS16Item.disabled = unavailable;
2008 debugValgrindRS32Item.disabled = unavailable;
2009 debugValgrindRS64Item.disabled = unavailable;
2010 debugValgrindRS128Item.disabled = unavailable;
2011 debugValgrindRS256Item.disabled = unavailable;
2012 debugValgrindRS512Item.disabled = unavailable;
2016 property bool hasOpenedCodeEditors
2021 for(w = firstChild; w; w = w.next)
2022 if(w._class == class(CodeEditor) &&
2023 w.isDocument && !w.closing && w.visible && w.created &&
2024 w.fileName && w.fileName[0])
2030 void AdjustFileMenus()
2032 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2034 projectQuickItem.disabled = unavailable;
2037 void AdjustBuildMenus()
2039 bool unavailable = project && projectView.buildInProgress;
2040 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2042 projectNewItem.disabled = unavailable;
2043 toolBar.buttonNewProject.disabled = unavailable;
2044 projectOpenItem.disabled = unavailable;
2045 toolBar.buttonOpenProject.disabled = unavailable;
2047 unavailable = !project || projectView.buildInProgress;
2049 projectCloseItem.disabled = unavailable;
2050 // toolBar.buttonCloseProject.disabled = unavailable;
2052 projectRunItem.disabled = naForRun;
2053 toolBar.buttonRun.disabled = naForRun;
2055 projectBuildItem.disabled = false;
2056 projectBuildItem.text = unavailable ? $"Stop Build" : $"Build";
2057 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2059 projectLinkItem.disabled = unavailable;
2060 toolBar.buttonReLink.disabled = unavailable;
2061 projectRebuildItem.disabled = unavailable;
2062 toolBar.buttonRebuild.disabled = unavailable;
2063 projectCleanItem.disabled = unavailable;
2064 toolBar.buttonClean.disabled = unavailable;
2065 projectCleanTargetItem.disabled = unavailable;
2066 projectRealCleanItem.disabled = unavailable;
2067 // toolBar.buttonRealClean.disabled = unavailable;
2068 projectRegenerateItem.disabled = unavailable;
2069 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2070 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2071 projectInstallItem.disabled = unavailable;
2072 toolBar.buttonInstall.disabled = unavailable;
2074 projectCompileItem.disabled = unavailable;
2076 AdjustPopupBuildMenus();
2079 void AdjustPopupBuildMenus()
2081 bool unavailable = !project || projectView.buildInProgress;
2083 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2086 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, 0);
2089 menu.disabled = false;
2090 menu.text = unavailable ? $"Stop Build" : $"Build";
2091 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2094 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, 0); if(menu) menu.disabled = unavailable;
2095 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, 0); if(menu) menu.disabled = unavailable;
2096 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, 0); if(menu) menu.disabled = unavailable;
2097 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, 0); if(menu) menu.disabled = unavailable;
2098 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, 0); if(menu) menu.disabled = unavailable;
2099 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, 0); if(menu) menu.disabled = unavailable;
2100 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, 0); if(menu) menu.disabled = unavailable;
2101 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, 0); if(menu) menu.disabled = unavailable;
2102 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, 0); if(menu) menu.disabled = unavailable;
2103 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, 0); if(menu) menu.disabled = unavailable;
2104 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, 0); if(menu) menu.disabled = unavailable;
2105 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, 0); if(menu) menu.disabled = unavailable;
2106 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, 0); if(menu) menu.disabled = unavailable;
2107 projectView.popupMenu.Update(null);
2111 property bool areDebugMenusUnavailable { get {
2113 project.GetTargetType(project.config) != executable ||
2114 projectView.buildInProgress == buildingMainProject;
2117 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2118 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2119 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2121 void AdjustDebugMenus()
2123 bool unavailable = areDebugMenusUnavailable;
2124 bool running = isDebuggerRunning;
2125 bool stopped = isDebuggerStopped;
2126 bool active = debugger.isActive;
2128 bool isNotRunning = unavailable || !running;
2129 bool isNotNotRunning = unavailable || running;
2130 bool isNotStopped = unavailable || !stopped;
2131 bool isNotActive = unavailable || !active;
2133 debugStartResumeItem.disabled = isNotNotRunning;
2134 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2135 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2138 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2139 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2142 debugBreakItem.disabled = isNotRunning;
2143 debugStopItem.disabled = isNotActive;
2144 debugRestartItem.disabled = isNotActive;
2147 toolBar.buttonDebugPause.disabled = isNotRunning;
2148 toolBar.buttonDebugStop.disabled = isNotActive;
2149 toolBar.buttonDebugRestart.disabled = isNotActive;
2152 debugStepIntoItem.disabled = isNotNotRunning;
2153 debugStepOverItem.disabled = isNotNotRunning;
2154 debugSkipStepOverItem.disabled = isNotNotRunning;
2155 debugStepOutItem.disabled = isNotStopped;
2156 debugSkipStepOutItem.disabled = isNotStopped;
2158 debugStepUntilItem.disabled = isNotStopped;
2159 debugSkipStepUntilItem.disabled = isNotStopped;
2163 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2164 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2165 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2166 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2167 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2169 if((Designer)GetActiveDesigner())
2171 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2173 codeEditor.AdjustDebugMenus();
2177 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2179 char tempString[MAX_LOCATION];
2180 strcpy(tempString, directory);
2181 if(saveSettings && !projectView)
2183 ideSettings.ideFileDialogLocation = directory;
2184 settingsContainer.Save();
2187 ideFileDialog.currentDirectory = tempString;
2188 codeEditorFileDialog.currentDirectory = tempString;
2189 codeEditorFormFileDialog.currentDirectory = tempString;
2192 void ChangeProjectFileDialogDirectory(char * directory)
2194 ideSettings.ideProjectFileDialogLocation = directory;
2195 settingsContainer.Save();
2198 Window FindWindow(const char * filePath)
2200 Window document = null;
2202 // TOCHECK: Do we need to change slashes here?
2203 for(document = firstChild; document; document = document.next)
2205 const char * fileName = document.fileName;
2206 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2208 document.visible = true;
2209 document.Activate();
2216 bool DontTerminateDebugSession(const char * title)
2218 if(debugger.isActive)
2220 if(MessageBox { type = yesNo, master = ide,
2221 contents = $"Do you want to terminate the debugging session in progress?",
2222 text = title }.Modal() == no)
2225 MessageBox msg { type = yesNo, master = ide,
2226 contents = "Do you want to terminate the debugging session in progress?",
2228 if(msg.Modal() == no)
2240 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2242 char extension[MAX_EXTENSION] = "";
2243 Window document = null;
2244 bool isProject = false;
2245 bool needFileModified = true;
2246 char winFilePath[MAX_LOCATION];
2247 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2248 Window currentDoc = activeClient;
2249 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2252 GetExtension(filePath, extension);
2256 strcpy(extension, type);
2258 if(strcmp(extension, ProjectExtension))
2260 for(document = firstChild; document; document = document.next)
2262 const char * fileName = document.fileName;
2263 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2265 document.visible = true;
2267 document.Activate();
2273 if(createIfFails == whatever)
2275 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2277 needFileModified = false;
2278 if(openMethod == normal)
2280 if(DontTerminateDebugSession($"Open Project"))
2289 Workspace workspace = null;
2291 if(FileExists(filePath))
2293 if(!strcmp(extension, ProjectExtension))
2295 char workspaceFile[MAX_LOCATION];
2296 strcpy(workspaceFile, filePath);
2297 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2298 workspace = LoadWorkspace(workspaceFile, filePath);
2300 else if(!strcmp(extension, WorkspaceExtension))
2301 workspace = LoadWorkspace(filePath, null);
2308 CreateProjectView(workspace, filePath);
2309 document = projectView;
2311 toolBox.visible = true;
2312 sheet.visible = true;
2313 projectView.MakeActive();
2315 workspace.ParseLoadedBreakpoints();
2316 workspace.DropInvalidBreakpoints(null);
2319 ide.projectView.ShowOutputBuildLog(true);
2321 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.compiler);
2322 ide.projectView.DisplayCompiler(compiler, false);
2325 UpdateCompilerConfigs(false);
2328 char newWorkingDir[MAX_LOCATION];
2329 StripLastDirectory(filePath, newWorkingDir);
2330 ChangeFileDialogsDirectory(newWorkingDir, false);
2333 document.fileName = filePath;
2335 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2337 // this crashes on starting ide with epj file, solution please?
2338 // app.UpdateDisplay();
2340 workspace.holdTracking = true;
2341 for(ofi : workspace.openedFiles)
2343 if(ofi.state != closed)
2345 Window file = OpenFile(ofi.path, false, true, null, no, normal, noParsing);
2348 char fileName[MAX_LOCATION];
2350 GetLastDirectory(ofi.path, fileName);
2351 node = projectView.project.topNode.Find(fileName, true);
2353 node.EnsureVisible();
2357 ide.RepositionWindows(false);
2358 workspace.holdTracking = false;
2360 workspace.timer.Start();
2362 #if !defined(__WIN32__)
2363 // Valgrind Debug menu updates
2364 debugUseValgrindItem.checked = workspace.useValgrind;
2366 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2367 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2368 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2369 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2371 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2372 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2373 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2374 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2375 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2376 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2377 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2378 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2380 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2383 findInFilesDialog.mode = FindInFilesMode::project;
2384 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2387 char location[MAX_LOCATION];
2388 StripLastDirectory(ide.project.topNode.path, location);
2389 ChangeProjectFileDialogDirectory(location);
2396 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2398 ideProjectFileDialog.text = openProjectFileDialogTitle;
2399 if(ideProjectFileDialog.Modal() == cancel)
2401 filePath = ideProjectFileDialog.filePath;
2402 GetExtension(filePath, extension);
2413 else if(openMethod == add)
2418 char slashFilePath[MAX_LOCATION];
2419 GetSlashPathBuffer(slashFilePath, filePath);
2420 for(p : workspace.projects)
2422 if(!fstrcmp(p.filePath, slashFilePath))
2430 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2431 contents = $"This project is already present in workspace." }.Modal();
2435 prj = LoadProject(filePath, null);
2438 const char * activeConfigName = null;
2439 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.compiler);
2440 prj.StartMonitoring();
2441 workspace.projects.Add(prj);
2442 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2443 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2444 activeConfigName = toolBar.activeConfig.currentRow.string;
2445 if(activeConfigName)
2447 for(cfg : prj.configurations)
2449 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2457 projectView.AddNode(prj.topNode, null);
2458 workspace.modified = true;
2460 findInFilesDialog.AddProjectItem(prj);
2461 projectView.ShowOutputBuildLog(true);
2462 projectView.DisplayCompiler(compiler, false);
2463 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2467 char location[MAX_LOCATION];
2468 StripLastDirectory(prj.topNode.path, location);
2469 ChangeProjectFileDialogDirectory(location);
2472 // projectView is associated with the main project and not with the one just added but
2473 return projectView; // just to let the caller know something was opened
2481 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2482 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2483 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2485 if(FileExists(filePath))
2486 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2487 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2488 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2491 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2494 else if(!strcmp(extension, "3ds"))
2496 if(FileExists(filePath))
2497 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2498 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2499 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2503 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2506 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2507 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2508 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2509 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2510 !strcmp(extension, "js"))
2512 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2513 editor.updatingCode = true;
2514 if(editor.LoadFile(filePath))
2517 editor.visible = true;
2521 needFileModified = false;
2525 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2526 if(editor.LoadFile(filePath))
2529 editor.visible = true;
2533 needFileModified = false;
2536 if(document && (document._class == class(PictureEdit) ||
2537 document._class == class(ModelView)))
2542 document.fileName = filePath;
2543 if(workspace && !workspace.holdTracking)
2544 workspace.UpdateOpenedFileInfo(filePath, opened);
2548 if(!document && createIfFails != no)
2550 if(createIfFails != yes && !needFileModified &&
2551 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2552 createIfFails = yes;
2553 if(createIfFails == yes || createIfFails == whatever)
2555 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2557 document.fileName = filePath;
2563 if(projectView && document._class == class(CodeEditor) && workspace)
2565 int lineNumber, position;
2567 CodeEditor editor = (CodeEditor)document;
2568 editor.openedFileInfo = workspace.UpdateOpenedFileInfo(filePath, opened);
2569 editor.openedFileInfo.holdTracking = true;
2570 lineNumber = Max(editor.openedFileInfo.lineNumber - 1, 0);
2571 position = Max(editor.openedFileInfo.position - 1, 0);
2572 if(editor.editBox.GoToLineNum(lineNumber))
2573 editor.editBox.GoToPosition(editor.editBox.line, lineNumber, position);
2574 scroll.x = Max(editor.openedFileInfo.scroll.x, 0);
2575 scroll.y = Max(editor.openedFileInfo.scroll.y, 0);
2576 editor.editBox.scroll = scroll;
2577 editor.openedFileInfo.holdTracking = false;
2580 if(needFileModified)
2581 document.OnFileModified = OnFileModified;
2582 document.NotifySaved = DocumentSaved;
2583 if(maximizeDoc && document.hasMaximize)
2584 document.state = maximized;
2587 ideSettings.AddRecentProject(document.fileName);
2589 ideSettings.AddRecentFile(document.fileName);
2590 ide.UpdateRecentMenus();
2591 ide.AdjustFileMenus();
2592 settingsContainer.Save();
2600 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2601 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2603 if(!parentClosing && ide.workspace)
2604 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2607 bool ModelView::ModelViewOnClose(bool parentClosing)
2609 if(!parentClosing && ide.workspace)
2610 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2613 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2615 if(!parentClosing && ide.workspace)
2616 ide.workspace.UpdateOpenedFileInfo(fileName, unknown);
2621 void OnUnloadGraphics(Window window)
2623 display.ClearMaterials();
2624 display.ClearTextures();
2625 display.ClearMeshes();
2629 void UpdateStateLight(StatusField fld, bool on)
2631 fld.color = on ? lime : Color { 128,128,128 };
2632 fld.backColor = on ? dimGray : 0;
2636 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2638 UpdateStateLight(caps, app.GetKeyState(capsState));
2639 UpdateStateLight(num, app.GetKeyState(numState));
2643 bool OnKeyDown(Key key, unichar ch)
2647 case b: projectView.Update(null); break;
2648 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2649 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2654 bool OnKeyUp(Key key, unichar ch)
2658 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2659 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2664 void GoToError(const char * line, bool noParsing)
2667 projectView.GoToError(line, noParsing);
2670 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir)
2673 const char *path = text;
2674 char *colon = strchr(text, ':');
2675 char filePath[MAX_LOCATION] = "";
2676 char completePath[MAX_LOCATION];
2677 int line = 0, col = 0;
2678 int len = strlen(text);
2680 FileAttribs fileAttribs;
2682 // support for valgrind output
2683 if((s = strstr(text, "==")) && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2694 /*for(s=colon; *s; s++)
2703 //line = atoi(colon+1);
2705 // support for "Found n match(es) in "file/path";
2706 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)
2712 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2714 path = (colon - 1 > path) ? colon - 1 : path;
2715 colon = strstr(colon + 1, ":");
2717 if(*path == '*' && (s = strchr(path+1, '*')))
2719 while(isspace(*path)) path++;
2723 char * close = strchr(path, ')');
2727 strncpy(name, path+1, close - path - 1);
2728 name[close - path - 1] = '\0';
2729 for(p : ide.workspace.projects)
2731 if(!strcmp(p.name, name))
2741 prj = project ? project : (dir ? null : ide.project);
2744 strncpy(filePath, path, colon - path);
2745 filePath[colon - path] = '\0';
2746 line = atoi(colon + 1);
2747 colon = strstr(colon + 1, ":");
2749 col = atoi(colon + 1);
2751 else if(path - 1 >= text && *(path - 1) == '\"')
2753 colon = strchr(path, '\"');
2756 strncpy(filePath, path, colon - path);
2757 filePath[colon - path] = '\0';
2760 else if(path && !colon)
2762 strcpy(filePath, path);
2768 strcpy(completePath, prj.topNode.path);
2769 else if(dir && dir[0])
2770 strcpy(completePath, dir);
2772 completePath[0] = '\0';
2773 PathCat(completePath, filePath);
2775 if((fileAttribs = FileExists(completePath)))
2776 CodeLocationGoTo(completePath, fileAttribs, line, col);
2777 else if(ide.workspace)
2780 for(p : ide.workspace.projects)
2782 strcpy(completePath, p.topNode.path);
2783 PathCat(completePath, filePath);
2784 if((fileAttribs = FileExists(completePath)).isFile)
2786 CodeLocationGoTo(completePath, fileAttribs, line, col);
2793 for(p : ide.workspace.projects)
2795 ProjectNode node = p.topNode.Find(filePath, false);
2798 node.GetFullFilePath(completePath);
2799 if((fileAttribs = FileExists(completePath)).isFile)
2801 CodeLocationGoTo(completePath, fileAttribs, line, col);
2811 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2813 if(fileAttribs.isFile)
2815 char ext[MAX_EXTENSION];
2816 GetExtension(path, ext);
2818 if(binaryDocExt.Find(ext))
2820 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2822 char dirPath[MAX_LOCATION];
2823 StripLastDirectory(path, dirPath);
2828 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, ext, no, normal, false);
2829 if(codeEditor && line)
2831 EditBox editBox = codeEditor.editBox;
2832 editBox.GoToLineNum(line - 1);
2833 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2837 else if(fileAttribs.isDirectory)
2841 void OnRedraw(Surface surface)
2843 Bitmap bitmap = back.bitmap;
2845 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2848 void SheetSelected(SheetType sheetSelected)
2850 if(activeChild == sheet)
2852 if(sheetSelected == methods)
2854 viewPropertiesItem.accelerator = f4;
2855 viewPropertiesItem.parent = viewMenu;
2856 viewMethodsItem.parent = null;
2860 viewMethodsItem.accelerator = f4;
2861 viewMethodsItem.parent = viewMenu;
2862 viewPropertiesItem.parent = null;
2867 viewMethodsItem.parent = viewMenu;
2868 viewPropertiesItem.parent = viewMenu;
2869 if(sheetSelected == methods)
2871 viewMethodsItem.accelerator = f4;
2872 viewPropertiesItem.accelerator = 0;
2876 viewMethodsItem.accelerator = 0;
2877 viewPropertiesItem.accelerator = f4;
2882 void OnActivateClient(Window client, Window previous)
2884 //if(!client || client != previous)
2887 if(!client || client != previous)
2890 dataType = previous._class;
2891 if(previous && !strcmp(dataType.name, "CodeEditor"))
2893 ((CodeEditor)previous).UpdateFormCode();
2895 else if(previous && !strcmp(dataType.name, "Designer"))
2897 ((Designer)previous).codeEditor.UpdateFormCode();
2902 dataType = client._class;
2903 if(client && !strcmp(dataType.name, "CodeEditor"))
2905 CodeEditor codeEditor = (CodeEditor)client;
2906 SetPrivateModule(codeEditor.privateModule);
2907 SetCurrentContext(codeEditor.globalContext);
2908 SetTopContext(codeEditor.globalContext);
2909 SetGlobalContext(codeEditor.globalContext);
2911 SetDefines(&codeEditor.defines);
2912 SetImports(&codeEditor.imports);
2914 SetActiveDesigner(codeEditor.designer);
2916 sheet.codeEditor = codeEditor;
2917 toolBox.codeEditor = codeEditor;
2919 viewDesignerItem.parent = viewMenu;
2920 if(activeChild != codeEditor)
2922 viewCodeItem.parent = viewMenu;
2923 viewDesignerItem.accelerator = 0;
2924 viewCodeItem.accelerator = f8;
2928 viewCodeItem.parent = null;
2929 viewDesignerItem.accelerator = f8;
2932 else if(client && !strcmp(dataType.name, "Designer"))
2934 CodeEditor codeEditor = ((Designer)client).codeEditor;
2937 SetPrivateModule(codeEditor.privateModule);
2938 SetCurrentContext(codeEditor.globalContext);
2939 SetTopContext(codeEditor.globalContext);
2940 SetGlobalContext(codeEditor.globalContext);
2941 SetDefines(&codeEditor.defines);
2942 SetImports(&codeEditor.imports);
2946 SetPrivateModule(null);
2947 SetCurrentContext(null);
2948 SetTopContext(null);
2949 SetGlobalContext(null);
2954 SetActiveDesigner((Designer)client);
2956 sheet.codeEditor = codeEditor;
2957 toolBox.codeEditor = codeEditor;
2959 viewCodeItem.parent = viewMenu;
2960 if(activeChild != client)
2962 viewDesignerItem.parent = viewMenu;
2963 viewDesignerItem.accelerator = f8;
2964 viewCodeItem.accelerator = 0;
2968 viewDesignerItem.parent = null;
2969 viewCodeItem.accelerator = f8;
2974 if(!client && !projectView && sheet.visible)
2977 sheet.visible = false;
2978 toolBox.visible = false;
2981 sheet.codeEditor = null;
2982 toolBox.codeEditor = null;
2983 SetActiveDesigner(null);
2985 viewDesignerItem.parent = null;
2986 viewCodeItem.parent = null;
2989 SheetSelected(sheet.sheetSelected);
2992 projectCompileItem = null;
2997 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
2999 CodeEditor codeEditor = (CodeEditor)client;
3000 EditBox editBox = codeEditor.editBox;
3002 statusBar.AddField(pos);
3004 caps = { width = 40, text = $"CAPS" };
3005 statusBar.AddField(caps);
3006 UpdateStateLight(caps, app.GetKeyState(capsState));
3008 ovr = { width = 36, text = $"OVR" };
3009 statusBar.AddField(ovr);
3010 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3012 num = { width = 36, text = $"NUM" };
3013 statusBar.AddField(num);
3014 UpdateStateLight(num, app.GetKeyState(numState));
3016 //statusBar.text = "Ready";
3018 if(projectView && projectView.project)
3020 bool isCObject = false;
3021 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3022 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3026 char nodeName[MAX_FILENAME];
3027 char name[MAX_FILENAME+96];
3029 ChangeExtension(node.name, "c", nodeName);
3030 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3031 projectCompileItem =
3033 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3035 bool NotifySelect(MenuItem selection, Modifiers mods)
3039 bool isCObject = false;
3040 bool isExcluded = false;
3041 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3045 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3048 List<ProjectNode> nodes { };
3050 projectView.Compile(node.project, nodes, mods.ctrl && mods.shift, isCObject ? cObject : normal);
3058 projectMenu.AddDynamic(projectCompileItem, ide, false);
3064 caps = ovr = num = null;
3069 bool OnClose(bool parentClosing)
3071 //return !projectView.buildInProgress;
3072 if(projectView && projectView.buildInProgress)
3074 if(DontTerminateDebugSession($"Close IDE"))
3076 if(findInFilesDialog)
3077 findInFilesDialog.SearchStop();
3080 workspace.timer.Stop();
3083 ideMainFrame.Destroy(0);
3090 bool passThrough = false;
3091 bool debugStart = false;
3092 bool debugWorkDir = false;
3093 char * passDebugWorkDir = null;
3094 bool openAsText = false;
3095 DynamicString passArgs { };
3098 for(c = 1; c<app.argc; c++)
3102 const char * arg = app.argv[c];
3103 char * buf = new char[strlen(arg)*2+1];
3105 passArgs.concat(" ");
3107 passArgs.concat(buf);
3110 else if(debugWorkDir)
3112 passDebugWorkDir = CopyString(app.argv[c]);
3113 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3114 debugWorkDir = false;
3116 else if(!strcmp(app.argv[c], "-t"))
3118 else if(!strcmp(app.argv[c], "-no-parsing"))
3119 ide.noParsing = true;
3120 else if(!strcmp(app.argv[c], "-debug-start"))
3122 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3123 debugWorkDir = true;
3124 else if(!strcmp(app.argv[c], "-@"))
3128 char fullPath[MAX_LOCATION];
3129 char parentPath[MAX_LOCATION];
3130 char ext[MAX_EXTENSION];
3132 FileAttribs dirAttribs;
3133 GetWorkingDir(fullPath, MAX_LOCATION);
3134 PathCat(fullPath, app.argv[c]);
3135 StripLastDirectory(fullPath, parentPath);
3136 GetExtension(app.argv[c], ext);
3137 isProject = !openAsText && !strcmpi(ext, "epj");
3139 if(isProject && c > (debugStart ? 2 : 1)) continue;
3141 // Create directory for projects (only)
3142 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3144 if(isProject && !FileExists(fullPath))
3146 char name[MAX_LOCATION];
3147 NewProjectDialog newProjectDialog;
3151 projectView.visible = false;
3152 if(!projectView.Destroy(0))
3156 newProjectDialog = { master = this };
3158 strcpy(name, app.argv[c]);
3159 StripExtension(name);
3160 GetLastDirectory(name, name);
3161 newProjectDialog.projectName.contents = name;
3162 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3163 newProjectDialog.locationEditBox.path = parentPath;
3164 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3166 incref newProjectDialog;
3167 newProjectDialog.Modal();
3170 ideSettings.AddRecentProject(projectView.fileName);
3171 ide.UpdateRecentMenus();
3172 settingsContainer.Save();
3174 delete newProjectDialog;
3175 // Open only one project
3179 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3181 else if(strstr(fullPath, "http://") == fullPath)
3182 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3185 if(passThrough && projectView && projectView.project && workspace)
3186 workspace.commandLineArgs = passArgs;
3187 if(passDebugWorkDir && projectView && projectView.project && workspace)
3189 workspace.debugDir = passDebugWorkDir;
3190 delete passDebugWorkDir;
3193 ;//MenuDebugStart(debugStartResumeItem, 0); // <-- how TODO this without getting into the app.Wait lock
3195 UpdateToolBarActiveConfigs(false);
3196 UpdateToolBarActiveCompilers();
3203 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3206 projectView.visible = false;
3207 projectView.Destroy(0);
3210 #ifdef GDB_DEBUG_GUI
3211 gdbDialog.Destroy(0);
3216 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3220 char * oldPaths[128];
3221 String oldList = new char[maxPathLen];
3222 Array<String> newExePaths { };
3223 //Map<String, bool> exePathExists { };
3225 #if defined(__unix__) || defined(__APPLE__)
3226 Array<String> newLibPaths { };
3227 Map<String, bool> libPathExists { };
3232 for(prj : workspace.projects)
3234 DirExpression targetDirExp;
3236 // SKIP FIRST PROJECT...
3237 if(prj == workspace.projects.firstIterator.data) continue;
3239 // NOTE: Right now the additional project config dir will be
3240 // obtained when the debugger is started, so toggling it
3241 // while building will change which library gets used.
3242 // To go with the initial state, e.g. when F5 was pressed,
3243 // we nould need to keep a list of all project's active
3244 // config upon startup.
3245 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3247 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3251 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3252 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3256 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3257 if(cfg.targetType == sharedLibrary && cfg.debug)
3261 if(targetDirExp.dir)
3263 char buffer[MAX_LOCATION];
3264 #if defined(__WIN32__)
3265 Array<String> paths = newExePaths;
3267 Array<String> paths = newLibPaths;
3269 GetSystemPathBuffer(buffer, prj.topNode.path);
3270 PathCat(buffer, targetDirExp.dir);
3273 if(!fstrcmp(p, buffer))
3280 paths.Add(CopyString(buffer));
3282 delete targetDirExp;
3286 for(item : compiler.executableDirs)
3289 for(p : newExePaths)
3291 if(!fstrcmp(p, item))
3298 newExePaths.Add(CopySystemPath(item));
3301 GetEnvironment("PATH", oldList, maxPathLen);
3303 printf("Old value of PATH: %s\n", oldList);
3305 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3306 for(c = 0; c < count; c++)
3309 for(p : newExePaths)
3311 if(!fstrcmp(p, oldPaths[c]))
3318 newExePaths.Add(CopySystemPath(oldPaths[c]));
3322 for(path : newExePaths)
3323 len += strlen(path) + 1;
3324 newList = new char[len + 1];
3326 for(path : newExePaths)
3328 strcat(newList, path);
3329 strcat(newList, pathListSep);
3331 newList[len - 1] = '\0';
3332 SetEnvironment("PATH", newList);
3334 printf("New value of PATH: %s\n", newList);
3341 #if defined(__unix__) || defined(__APPLE__)
3343 for(item : compiler.libraryDirs)
3345 if(!libPathExists[item]) // fstrcmp should be used
3347 String s = CopyString(item);
3349 libPathExists[s] = true;
3353 #if defined(__APPLE__)
3354 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3356 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3359 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3361 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3362 for(c = 0; c < count; c++)
3364 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3366 String s = CopyString(oldPaths[c]);
3368 libPathExists[s] = true;
3373 for(path : newLibPaths)
3374 len += strlen(path) + 1;
3375 newList = new char[len + 1];
3377 for(path : newLibPaths)
3379 strcat(newList, path);
3380 strcat(newList, pathListSep);
3382 newList[len - 1] = '\0';
3383 #if defined(__APPLE__)
3384 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3386 SetEnvironment("LD_LIBRARY_PATH", newList);
3389 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3395 delete libPathExists;
3398 if(compiler.distccEnabled && compiler.distccHosts)
3399 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3404 void DestroyTemporaryProjectDir()
3406 if(tmpPrjDir && tmpPrjDir[0])
3408 if(FileExists(tmpPrjDir).isDirectory)
3409 DestroyDir(tmpPrjDir);
3410 property::tmpPrjDir = null;
3416 // Graphics Driver Menu
3419 app.currentSkin.selectionColor = selectionColor;
3420 app.currentSkin.selectionText = selectionText;
3424 driverItems = new MenuItem[app.numDrivers];
3425 for(c = 0; c < app.numDrivers; c++)
3427 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3428 driverItems[c].id = c;
3429 driverItems[c].isRadio = true;
3432 driverItems = new MenuItem[2];
3433 #if defined(__unix__)
3434 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3435 driverItems[0].id = 0;
3436 driverItems[0].isRadio = true;
3438 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3439 driverItems[0].id = 0;
3440 driverItems[0].isRadio = true;
3442 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3443 driverItems[1].id = 1;
3444 driverItems[1].isRadio = true;
3446 /* skinItems = new MenuItem[app.numSkins];
3447 for(c = 0; c < app.numSkins; c++)
3449 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3450 skinItems[c].id = c;
3451 skinItems[c].isRadio = true;
3454 ideFileDialog.master = this;
3455 ideProjectFileDialog.master = this;
3457 //SetDriverAndSkin();
3461 void UpdateRecentMenus()
3464 Menu fileMenu = menu.FindMenu($"File");
3465 Menu recentFiles = fileMenu.FindMenu($"Recent Files");
3466 Menu recentProjects = fileMenu.FindMenu($"Recent Projects");
3467 char * itemPath = new char[MAX_LOCATION];
3468 char * itemName = new char[MAX_LOCATION+4];
3470 recentFiles.Clear();
3473 for(recent : ideSettings.recentFiles)
3475 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3476 MakeSystemPath(itemPath);
3477 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3478 recentFiles.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3482 recentProjects.Clear();
3484 for(recent : ideSettings.recentProjects)
3486 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3487 MakeSystemPath(itemPath);
3488 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3489 recentProjects.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3501 delete languageItems;
3505 documentor.Puts("Quit\n");
3512 void DestroyDir(char * path)
3514 RecursiveDeleteFolderFSI fsi { };
3519 #if defined(__WIN32__)
3520 define sdkDirName = "Ecere SDK";
3522 define sdkDirName = "ecere";
3525 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3528 char * v = new char[maxPathLen];
3532 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3533 StripLastDirectory(path, path);
3534 PathCat(path, subDir);
3535 if(name) PathCat(path, name);
3536 if(FileExists(path) & attribs) found = true;
3538 #if defined(__WIN32__)
3541 GetEnvironment("ECERE_SDK_SRC", v, maxPathLen);
3544 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3545 PathCat(path, subDir);
3546 if(name) PathCat(path, name);
3547 if(FileExists(path) & attribs) found = true;
3552 GetEnvironment("AppData", v, maxPathLen);
3555 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3556 PathCat(path, sdkDirName);
3557 PathCat(path, subDir);
3558 if(name) PathCat(path, name);
3559 if(FileExists(path) & attribs) found = true;
3564 GetEnvironment("ProgramData", v, maxPathLen);
3567 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3568 PathCat(path, sdkDirName);
3569 PathCat(path, subDir);
3570 if(name) PathCat(path, name);
3571 if(FileExists(path) & attribs) found = true;
3576 GetEnvironment("ProgramFiles", v, maxPathLen);
3579 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3580 PathCat(path, sdkDirName);
3581 PathCat(path, subDir);
3582 if(name) PathCat(path, name);
3583 if(FileExists(path) & attribs) found = true;
3588 GetEnvironment("ProgramFiles(x86)", v, maxPathLen);
3591 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3592 PathCat(path, sdkDirName);
3593 PathCat(path, subDir);
3594 if(name) PathCat(path, name);
3595 if(FileExists(path) & attribs) found = true;
3600 GetEnvironment("SystemDrive", v, maxPathLen);
3603 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3604 PathCat(path, "Program Files");
3605 PathCat(path, sdkDirName);
3606 PathCat(path, subDir);
3607 if(name) PathCat(path, name);
3608 if(FileExists(path) & attribs) found = true;
3617 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3618 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3619 for(c=0; c<numTokens; c++)
3621 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3622 PathCat(path, sdkDirName);
3623 PathCat(path, subDir);
3624 if(name) PathCat(path, name);
3625 if(FileExists(path) & attribs) found = true;
3633 void FindAndShellOpenInstalledFolder(const char * name)
3635 char path[MAX_LOCATION];
3636 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3640 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3642 char path[MAX_LOCATION];
3643 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3647 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3649 bool preserveRootFolder;
3651 void OutFolder(const char * folderPath, bool isRoot)
3653 if(!(preserveRootFolder && isRoot))
3654 RemoveDir(folderPath);
3657 bool OnFile(const char * filePath)
3659 DeleteFile(filePath);
3664 class IDEApp : GuiApplication
3666 //driver = "Win32Console";
3667 // driver = "OpenGL";
3671 TempFile includeFile { };
3676 char ext[MAX_EXTENSION];
3677 SetLoggingMode(stdOut, null);
3678 //SetLoggingMode(debug, null);
3680 settingsContainer.Load();
3682 if(ideSettings.language)
3684 const String language = GetLanguageString();
3685 if(ideSettings.language.OnCompare(language))
3687 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3692 // First count files arg to decide whether to maximize
3694 bool passThrough = false, debugWorkDir = false;
3697 for(c = 1; c<app.argc; c++)
3700 else if(debugWorkDir)
3701 debugWorkDir = false;
3702 else if(!strcmp(app.argv[c], "-t"));
3703 else if(!strcmp(app.argv[c], "-no-parsing"));
3704 else if(!strcmp(app.argv[c], "-debug-start"));
3705 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3706 debugWorkDir = true;
3707 else if(!strcmp(app.argv[c], "-@"))
3714 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3716 app.driver = "OpenGL";
3717 ide.driverItems[1].checked = true;
3721 #if defined(__unix__) || defined(__APPLE__)
3722 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3724 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3726 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3730 char model[MAX_LOCATION];
3731 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3733 ide.duck.modelFile = model;
3734 ide.duck.parent = ideMainFrame;
3737 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3738 ide.debugRubberDuck.disabled = false;
3742 desktop.caption = titleECEREIDE;
3745 for(c = 1; c<app.argc; c++)
3747 char fullPath[MAX_LOCATION];
3748 GetWorkingDir(fullPath, MAX_LOCATION);
3749 PathCat(fullPath, app.argv[c]);
3750 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3754 // Default to language specified by environment if no language selected
3755 if(!ideSettings.language)
3757 ideSettings.language = GetLanguageString();
3758 settingsContainer.Save();
3761 // Default to home directory if no directory yet set up
3762 if(!ideSettings.ideProjectFileDialogLocation[0])
3765 char location[MAX_LOCATION];
3766 char * home = getenv("HOME");
3767 char * homeDrive = getenv("HOMEDRIVE");
3768 char * homePath = getenv("HOMEPATH");
3769 char * userProfile = getenv("USERPROFILE");
3770 char * systemDrive = getenv("SystemDrive");
3771 if(home && FileExists(home).isDirectory)
3773 strcpy(location, home);
3776 if(!found && homeDrive && homePath)
3778 strcpy(location, homeDrive);
3779 PathCat(location, homePath);
3780 if(FileExists(location).isDirectory)
3783 if(!found && FileExists(userProfile).isDirectory)
3785 strcpy(location, userProfile);
3788 if(!found && FileExists(systemDrive).isDirectory)
3790 strcpy(location, systemDrive);
3795 ideSettings.ideProjectFileDialogLocation = location;
3796 if(!ideSettings.ideFileDialogLocation[0])
3797 ideSettings.ideFileDialogLocation = location;
3801 if(!LoadIncludeFile())
3802 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3804 // Create language menu
3806 String language = ideSettings.language;
3810 ide.languageItems = new MenuItem[languages.count];
3813 ide.languageItems[i] =
3815 ide.languageMenu, l.name;
3816 bitmap = { l.bitmap };
3820 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3822 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3824 // Re-select previous selected language if aborted
3825 String language = ideSettings.language;
3829 if(((!language || !language[0]) && i == 0) ||
3830 (language && !strcmpi(l.code, language)))
3832 ide.languageItems[i].checked = true;
3844 // Try to find country-specific language first
3850 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3852 ide.languageItems[i].checked = true;
3860 // Try generalizing locale
3861 if(!found && language)
3864 char genericLocale[256];
3866 strncpy(genericLocale, language, sizeof(genericLocale));
3867 genericLocale[sizeof(genericLocale)-1] = 0;
3869 under = strchr(genericLocale, '_');
3872 if(!strcmpi(genericLocale, "zh"))
3873 strcpy(genericLocale, "zh_CN");
3874 if(strcmp(genericLocale, language))
3878 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3880 ide.languageItems[i].checked = true;
3890 ide.languageItems[0].checked = true;
3892 MenuDivider { ide.languageMenu };
3895 ide.languageMenu, "Help Translate";
3897 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3899 ShellOpen("http://translations.launchpad.net/ecere");
3905 ideMainFrame.Create();
3906 if(app.argFilesCount > 1)
3907 ide.MenuWindowTileVert(null, 0);
3911 bool Cycle(bool idle)
3915 if(ide.documentor.Peek())
3918 ide.documentor.GetLine(line, sizeof(line));
3919 if(!strcmpi(line, "Exited"))
3921 ide.documentor.CloseInput();
3922 ide.documentor.CloseOutput();
3923 ide.documentor.Wait();
3924 delete ide.documentor;
3927 if(ide.documentor && ide.documentor.eof)
3929 ide.documentor.CloseInput();
3930 ide.documentor.CloseOutput();
3931 ide.documentor.Wait();
3932 delete ide.documentor;
3938 bool LoadIncludeFile()
3940 bool result = false;
3941 File include = FileOpen(":crossplatform.mk", read);
3944 File f = includeFile;
3947 for(; !include.Eof(); )
3950 int count = include.Read(buffer, 1, 4096);
3951 f.Write(buffer, 1, count);
3961 IDEMainFrame ideMainFrame { };
3963 define app = ((IDEApp)__thisModule);
3965 define titleECEREIDE = $"Ecere IDE (Debug)";
3967 define titleECEREIDE = $"Ecere IDE";