2 public import static "ecere"
3 public import static "ec"
9 import "GlobalSettingsDialog"
10 import "NewProjectDialog"
11 import "FindInFilesDialog"
18 import "ProjectConfig"
20 import "NodeProperties"
21 import "ProjectSettings"
33 import "BreakpointsView"
34 import "CallStackView"
45 import "FileSystemIterator"
47 AVLTree<const String> binaryDocExt
49 "wav", "mp3", "flac", "ogg",
51 "avi", "mkv", "mpg", "mpeg",
52 "7z", "zip", "gz", "bz2", "xz", "rar", "z", "tar", "ear",
53 "pdf", "odp", "ods", "odt", "ppt", "doc", "xls", "pptx", "docx", "xlsx"
56 #if defined(__WIN32__)
57 define pathListSep = ";";
59 define pathListSep = ":";
62 define maxPathLen = 65 * MAX_LOCATION;
64 class PathBackup : struct
71 oldPath = new char[maxPathLen];
72 oldLDPath = new char[maxPathLen];
74 GetEnvironment("PATH", oldPath, maxPathLen);
75 #if defined(__APPLE__)
76 GetEnvironment("DYLD_LIBRARY_PATH", oldLDPath, maxPathLen);
78 GetEnvironment("LD_LIBRARY_PATH", oldLDPath, maxPathLen);
84 SetEnvironment("PATH", oldPath);
85 #if defined(__APPLE__)
86 SetEnvironment("DYLD_LIBRARY_PATH", oldLDPath);
88 SetEnvironment("LD_LIBRARY_PATH", oldLDPath);
95 enum OpenCreateIfFails { no, yes, something, whatever };
96 enum OpenMethod { normal, add };
98 static Array<FileFilter> fileFilters
100 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
101 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
102 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
103 { $"Text files (*.txt, *.text, *.nfo, *.info)", "txt, text, nfo, info" },
104 { $"Web files (*.html, *.htm, *.xhtml, *.css, *.php, *.js, *.jsi, *.rb, *.xml)", "html, htm, xhtml, css, php, js, jsi, rb, xml" },
105 { $"Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", "jpg, jpeg, bmp, pcx, png, gif" },
106 { $"3D Studio Model Files (*.3ds)", "3ds" },
107 { $"All files", null }
110 static Array<FileType> fileTypes
112 { $"Based on extension", null },
115 { $"3D Studio Model", "3ds" }
118 static Array<FileFilter> projectFilters
120 { $"Project Files (*.epj)", ProjectExtension }
123 static Array<FileType> projectTypes
125 { $"Project File", ProjectExtension }
128 static Array<FileFilter> findInFilesFileFilters
130 { $"eC Files (*.ec, *.eh)", "ec, eh" },
131 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
132 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
133 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
134 { $"Text files (*.txt)", "txt" },
135 { $"All files", null }
138 FileDialog ideFileDialog
140 type = multiOpen, text = $"Open";
141 types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType), filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter);
144 define openProjectFileDialogTitle = $"Open Project";
145 define addProjectFileDialogTitle = $"Open Additional Project";
146 FileDialog ideProjectFileDialog
149 types = projectTypes.array, sizeTypes = projectTypes.count * sizeof(FileType), filters = projectFilters.array, sizeFilters = projectFilters.count * sizeof(FileFilter);
152 GlobalSettingsDialog globalSettingsDialog
154 ideSettings = ideSettings;
155 settingsContainer = settingsContainer;
157 void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange)
159 switch(globalSettingsChange)
164 for(child = ide.firstChild; child; child = child.next)
166 if(child._class == class(CodeEditor))
168 CodeEditor codeEditor = (CodeEditor) child;
169 codeEditor.editBox.freeCaret = ideSettings.useFreeCaret;
170 // codeEditor.editBox.lineNumbers = ideSettings.showLineNumbers;
171 codeEditor.editBox.caretFollowsScrolling = ideSettings.caretFollowsScrolling;
172 codeEditor.OnPostCreate(); // Update editBox margin size
179 case compilerSettings:
181 ide.UpdateCompilerConfigs(true);
188 void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
193 lineY = (line - 1) * lineH;
194 if(lineY + lineH > scrollY && lineY + lineH < scrollY + boxH)
196 Bitmap bitmap = resource.bitmap;
198 surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
203 #define IDEItem(x) (&((IDEWorkSpace)0).x)
205 class IDEToolbar : ToolBar
209 ToolButton buttonNewFile { this, toolTip = $"New file", menuItemPtr = IDEItem(fileNewItem) };
211 ToolButton buttonOpenFile { this, toolTip = $"Open file", menuItemPtr = IDEItem(fileOpenItem) };
213 // ToolButton buttonCloseFile { this, toolTip = $"Close file", menuItemPtr = IDEItem(fileCloseItem) };
215 ToolButton buttonSaveFile { this, toolTip = $"Save file", menuItemPtr = IDEItem(fileSaveItem) };
217 ToolButton buttonSaveAllFile { this, toolTip = $"Save all", menuItemPtr = IDEItem(fileSaveAllItem) };
219 ToolSeparator separator1 { this };
228 // ToolSeparator separator2 { this };
232 ToolButton buttonNewProject { this, toolTip = $"New project", menuItemPtr = IDEItem(projectNewItem) };
234 ToolButton buttonOpenProject { this, toolTip = $"Open project", menuItemPtr = IDEItem(projectOpenItem) };
235 // Add project to workspace
236 ToolButton buttonAddProject { this, toolTip = $"Add project to workspace", menuItemPtr = IDEItem(projectAddItem), disabled = true; };
238 // ToolButton buttonCloseProject { this, toolTip = $"Close project", menuItemPtr = IDEItem(projectCloseItem), disabled = true; };
240 ToolSeparator separator3 { this };
242 // Build/Execution options
244 ToolButton buttonBuild { this, toolTip = $"Build project", menuItemPtr = IDEItem(projectBuildItem), disabled = true; };
246 ToolButton buttonReLink { this, toolTip = $"Relink project", menuItemPtr = IDEItem(projectLinkItem), disabled = true; };
248 ToolButton buttonRebuild { this, toolTip = $"Rebuild project", menuItemPtr = IDEItem(projectRebuildItem), disabled = true; };
250 ToolButton buttonClean { this, toolTip = $"Clean project", menuItemPtr = IDEItem(projectCleanItem), disabled = true; };
252 // ToolButton buttonRealClean { this, toolTip = $"Real clean project", menuItemPtr = IDEItem(projectRealCleanItem), disabled = true; };
253 // Regenerate Makefile
254 ToolButton buttonRegenerateMakefile { this, toolTip = $"Regenerate Makefile", menuItemPtr = IDEItem(projectRegenerateItem), disabled = true; };
255 // Compile actual file
257 ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem), disabled = true; };
258 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
259 ToolButton buttonInstall { this, toolTip = $"Install", menuItemPtr = IDEItem(projectInstallItem), disabled = true; };
262 ToolSeparator separator4 { this };
266 ToolButton buttonDebugStartResume { this, toolTip = $"Start", menuItemPtr = IDEItem(debugStartResumeItem), disabled = true; };
268 ToolButton buttonDebugRestart { this, toolTip = $"Restart", menuItemPtr = IDEItem(debugRestartItem), disabled = true; };
270 ToolButton buttonDebugPause { this, toolTip = $"Break", menuItemPtr = IDEItem(debugBreakItem), disabled = true; };
272 ToolButton buttonDebugStop { this, toolTip = $"Stop", menuItemPtr = IDEItem(debugStopItem), disabled = true; };
274 //ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem) };
276 ToolButton buttonDebugStepInto { this, toolTip = $"Step Into", menuItemPtr = IDEItem(debugStepIntoItem), disabled = true; };
278 ToolButton buttonDebugStepOver { this, toolTip = $"Step Over", menuItemPtr = IDEItem(debugStepOverItem), disabled = true; };
280 ToolButton buttonDebugStepOut { this, toolTip = $"Step Out", menuItemPtr = IDEItem(debugStepOutItem), disabled = true; };
282 ToolButton buttonDebugSkipStepOver { this, toolTip = $"Step Over Skipping Breakpoints", menuItemPtr = IDEItem(debugSkipStepOverItem), disabled = true; };
284 ToolSeparator separator5 { this };
286 Window spacer5 { this, size = { 4 } };
290 this, toolTip = $"Active Configuration(s)", size = { 160 }, disabled = true;
291 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
294 ide.workspace.SelectActiveConfig(row.string);
299 Window spacer6 { this, size = { 4 } };
301 DropBox activeCompiler
303 this, toolTip = $"Active Compiler", size = { 160 }, disabled = true;
304 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
306 if(ide.workspace && ide.projectView && row && strcmp(row.string, ide.workspace.activeCompiler))
308 bool silent = ide.projectView.buildInProgress == none ? false : true;
309 CompilerConfig compiler = ideSettings.GetCompilerConfig(row.string);
310 ide.workspace.activeCompiler = row.string;
311 ide.projectView.ShowOutputBuildLog(!silent);
313 ide.projectView.DisplayCompiler(compiler, false);
314 for(prj : ide.workspace.projects)
315 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
317 ide.workspace.Save();
323 DropBox activeBitDepth
325 this, toolTip = $"Active Bit Length", size = { 60 }, disabled = true;
326 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
328 if(ide.workspace && ide.projectView && row)
330 bool silent = ide.projectView.buildInProgress == none ? false : true;
331 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
332 ide.workspace.bitDepth = (int)row.tag;
333 ide.projectView.ShowOutputBuildLog(!silent);
335 ide.projectView.DisplayCompiler(compiler, false);
336 for(prj : ide.workspace.projects)
337 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
339 ide.workspace.Save();
345 Window spacer7 { this, size = { 4 } };
350 row = activeBitDepth.AddString("Auto");
352 activeBitDepth.AddString("32 bit").tag = 32;
353 activeBitDepth.AddString("64 bit").tag = 64;
354 activeBitDepth.currentRow = row;
358 class IDEMainFrame : Window
360 background = formColor;
361 borderStyle = sizable;
365 minClientSize = { 600, 300 };
367 icon = { ":icon.png" };
368 text = titleECEREIDE;
372 anchor = { top = 0, right = 0, bottom = 0 };
375 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
382 isActiveClient = true;
384 direction = vertical;
385 background = formColor;
386 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
394 ((IDEWorkSpace)master).toolBar = null;
397 IDEWorkSpace ideWorkSpace { stack, this, toolBar = toolBar };
400 define ide = ideMainFrame.ideWorkSpace;
402 class IDEWorkSpace : Window
404 background = Color { 85, 85, 85 };
407 hasVertScroll = true;
408 hasHorzScroll = true;
410 isActiveClient = true;
411 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
415 MenuItem * driverItems, * skinItems, * languageItems;
416 StatusField pos { width = 150 };
417 StatusField ovr, caps, num;
420 BitmapResource back { ":ecereBack.jpg", window = this };
421 BitmapResource bmpBp { ":codeMarks/breakpoint.png", window = this };
422 BitmapResource bmpBpDisabled { ":codeMarks/breakpointDisabled.png", window = this };
423 BitmapResource bmpBpHalf { ":codeMarks/breakpointHalf.png", window = this };
424 BitmapResource bmpBpHalfDisabled { ":codeMarks/breakpointHalfDisabled.png", window = this };
425 BitmapResource bmpCursor { ":codeMarks/cursor.png", window = this };
426 BitmapResource bmpCursorError { ":codeMarks/cursorError.png", window = this };
427 BitmapResource bmpTopFrame { ":codeMarks/topFrame.png", window = this };
428 BitmapResource bmpTopFrameError { ":codeMarks/topFrameError.png", window = this };
429 BitmapResource bmpTopFrameHalf { ":codeMarks/topFrameHalf.png", window = this };
430 BitmapResource bmpTopFrameHalfError { ":codeMarks/topFrameHalfError.png", window = this };
432 BuildOutputMode rightClickMenuBuildOutputMode;
434 Debugger debugger { };
436 ProjectView projectView;
438 OutputView outputView
442 void OnGotoError(const char * line, bool noParsing)
444 CompilerConfig compiler = ide.workspace ? ideSettings.GetCompilerConfig(ide.workspace.activeCompiler) : null;
445 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
446 ide.GoToError(line, noParsing, objectFileExt);
450 void OnCodeLocationParseAndGoTo(const char * line)
452 CompilerConfig compiler = ide.workspace ? ideSettings.GetCompilerConfig(ide.workspace.activeCompiler) : null;
453 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
454 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir, objectFileExt);
458 bool OnKeyDown(Key key, unichar ch)
463 if(activeBox != findBox || !ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
464 ide.ShowCodeEditor();
468 OutputView::OnKeyDown(key, ch);
475 bool OnClose(bool parentClosing)
479 ide.RepositionWindows(false);
480 return parentClosing;
484 CallStackView callStackView
486 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
488 void OnSelectFrame(int frameIndex)
490 ide.debugger.GoToStackFrameLine(frameIndex, true, true);
492 ide.debugger.SelectFrame(frameIndex);
495 void OnToggleBreakpoint()
497 Debugger debugger = ide.debugger;
498 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
500 int line = debugger.activeFrame.line;
501 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line);
504 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
505 if(codeEditor) { codeEditor.Update(null); Activate(); }
510 bool OnKeyDown(Key key, unichar ch)
514 case escape: ide.ShowCodeEditor(); break;
519 bool OnClose(bool parentClosing)
523 ide.RepositionWindows(false);
524 return parentClosing;
527 void OnRedraw(Surface surface)
529 Debugger debugger = ide.debugger;
530 Frame activeFrame = debugger.activeFrame;
534 int lineCursor, lineTopFrame;
535 int lineH, scrollY, boxH;
537 Breakpoint bp = null;
540 scrollY = editBox.scroll.y;
541 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
542 //activeThread = debugger.activeThread;
543 //hitThread = debugger.hitThread;
544 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
546 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
547 if(activeFrame.absoluteFile)
549 for(i : ide.workspace.breakpoints; i.type == user)
551 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
552 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
553 activeFrame.line == i.line)
561 DrawLineMarginIcon(surface,
562 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
563 lineCursor /*1*/, lineH, scrollY, boxH);
565 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
566 DrawLineMarginIcon(surface,
567 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
568 1, lineH, scrollY, boxH);
570 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
571 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
572 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
574 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
575 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
577 if(editBox.horzScroll && editBox.horzScroll.visible)
579 surface.SetBackground(control);
580 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
585 WatchesView watchesView { parent = this };
586 ThreadsView threadsView
588 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
590 bool OnKeyDown(Key key, unichar ch)
594 case escape: ide.ShowCodeEditor(); break;
599 bool OnClose(bool parentClosing)
603 ide.RepositionWindows(false);
604 return parentClosing;
607 void OnSelectThread(int threadId)
610 ide.debugger.SelectThread(threadId);
613 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
616 Debugger debugger = ide.debugger;
617 *activeThread = debugger.activeThread;
618 *hitThread = debugger.hitThread;
619 *signalThread = debugger.signalThread;
624 BreakpointsView breakpointsView { parent = this };
626 ToolBox toolBox { parent = this, visible = false };
627 Sheet sheet { parent = this, visible = false };
630 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
632 Menu fileMenu { menu, $"File", f, hasMargin = true };
635 fileMenu, $"New", n, ctrlN;
636 bitmap = { ":actions/docNew.png" };
637 bool NotifySelect(MenuItem selection, Modifiers mods)
639 Window currentDoc = activeClient;
640 bool maximizeDoc = ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
641 Window document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, false);
642 RepositionWindows(false);
643 document.NotifySaved = DocumentSaved;
647 MenuItem fileOpenItem
649 fileMenu, $"Open...", o, ctrlO;
650 bitmap = { ":actions/docOpen.png" };
651 bool NotifySelect(MenuItem selection, Modifiers mods)
653 if(!projectView && ideSettings.ideFileDialogLocation)
654 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
657 if(ideFileDialog.Modal() == ok)
659 bool gotWhatWeWant = false;
661 int numSelections = ideFileDialog.numSelections;
662 const char * const * multiFilePaths = ideFileDialog.multiFilePaths;
664 for(c = 0; c < numSelections; c++)
666 if(OpenFile(multiFilePaths[c], false, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
667 gotWhatWeWant = true;
670 MessageBox { type = yesNo, master = this, text = $"Error opening file",
671 contents = $"Open a different file?" }.Modal() == no)
673 if(!projectView && gotWhatWeWant)
674 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
675 ide.RepositionWindows(false);
685 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
686 MenuDivider { fileMenu };
687 MenuItem fileSaveItem
689 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
691 // For the toolbar button; clients can still override that for the menu item
692 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
694 Window w = activeClient;
696 w.MenuFileSave(null, 0);
700 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
701 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
702 MenuDivider { fileMenu };
705 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
706 bool NotifySelect(MenuItem selection, Modifiers mods)
708 findInFilesDialog.replaceMode = false;
709 findInFilesDialog.Show();
713 MenuItem replaceInFiles
715 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
716 bool NotifySelect(MenuItem selection, Modifiers mods)
718 findInFilesDialog.replaceMode = true;
719 findInFilesDialog.Show();
723 MenuDivider { fileMenu };
724 MenuItem globalSettingsItem
726 fileMenu, $"Global Settings...", g;
727 bool NotifySelect(MenuItem selection, Modifiers mods)
729 globalSettingsDialog.master = this;
730 if(ide.workspace && ide.workspace.activeCompiler)
731 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.activeCompiler;
732 else if(ideSettings.defaultCompiler)
733 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
734 globalSettingsDialog.Modal();
738 MenuDivider { fileMenu };
739 Menu recentFilesMenu { fileMenu, $"Recent Files", r };
740 Menu recentProjectsMenu { fileMenu, $"Recent Projects", p };
741 MenuDivider { fileMenu };
744 fileMenu, $"Exit", x, altF4;
746 bool NotifySelect(MenuItem selection, Modifiers mods)
748 ideMainFrame.Destroy(0);
753 bool FileRecentFile(MenuItem selection, Modifiers mods)
756 RecentPaths recentFiles = workspace ? workspace.recentFiles : ideConfig.recentFiles;
757 for(file : recentFiles)
759 if(id == selection.id)
762 char extension[MAX_EXTENSION] = "";
763 GetExtension(file, extension);
764 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
765 if(mods.ctrl && !mods.shift)
767 char * command = PrintString("ecere-ide ", isProjectFile ? "-t " : "", file);
773 OpenFile(file, false, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
774 ide.RepositionWindows(false);
783 bool FileRecentProject(MenuItem selection, Modifiers mods)
786 for(file : ideConfig.recentWorkspaces)
788 if(id == selection.id)
790 if(mods.ctrl && !mods.shift)
792 char * command = PrintString("ecere-ide ", file);
797 OpenFile(file, false, true, (mods.ctrl && mods.shift) ? "txt" : null, no, normal, mods.ctrl && mods.shift);
805 MenuPlacement editMenu { menu, $"Edit", e };
807 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
808 MenuItem projectNewItem
810 projectMenu, $"New...", n, Key { n, true, true };
811 bitmap = { ":actions/projNew.png" };
812 bool NotifySelect(MenuItem selection, Modifiers mods)
814 if(!DontTerminateDebugSession($"New Project"))
817 NewProjectDialog newProjectDialog { master = this };
818 incref newProjectDialog;
819 result = newProjectDialog.Modal();
824 newProjectDialog.CreateNewProject();
827 ideConfig.recentWorkspaces.addRecent(CopyString(projectView.fileName));
828 ide.updateRecentProjectsMenu();
832 delete newProjectDialog;
837 MenuItem projectOpenItem
839 projectMenu, $"Open...", o, Key { o, true, true };
840 bitmap = { ":actions/projOpen.png" };
841 bool NotifySelect(MenuItem selection, Modifiers mods)
843 if(ideSettings.ideProjectFileDialogLocation)
844 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
846 ideProjectFileDialog.text = openProjectFileDialogTitle;
847 if(ideProjectFileDialog.Modal() == ok)
849 OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
850 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
855 MenuItem projectQuickItem
857 projectMenu, $"Quick...", q, f7, disabled = true;
858 bool NotifySelect(MenuItem selection, Modifiers mods)
861 QuickProjectDialog { this }.Modal();
865 MenuItem projectAddItem
867 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
868 bitmap = { ":actions/projAdd.png" };
870 bool NotifySelect(MenuItem selection, Modifiers mods)
872 if(ideSettings.ideProjectFileDialogLocation)
873 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
875 ideProjectFileDialog.text = addProjectFileDialogTitle;
878 if(ideProjectFileDialog.Modal() == ok)
880 if(OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
882 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
883 contents = $"Add a different project?" }.Modal() == no)
894 MenuItem projectCloseItem
896 projectMenu, $"Close", c, disabled = true;
897 bool NotifySelect(MenuItem selection, Modifiers mods)
901 if(!ide.DontTerminateDebugSession($"Project Close"))
907 MenuDivider { projectMenu };
908 MenuItem projectSettingsItem
910 projectMenu, $"Settings...", s, altF7, disabled = true;
911 bool NotifySelect(MenuItem selection, Modifiers mods)
913 projectView.MenuSettings(projectView.active ? selection : null, mods);
917 MenuDivider { projectMenu };
918 MenuItem projectBrowseFolderItem
920 projectMenu, $"Browse Project Folder", p, disabled = true;
921 bool NotifySelect(MenuItem selection, Modifiers mods)
924 projectView.MenuBrowseFolder(null, mods);
928 MenuDivider { projectMenu };
929 MenuItem projectRunItem
931 projectMenu, $"Run", r, ctrlF5, disabled = true;
932 bitmap = { ":actions/run.png" };
933 bool NotifySelect(MenuItem selection, Modifiers mods)
936 projectView.Run(null, mods);
940 MenuItem projectBuildItem
942 projectMenu, $"Build", b, f7, disabled = true;
943 bitmap = { ":actions/build.png" };
944 bool NotifySelect(MenuItem selection, Modifiers mods)
948 if(projectView.buildInProgress == none)
949 projectView.ProjectBuild(projectView.active ? selection : null, mods);
951 projectView.stopBuild = true;
956 MenuItem projectLinkItem
958 projectMenu, $"Relink", l, disabled = true;
959 bitmap = { ":actions/relink.png" };
960 bool NotifySelect(MenuItem selection, Modifiers mods)
963 projectView.ProjectLink(projectView.active ? selection : null, mods);
967 MenuItem projectRebuildItem
969 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
970 bitmap = { ":actions/rebuild.png" };
971 bool NotifySelect(MenuItem selection, Modifiers mods)
974 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
978 MenuItem projectCleanTargetItem
980 projectMenu, $"Clean Target", g, disabled = true;
981 bitmap = { ":actions/clean.png" };
982 bool NotifySelect(MenuItem selection, Modifiers mods)
987 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
992 MenuItem projectCleanItem
994 projectMenu, $"Clean", e, disabled = true;
995 bitmap = { ":actions/clean.png" };
996 bool NotifySelect(MenuItem selection, Modifiers mods)
1001 projectView.ProjectClean(projectView.active ? selection : null, mods);
1006 MenuItem projectRealCleanItem
1008 projectMenu, $"Real Clean", disabled = true;
1009 bitmap = { ":actions/clean.png" };
1010 bool NotifySelect(MenuItem selection, Modifiers mods)
1015 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1020 MenuItem projectRegenerateItem
1022 projectMenu, $"Regenerate Makefile", m, disabled = true;
1023 bitmap = { ":actions/regMakefile.png" };
1024 bool NotifySelect(MenuItem selection, Modifiers mods)
1027 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1031 MenuItem projectInstallItem
1033 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
1034 projectMenu, $"Install", t, disabled = true;
1036 bitmap = { ":status/software-update-available.png" };
1037 bool NotifySelect(MenuItem selection, Modifiers mods)
1040 projectView.ProjectInstall(projectView.active ? selection : null, mods);
1044 MenuItem projectCompileItem;
1045 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1046 MenuItem debugStartResumeItem
1048 debugMenu, $"Start", s, f5, disabled = true;
1049 bitmap = { ":actions/debug.png" };
1050 NotifySelect = MenuDebugStart;
1052 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1056 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1057 if(!projectView.DebugStart())
1058 debugStartResumeItem.disabled = false; // same exception
1062 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1065 projectView.DebugResume();
1068 MenuItem debugRestartItem
1070 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1071 bitmap = { ":actions/restart.png" };
1072 bool NotifySelect(MenuItem selection, Modifiers mods)
1075 projectView.DebugRestart();
1079 MenuItem debugBreakItem
1081 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1082 bitmap = { ":actions/pause.png" };
1083 bool NotifySelect(MenuItem selection, Modifiers mods)
1085 if(projectView && projectView.buildInProgress != none)
1088 projectView.DebugBreak();
1092 MenuItem debugStopItem
1094 debugMenu, $"Stop", p, shiftF5, disabled = true;
1095 bitmap = { ":actions/stopDebug.png" };
1096 bool NotifySelect(MenuItem selection, Modifiers mods)
1099 projectView.DebugStop();
1103 MenuDivider { debugMenu };
1107 // nonClient = true,
1114 anchor = { right = 0, bottom = 0 },
1116 isActiveClient = false,
1118 clickThrough = true,
1119 size = { 500, 500 };
1121 bool OnLoadGraphics()
1123 ModelView::OnLoadGraphics();
1124 camera.position.z /= 1.3;
1125 camera.orientation = Euler { yaw = 280, pitch = 20 };
1131 bool OnRightButtonDown(int x, int y, Modifiers mods)
1133 if(!displaySystem.flags.flipping) return true;
1134 MenuWindowMove(null, 0);
1138 bool OnRightButtonUp(int x, int y, Modifiers mods)
1140 position = position;
1145 MenuItem debugRubberDuck
1147 debugMenu, $"Rubber Duck", checkable = true, disabled = true;
1148 bool NotifySelect(MenuItem selection, Modifiers mods)
1150 if(selection.checked)
1158 MenuDivider { debugMenu };
1159 MenuItem debugUseValgrindItem
1161 debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
1162 bool NotifySelect(MenuItem selection, Modifiers mods)
1166 ide.workspace.useValgrind = selection.checked;
1167 ide.workspace.Save();
1169 ide.AdjustValgrindMenus();
1173 Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
1174 MenuItem debugValgrindNoLeakCheckItem { debugValgrindLeakCheckItem, $"No" , f, id = ValgrindLeakCheck::no , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1175 MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; };
1176 MenuItem debugValgrindYesLeakCheckItem { debugValgrindLeakCheckItem, $"Yes" , f, id = ValgrindLeakCheck::yes , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1177 MenuItem debugValgrindFullLeakCheckItem { debugValgrindLeakCheckItem, $"Full" , f, id = ValgrindLeakCheck::full , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1178 bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
1182 if(selection.checked)
1184 ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
1186 debugValgrindNoLeakCheckItem.checked = debugValgrindNoLeakCheckItem.id == vgLeakCheck;
1187 debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
1188 debugValgrindYesLeakCheckItem.checked = debugValgrindYesLeakCheckItem.id == vgLeakCheck;
1189 debugValgrindFullLeakCheckItem.checked = debugValgrindFullLeakCheckItem.id == vgLeakCheck;
1191 ide.workspace.vgLeakCheck = vgLeakCheck;
1192 ide.workspace.Save();
1195 selection.checked = true;
1199 Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
1200 MenuItem debugValgrindRSDefaultItem { debugValgrindRedzoneSizeItem, $"Default", f, id = -1, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; };
1201 MenuItem debugValgrindRS0Item { debugValgrindRedzoneSizeItem, "0" , f, id = 0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1202 MenuItem debugValgrindRS16Item { debugValgrindRedzoneSizeItem, "16" , f, id = 16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1203 MenuItem debugValgrindRS32Item { debugValgrindRedzoneSizeItem, "32" , f, id = 32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1204 MenuItem debugValgrindRS64Item { debugValgrindRedzoneSizeItem, "64" , f, id = 64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1205 MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, "128" , f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1206 MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, "256" , f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1207 MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, "512" , f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1208 bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
1212 if(selection.checked)
1214 int vgRedzoneSize = (int)selection.id;
1216 debugValgrindRSDefaultItem.checked = debugValgrindRSDefaultItem.id == vgRedzoneSize;
1217 debugValgrindRS0Item.checked = debugValgrindRS0Item.id == vgRedzoneSize;
1218 debugValgrindRS16Item.checked = debugValgrindRS16Item.id == vgRedzoneSize;
1219 debugValgrindRS32Item.checked = debugValgrindRS32Item.id == vgRedzoneSize;
1220 debugValgrindRS64Item.checked = debugValgrindRS64Item.id == vgRedzoneSize;
1221 debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
1222 debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
1223 debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
1225 ide.workspace.vgRedzoneSize = vgRedzoneSize;
1226 ide.workspace.Save();
1229 selection.checked = true;
1233 MenuItem debugValgrindTrackOriginsItem
1235 debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
1236 bool NotifySelect(MenuItem selection, Modifiers mods)
1240 ide.workspace.vgTrackOrigins = selection.checked;
1241 ide.workspace.Save();
1247 MenuDivider { debugMenu };
1248 MenuItem debugStepIntoItem
1250 debugMenu, $"Step Into", i, f11, disabled = true;
1251 bitmap = { ":actions/stepInto.png" };
1252 bool NotifySelect(MenuItem selection, Modifiers mods)
1254 if(projectView) projectView.DebugStepInto();
1258 MenuItem debugStepOverItem
1260 debugMenu, $"Step Over", v, f10, disabled = true;
1261 bitmap = { ":actions/stepOver.png" };
1262 bool NotifySelect(MenuItem selection, Modifiers mods)
1264 if(projectView) projectView.DebugStepOver(false);
1268 MenuItem debugSkipStepOverItem
1270 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1271 bitmap = { ":actions/stepOverSkipBreak.png" };
1272 bool NotifySelect(MenuItem selection, Modifiers mods)
1274 if(projectView) projectView.DebugStepOver(true);
1278 MenuItem debugStepOutItem
1280 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1281 bitmap = { ":actions/stepOut.png" };
1282 bool NotifySelect(MenuItem selection, Modifiers mods)
1284 if(projectView) projectView.DebugStepOut(false);
1288 MenuItem debugSkipStepOutItem
1290 debugMenu, $"Step Out Skipping Breakpoints", n, Key { f11, ctrl = true, shift = true }, disabled = true;
1291 bitmap = { ":actions/skipBreaks.png" };
1292 bool NotifySelect(MenuItem selection, Modifiers mods)
1294 if(projectView) projectView.DebugStepOut(true);
1299 MenuItem debugStepUntilItem
1301 debugMenu, $"Step Over Until Next Line", x, disabled = true;
1302 bool NotifySelect(MenuItem selection, Modifiers mods)
1304 if(projectView) projectView.DebugStepUntil(false);
1308 MenuItem debugSkipStepUntilItem
1310 debugMenu, $"Step Over Until Next Line Skipping Breakpoints", e, Key { f10, shift = true, alt = true }, disabled = true;
1311 bool NotifySelect(MenuItem selection, Modifiers mods)
1313 if(projectView) projectView.DebugStepUntil(true);
1318 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1319 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1320 MenuPlacement debugRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level", l };
1321 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", g };
1323 MenuPlacement debugBpRunToCursorItem { debugMenu, $"BP Run To Cursor" };
1324 MenuPlacement debugBpSkipRunToCursorItem { debugMenu, $"BP Run To Cursor Skipping Breakpoints" };
1325 MenuPlacement debugBpRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level" };
1326 MenuPlacement debugBpSkipRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level Skipping Breakpoints" };
1328 //MenuDivider { debugMenu };
1329 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1330 MenuPlacement imageMenu { menu, $"Image", i };
1331 Menu viewMenu { menu, $"View", v };
1332 MenuItem viewProjectItem
1334 viewMenu, $"Project View", j, alt0, disabled = true;
1335 bool NotifySelect(MenuItem selection, Modifiers mods)
1339 projectView.visible = true;
1340 projectView.Activate();
1345 MenuPlacement { viewMenu, $"View Designer" };
1346 MenuPlacement { viewMenu, $"View Code" };
1347 MenuPlacement { viewMenu, $"View Properties" };
1348 MenuPlacement { viewMenu, $"View Methods" };
1349 MenuItem viewDesignerItem
1351 viewMenu, $"View Designer", d, f8;
1352 bool NotifySelect(MenuItem selection, Modifiers mods)
1354 Window client = activeClient;
1355 Class dataType = client._class;
1356 if(!strcmp(dataType.name, "Designer"))
1358 client.visible = true;
1362 ((CodeEditor)client).ViewDesigner();
1366 MenuItem viewCodeItem
1368 viewMenu, $"View Code", c, f8;
1369 bool NotifySelect(MenuItem selection, Modifiers mods)
1371 Window client = activeClient;
1372 Class dataType = client._class;
1373 if(!strcmp(dataType.name, "Designer"))
1374 client = ((Designer)client).codeEditor;
1377 // Do this after so the caret isn't moved yet...
1378 client.visible = true;
1382 MenuItem viewPropertiesItem
1384 viewMenu, $"View Properties", p, f4;
1385 bool NotifySelect(MenuItem selection, Modifiers mods)
1387 sheet.visible = true;
1388 sheet.sheetSelected = properties;
1393 MenuItem viewMethodsItem
1395 viewMenu, $"View Methods", m, f4;
1396 bool NotifySelect(MenuItem selection, Modifiers mods)
1398 sheet.visible = true;
1399 sheet.sheetSelected = methods;
1404 MenuItem viewToolBoxItem
1406 viewMenu, $"View Toolbox", x, f12;
1407 bool NotifySelect(MenuItem selection, Modifiers mods)
1409 toolBox.visible = true;
1414 MenuItem viewOutputItem
1416 viewMenu, $"Output", o, alt2;
1417 bool NotifySelect(MenuItem selection, Modifiers mods)
1423 MenuItem viewWatchesItem
1425 viewMenu, $"Watches", w, alt3;
1426 bool NotifySelect(MenuItem selection, Modifiers mods)
1432 MenuItem viewThreadsItem
1434 viewMenu, $"Threads", t, alt4;
1435 bool NotifySelect(MenuItem selection, Modifiers mods)
1441 MenuItem viewBreakpointsItem
1443 viewMenu, $"Breakpoints", b, alt5;
1444 bool NotifySelect(MenuItem selection, Modifiers mods)
1446 breakpointsView.Show();
1450 MenuItem viewCallStackItem
1452 viewMenu, $"Call Stack", s, alt7;
1453 bool NotifySelect(MenuItem selection, Modifiers mods)
1455 callStackView.Show();
1459 MenuItem viewAllDebugViews
1461 viewMenu, $"All Debug Views", a, alt9;
1462 bool NotifySelect(MenuItem selection, Modifiers mods)
1467 callStackView.Show();
1468 breakpointsView.Show();
1472 #ifdef GDB_DEBUG_GUI
1473 MenuDivider { viewMenu };
1474 MenuItem viewGDBItem
1476 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1477 bool NotifySelect(MenuItem selection, Modifiers mods)
1484 MenuDivider { viewMenu };
1485 MenuItem viewColorPicker
1487 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1488 bool NotifySelect(MenuItem selection, Modifiers mods)
1490 ColorPicker colorPicker { master = this };
1491 colorPicker.Modal();
1495 MenuDivider { viewMenu };
1499 viewMenu, "Full Screen", f, checkable = true;
1501 bool NotifySelect(MenuItem selection, Modifiers mods)
1503 app.fullScreen ^= true;
1505 anchor = { 0, 0, 0, 0 };
1510 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1512 MenuDivider { viewMenu };
1514 Menu languageMenu { viewMenu, "Language", l };
1516 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1517 Menu windowMenu { menu, $"Window", w };
1518 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1519 MenuDivider { windowMenu };
1520 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1521 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1522 MenuDivider { windowMenu };
1523 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1524 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1525 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1526 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1527 MenuDivider { windowMenu };
1528 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1529 Menu helpMenu { menu, $"Help", h };
1532 helpMenu, $"API Reference", r, f1;
1533 bool NotifySelect(MenuItem selection, Modifiers mods)
1537 char * p = new char[MAX_LOCATION];
1539 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1540 PathCat(p, "documentor");
1541 #if defined(__WIN32__)
1542 ChangeExtension(p, "exe", p);
1544 if(!FileExists(p).isFile)
1545 strcpy(p, "documentor");
1547 documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
1552 Process_ShowWindows(documentor.GetProcessID());
1553 // documentor.Puts("Activate\n");
1558 MenuDivider { helpMenu };
1561 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1562 bool NotifySelect(MenuItem selection, Modifiers mods)
1564 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1568 MenuDivider { helpMenu };
1571 helpMenu, $"Documentation Folder", d;
1572 bool NotifySelect(MenuItem selection, Modifiers mods)
1574 FindAndShellOpenInstalledFolder("doc");
1580 helpMenu, $"Samples Folder", s;
1581 bool NotifySelect(MenuItem selection, Modifiers mods)
1583 FindAndShellOpenInstalledFolder("samples");
1589 helpMenu, $"Extras Folder", x;
1590 bool NotifySelect(MenuItem selection, Modifiers mods)
1592 FindAndShellOpenInstalledFolder("extras");
1596 MenuDivider { helpMenu };
1599 helpMenu, $"Community Forums", f;
1600 bool NotifySelect(MenuItem selection, Modifiers mods)
1602 ShellOpen("http://ecere.com/forums");
1606 MenuDivider { helpMenu };
1609 helpMenu, $"About...", a;
1610 bool NotifySelect(MenuItem selection, Modifiers mods)
1612 AboutIDE { master = this }.Modal();
1617 property ToolBox toolBox
1619 get { return toolBox; }
1622 property Sheet sheet
1624 get { return sheet; }
1627 property Project project
1629 get { return projectView ? projectView.project : null; }
1632 property Workspace workspace
1634 get { return projectView ? projectView.workspace : null; }
1637 FindInFilesDialog findInFilesDialog
1640 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1647 #ifdef GDB_DEBUG_GUI
1650 master = this, parent = this;
1651 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1653 void OnCommand(const char * string)
1656 ide.debugger.SendGDBCommand(string);
1661 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1663 //app.driver = app.drivers[selection.id];
1664 #if defined(__unix__) || defined(__APPLE__)
1665 app.driver = selection.id ? "OpenGL" : "X";
1667 app.driver = selection.id ? "OpenGL" : "GDI";
1669 delete ideSettings.displayDriver;
1670 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1672 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1674 settingsContainer.Save();
1675 //SetDriverAndSkin();
1679 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1681 app.skin = app.skins[selection.id];
1686 void SetDriverAndSkin()
1689 for(c = 0; c < app.numSkins; c++)
1690 if(!strcmp(app.skins[c], app.skin))
1692 skinItems[c].checked = true;
1695 for(c = 0; c < app.numDrivers; c++)
1696 if(!strcmp(app.drivers[c], app.driver))
1698 driverItems[c].checked = true;
1703 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1705 Project project = workspace.projects.firstIterator.data;
1706 projectView = ProjectView
1709 fileName = fileName;
1711 void NotifyDestroyed(Window window, DialogResult result)
1714 text = titleECEREIDE;
1719 projectView.Create();
1720 RepositionWindows(false);
1722 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1723 projectView.workspace = workspace;
1724 projectView.project = project;
1725 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1728 updateRecentMenus();
1730 ide.breakpointsView.LoadFromWorkspace();
1731 ide.watchesView.LoadFromWorkspace();
1733 findInFilesDialog.projectNodeField.userData = projectView;
1736 char fileName[MAX_LOCATION];
1737 strcpy(fileName, project.topNode.path);
1738 PathCat(fileName, project.topNode.name);
1745 projectView.visible = false;
1746 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1748 if(findInFilesDialog)
1750 char workingDir[MAX_LOCATION];
1751 GetWorkingDir(workingDir, MAX_LOCATION);
1752 findInFilesDialog.SearchStop();
1753 findInFilesDialog.currentDirectory = workingDir;
1755 sheet.visible = false;
1756 toolBox.visible = false;
1757 outputView.visible = false;
1758 ideMainFrame.text = titleECEREIDE;
1760 ide.updateRecentMenus();
1766 void RepositionWindows(bool expand)
1771 bool callStackVisible = expand ? false : callStackView.visible;
1772 bool threadsVisible = expand ? false : threadsView.visible;
1773 bool watchesVisible = expand ? false : watchesView.visible;
1774 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1775 bool toolBoxVisible = toolBox.visible;
1776 bool outputVisible = expand ? false : outputView.visible;
1777 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1778 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1780 for(child = firstChild; child; child = child.next)
1782 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1783 child._class == class(Sheet) || child._class == class(ProjectView))
1785 Anchor anchor = child.anchor;
1786 anchor.top = topDistance;
1787 anchor.bottom = bottomDistance;
1788 if(child._class == class(CodeEditor) || child._class == class(Designer))
1790 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1791 anchor.right = toolBoxVisible ? 150 : 0;
1794 child.anchor = anchor;
1798 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1799 child._class == class(BreakpointsView))
1800 child.visible = false;
1803 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1805 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1809 bool ShowCodeEditor()
1812 activeClient.Activate();
1813 else if(projectView)
1815 projectView.visible = true;
1816 projectView.Activate();
1818 else if(sheet.visible)
1821 outputView.visible = false;
1825 void DocumentSaved(Window document, const char * fileName)
1827 ideConfig.recentFiles.addRecent(CopyString(fileName));
1828 ide.updateRecentFilesMenu();
1829 ide.AdjustFileMenus();
1832 bool Window::OnFileModified(FileChange fileChange, const char * param)
1835 sprintf(temp, $"The document %s was modified by another application.\n"
1836 "Would you like to reload it and lose your changes?", this.fileName);
1837 if(MessageBox { creationActivation = flash, type = yesNo, master = this/*.parent*/,
1838 text = $"Document has been modified", contents = temp }.Modal() == yes)
1840 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1841 char * fileName = CopyString(this.fileName);
1842 WindowState state = this.state;
1843 Anchor anchor = this.anchor;
1844 Size size = this.size;
1846 this.modifiedDocument = false;
1848 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1851 this.anchor = anchor;
1853 this.SetState(state, true, 0);
1861 void UpdateMakefiles()
1865 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
1866 for(prj : workspace.projects)
1867 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1872 void UpdateCompilerConfigs(bool mute)
1874 UpdateToolBarActiveCompilers();
1877 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
1878 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
1881 projectView.ShowOutputBuildLog(true);
1882 projectView.DisplayCompiler(compiler, false);
1884 for(prj : workspace.projects)
1885 projectView.ProjectPrepareCompiler(prj, compiler, silent);
1890 void UpdateToolBarActiveCompilers()
1892 toolBar.activeCompiler.Clear();
1893 for(compiler : ideConfig.compilers)
1895 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
1896 if(workspace && workspace.activeCompiler && !strcmp(compiler.name, workspace.activeCompiler))
1897 toolBar.activeCompiler.currentRow = row;
1899 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
1900 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
1901 toolBar.activeBitDepth.SelectRow(toolBar.activeBitDepth.FindRow(workspace ? workspace.bitDepth : 0));
1904 void UpdateToolBarActiveConfigs(bool selectionOnly)
1906 bool commonSelected = false;
1907 DataRow row = toolBar.activeConfig.currentRow;
1909 row = toolBar.activeConfig.FindRow(1);
1912 toolBar.activeConfig.Clear();
1913 row = toolBar.activeConfig.AddString($"(Mixed)");
1918 char * configName = null;
1921 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
1922 for(prj : workspace.projects)
1924 for(cfg : prj.configurations)
1927 configs[cfg.name] = 1;
1932 toolBar.activeConfig.AddString(&name);
1936 if(projectView && projectView.project)
1938 for(prj : workspace.projects)
1940 if(prj.config && prj.config.name)
1942 configName = prj.config.name;
1948 commonSelected = true;
1949 for(prj : workspace.projects)
1951 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
1953 commonSelected = false;
1961 commonSelected = false;
1962 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
1964 if(!strcmp(row.string, configName))
1966 toolBar.activeConfig.currentRow = row;
1967 commonSelected = true;
1974 toolBar.activeConfig.Sort(null, 0);
1976 toolBar.activeConfig.currentRow = row;
1981 bool unavailable = !project;
1983 projectAddItem.disabled = unavailable;
1984 toolBar.buttonAddProject.disabled = unavailable;
1986 projectSettingsItem.disabled = unavailable;
1988 projectBrowseFolderItem.disabled = unavailable;
1990 viewProjectItem.disabled = unavailable;
1992 toolBar.activeConfig.disabled = unavailable;
1993 toolBar.activeCompiler.disabled = unavailable;
1994 toolBar.activeBitDepth.disabled = unavailable;
1997 debugUseValgrindItem.disabled = unavailable;
1998 AdjustValgrindMenus();
2007 void AdjustValgrindMenus()
2009 bool unavailable = !project || !debugUseValgrindItem.checked;
2010 debugValgrindNoLeakCheckItem.disabled = unavailable;
2011 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2012 debugValgrindYesLeakCheckItem.disabled = unavailable;
2013 debugValgrindFullLeakCheckItem.disabled = unavailable;
2015 debugValgrindTrackOriginsItem.disabled = unavailable;
2017 debugValgrindRSDefaultItem.disabled = unavailable;
2018 debugValgrindRS0Item.disabled = unavailable;
2019 debugValgrindRS16Item.disabled = unavailable;
2020 debugValgrindRS32Item.disabled = unavailable;
2021 debugValgrindRS64Item.disabled = unavailable;
2022 debugValgrindRS128Item.disabled = unavailable;
2023 debugValgrindRS256Item.disabled = unavailable;
2024 debugValgrindRS512Item.disabled = unavailable;
2028 property bool hasOpenedCodeEditors
2033 for(w = firstChild; w; w = w.next)
2034 if(w._class == class(CodeEditor) &&
2035 w.isDocument && !w.closing && w.visible && w.created &&
2036 w.fileName && w.fileName[0])
2042 void AdjustFileMenus()
2044 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2046 projectQuickItem.disabled = unavailable;
2049 void AdjustBuildMenus()
2051 bool unavailable = project && projectView.buildInProgress;
2052 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2053 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2055 projectNewItem.disabled = unavailable;
2056 toolBar.buttonNewProject.disabled = unavailable;
2057 projectOpenItem.disabled = unavailable;
2058 toolBar.buttonOpenProject.disabled = unavailable;
2060 unavailable = !project || projectView.buildInProgress;
2062 projectCloseItem.disabled = unavailable;
2063 // toolBar.buttonCloseProject.disabled = unavailable;
2065 projectRunItem.disabled = naForRun;
2066 toolBar.buttonRun.disabled = naForRun;
2068 projectBuildItem.disabled = false;
2069 projectBuildItem.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2070 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2072 projectLinkItem.disabled = unavailable;
2073 toolBar.buttonReLink.disabled = unavailable;
2074 projectRebuildItem.disabled = unavailable;
2075 toolBar.buttonRebuild.disabled = unavailable;
2076 projectCleanItem.disabled = unavailable;
2077 toolBar.buttonClean.disabled = unavailable;
2078 projectCleanTargetItem.disabled = unavailable;
2079 projectRealCleanItem.disabled = unavailable;
2080 // toolBar.buttonRealClean.disabled = unavailable;
2081 projectRegenerateItem.disabled = unavailable;
2082 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2083 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2084 projectInstallItem.disabled = unavailable;
2085 toolBar.buttonInstall.disabled = unavailable;
2087 projectCompileItem.disabled = unavailable;
2089 AdjustPopupBuildMenus();
2092 void AdjustPopupBuildMenus()
2094 bool unavailable = !project || projectView.buildInProgress;
2096 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2099 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2100 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, mode);
2103 menu.disabled = false;
2104 menu.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2105 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2108 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, mode); if(menu) menu.disabled = unavailable;
2109 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, mode); if(menu) menu.disabled = unavailable;
2110 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, mode); if(menu) menu.disabled = unavailable;
2111 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, mode); if(menu) menu.disabled = unavailable;
2112 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, mode); if(menu) menu.disabled = unavailable;
2113 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, mode); if(menu) menu.disabled = unavailable;
2114 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, mode); if(menu) menu.disabled = unavailable;
2115 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, mode); if(menu) menu.disabled = unavailable;
2116 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, mode); if(menu) menu.disabled = unavailable;
2117 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, mode); if(menu) menu.disabled = unavailable;
2118 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, mode); if(menu) menu.disabled = unavailable;
2119 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, mode); if(menu) menu.disabled = unavailable;
2120 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, mode); if(menu) menu.disabled = unavailable;
2121 projectView.popupMenu.Update(null);
2125 property bool areDebugMenusUnavailable { get {
2127 project.GetTargetType(project.config) != executable ||
2128 projectView.buildInProgress == buildingMainProject;
2131 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2132 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2133 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2135 void AdjustDebugMenus()
2137 bool unavailable = areDebugMenusUnavailable;
2138 bool running = isDebuggerRunning;
2139 bool stopped = isDebuggerStopped;
2140 bool active = debugger.isActive;
2142 bool isNotRunning = unavailable || !running;
2143 bool isNotNotRunning = unavailable || running;
2144 bool isNotStopped = unavailable || !stopped;
2145 bool isNotActive = unavailable || !active;
2147 debugStartResumeItem.disabled = isNotNotRunning;
2148 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2149 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2152 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2153 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2156 debugBreakItem.disabled = isNotRunning;
2157 debugStopItem.disabled = isNotActive;
2158 debugRestartItem.disabled = isNotActive;
2161 toolBar.buttonDebugPause.disabled = isNotRunning;
2162 toolBar.buttonDebugStop.disabled = isNotActive;
2163 toolBar.buttonDebugRestart.disabled = isNotActive;
2166 debugStepIntoItem.disabled = isNotNotRunning;
2167 debugStepOverItem.disabled = isNotNotRunning;
2168 debugSkipStepOverItem.disabled = isNotNotRunning;
2169 debugStepOutItem.disabled = isNotStopped;
2170 debugSkipStepOutItem.disabled = isNotStopped;
2172 debugStepUntilItem.disabled = isNotStopped;
2173 debugSkipStepUntilItem.disabled = isNotStopped;
2177 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2178 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2179 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2180 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2181 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2183 if((Designer)GetActiveDesigner())
2185 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2187 codeEditor.AdjustDebugMenus();
2191 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2193 char tempString[MAX_LOCATION];
2194 strcpy(tempString, directory);
2195 if(saveSettings && !projectView)
2197 ideSettings.ideFileDialogLocation = directory;
2198 settingsContainer.Save();
2201 ideFileDialog.currentDirectory = tempString;
2202 codeEditorFileDialog.currentDirectory = tempString;
2203 codeEditorFormFileDialog.currentDirectory = tempString;
2206 void ChangeProjectFileDialogDirectory(char * directory)
2208 ideSettings.ideProjectFileDialogLocation = directory;
2209 settingsContainer.Save();
2212 Window FindWindow(const char * filePath)
2214 Window document = null;
2216 // TOCHECK: Do we need to change slashes here?
2217 for(document = firstChild; document; document = document.next)
2219 const char * fileName = document.fileName;
2220 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2222 document.visible = true;
2223 document.Activate();
2230 bool DontTerminateDebugSession(const char * title)
2232 if(debugger.isActive)
2234 if(MessageBox { type = yesNo, master = ide,
2235 contents = $"Do you want to terminate the debugging session in progress?",
2236 text = title }.Modal() == no)
2239 MessageBox msg { type = yesNo, master = ide,
2240 contents = "Do you want to terminate the debugging session in progress?",
2242 if(msg.Modal() == no)
2254 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2256 char extension[MAX_EXTENSION] = "";
2257 Window document = null;
2258 bool isProject = false;
2259 bool needFileModified = true;
2260 char winFilePath[MAX_LOCATION];
2261 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2262 Window currentDoc = activeClient;
2263 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2266 GetExtension(filePath, extension);
2270 strcpy(extension, type);
2272 if(strcmp(extension, ProjectExtension))
2274 for(document = firstChild; document; document = document.next)
2276 const char * fileName = document.fileName;
2277 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2279 document.visible = true;
2281 document.Activate();
2287 if(createIfFails == whatever)
2289 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2291 needFileModified = false;
2292 if(openMethod == normal)
2294 if(DontTerminateDebugSession($"Open Project"))
2303 Workspace workspace = null;
2305 if(FileExists(filePath))
2307 if(!strcmp(extension, ProjectExtension))
2309 char workspaceFile[MAX_LOCATION];
2310 strcpy(workspaceFile, filePath);
2311 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2312 workspace = LoadWorkspace(workspaceFile, filePath);
2314 else if(!strcmp(extension, WorkspaceExtension))
2315 workspace = LoadWorkspace(filePath, null);
2322 CreateProjectView(workspace, filePath);
2323 document = projectView;
2325 toolBox.visible = true;
2326 sheet.visible = true;
2327 projectView.MakeActive();
2329 workspace.ParseLoadedBreakpoints();
2330 workspace.DropInvalidBreakpoints(null);
2333 ide.projectView.ShowOutputBuildLog(true);
2335 CompilerConfig compiler = ideSettings.GetCompilerConfig(ide.workspace.activeCompiler);
2336 ide.projectView.DisplayCompiler(compiler, false);
2339 UpdateCompilerConfigs(false);
2342 char newWorkingDir[MAX_LOCATION];
2343 StripLastDirectory(filePath, newWorkingDir);
2344 ChangeFileDialogsDirectory(newWorkingDir, false);
2347 document.fileName = filePath;
2349 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2351 // this crashes on starting ide with epj file, solution please?
2352 // app.UpdateDisplay();
2354 workspace.OpenPreviouslyOpenedFiles(noParsing);
2355 workspace.holdTracking = true;
2356 ide.RepositionWindows(false);
2357 workspace.holdTracking = false;
2359 workspace.timer.Start();
2361 #if !defined(__WIN32__)
2362 // Valgrind Debug menu updates
2363 debugUseValgrindItem.checked = workspace.useValgrind;
2365 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2366 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2367 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2368 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2370 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2371 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2372 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2373 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2374 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2375 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2376 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2377 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2379 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2382 findInFilesDialog.mode = FindInFilesMode::project;
2383 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2386 char location[MAX_LOCATION];
2387 StripLastDirectory(ide.project.topNode.path, location);
2388 ChangeProjectFileDialogDirectory(location);
2395 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2397 ideProjectFileDialog.text = openProjectFileDialogTitle;
2398 if(ideProjectFileDialog.Modal() == cancel)
2400 filePath = ideProjectFileDialog.filePath;
2401 GetExtension(filePath, extension);
2412 else if(openMethod == add)
2417 char slashFilePath[MAX_LOCATION];
2418 GetSlashPathBuffer(slashFilePath, filePath);
2419 for(p : workspace.projects)
2421 if(!fstrcmp(p.filePath, slashFilePath))
2429 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2430 contents = $"This project is already present in workspace." }.Modal();
2434 prj = LoadProject(filePath, null);
2437 const char * activeConfigName = null;
2438 CompilerConfig compiler = ideSettings.GetCompilerConfig(workspace.activeCompiler);
2439 prj.StartMonitoring();
2440 workspace.AddProject(prj, null);
2441 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2442 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2443 activeConfigName = toolBar.activeConfig.currentRow.string;
2444 if(activeConfigName)
2446 for(cfg : prj.configurations)
2448 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2456 projectView.AddNode(prj.topNode, null);
2457 workspace.modified = true;
2459 findInFilesDialog.AddProjectItem(prj);
2460 projectView.ShowOutputBuildLog(true);
2461 projectView.DisplayCompiler(compiler, false);
2462 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2466 char location[MAX_LOCATION];
2467 StripLastDirectory(prj.topNode.path, location);
2468 ChangeProjectFileDialogDirectory(location);
2471 // projectView is associated with the main project and not with the one just added but
2472 return projectView; // just to let the caller know something was opened
2480 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2481 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2482 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2484 if(FileExists(filePath))
2485 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2486 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2487 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2490 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2493 else if(!strcmp(extension, "3ds"))
2495 if(FileExists(filePath))
2496 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2497 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2498 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2502 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2505 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2506 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2507 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2508 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2509 !strcmp(extension, "js"))
2511 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2512 editor.updatingCode = true;
2513 if(editor.LoadFile(filePath))
2516 editor.visible = true;
2520 needFileModified = false;
2524 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2525 if(editor.LoadFile(filePath))
2528 editor.visible = true;
2532 needFileModified = false;
2535 if(document && (document._class == class(PictureEdit) ||
2536 document._class == class(ModelView)))
2541 document.fileName = filePath;
2542 if(workspace && !workspace.holdTracking)
2543 workspace.UpdateOpenedFileInfo(filePath, opened, true);
2547 if(!document && createIfFails != no)
2549 if(createIfFails != yes && !needFileModified &&
2550 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2551 createIfFails = yes;
2552 if(createIfFails == yes || createIfFails == whatever)
2554 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2556 document.fileName = filePath;
2562 if(projectView && document._class == class(CodeEditor) && workspace)
2563 workspace.RestorePreviouslyOpenedFileState((CodeEditor)document);
2565 if(needFileModified)
2566 document.OnFileModified = OnFileModified;
2567 document.NotifySaved = DocumentSaved;
2568 if(maximizeDoc && document.hasMaximize)
2569 document.state = maximized;
2572 ideConfig.recentWorkspaces.addRecent(CopyString(document.fileName));
2574 ideConfig.recentFiles.addRecent(CopyString(document.fileName));
2575 ide.AdjustFileMenus();
2576 ide.updateRecentFilesMenu();
2584 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2585 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2587 if(!parentClosing && ide.workspace)
2588 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2591 bool ModelView::ModelViewOnClose(bool parentClosing)
2593 if(!parentClosing && ide.workspace)
2594 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2597 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2599 if(!parentClosing && ide.workspace)
2600 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2605 void OnUnloadGraphics(Window window)
2607 display.ClearMaterials();
2608 display.ClearTextures();
2609 display.ClearMeshes();
2613 void UpdateStateLight(StatusField fld, bool on)
2615 fld.color = on ? lime : Color { 128,128,128 };
2616 fld.backColor = on ? dimGray : 0;
2620 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2622 UpdateStateLight(caps, app.GetKeyState(capsState));
2623 UpdateStateLight(num, app.GetKeyState(numState));
2627 bool OnKeyDown(Key key, unichar ch)
2631 case b: projectView.Update(null); break;
2632 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2633 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2638 bool OnKeyUp(Key key, unichar ch)
2642 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2643 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2648 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2651 projectView.GoToError(line, noParsing, objectFileExt);
2654 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2656 FileAttribs result { };
2657 FileAttribs fileAttribs;
2661 strcpy(selectedPath, prj.topNode.path);
2662 else if(dir && dir[0])
2663 strcpy(selectedPath, dir);
2665 selectedPath[0] = '\0';
2666 PathCat(selectedPath, filePath);
2668 if((fileAttribs = FileExists(selectedPath)).isFile)
2669 result = fileAttribs;
2673 for(p : workspace.projects)
2675 strcpy(selectedPath, p.topNode.path);
2676 PathCat(selectedPath, filePath);
2677 if((fileAttribs = FileExists(selectedPath)).isFile)
2680 result = fileAttribs;
2687 ProjectNode n = null;
2688 for(p : workspace.projects)
2690 if((n = p.topNode.Find(filePath, false)))
2692 n.GetFullFilePath(selectedPath, true);
2693 if((fileAttribs = FileExists(selectedPath)).isFile)
2696 result = fileAttribs;
2701 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2702 (fileAttribs = FileExists(selectedPath)).isFile)
2705 result = fileAttribs;
2713 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2716 const char *path = text;
2717 char *colon = strchr(text, ':');
2718 char filePath[MAX_LOCATION] = "";
2719 char completePath[MAX_LOCATION];
2720 int line = 0, col = 0;
2721 int len = strlen(text);
2723 FileAttribs fileAttribs;
2725 // support for valgrind output
2726 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2737 /*for(s=colon; *s; s++)
2746 //line = atoi(colon+1);
2748 // support for "Found n match(es) in "file/path";
2749 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)
2755 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2757 path = (colon - 1 > path) ? colon - 1 : path;
2758 colon = strstr(colon + 1, ":");
2760 if(*path == '*' && (s = strchr(path+1, '*')))
2762 while(isspace(*path)) path++;
2766 char * close = strchr(path, ')');
2770 strncpy(name, path+1, close - path - 1);
2771 name[close - path - 1] = '\0';
2772 for(p : ide.workspace.projects)
2774 if(!strcmp(p.name, name))
2784 prj = project ? project : (dir ? null : ide.project);
2787 strncpy(filePath, path, colon - path);
2788 filePath[colon - path] = '\0';
2789 line = atoi(colon + 1);
2790 colon = strstr(colon + 1, ":");
2792 col = atoi(colon + 1);
2794 else if(path - 1 >= text && *(path - 1) == '\"')
2796 colon = strchr(path, '\"');
2799 strncpy(filePath, path, colon - path);
2800 filePath[colon - path] = '\0';
2803 else if(path && !colon)
2805 strcpy(filePath, path);
2808 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2809 CodeLocationGoTo(completePath, fileAttribs, line, col);
2812 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2814 if(fileAttribs.isFile)
2816 char ext[MAX_EXTENSION];
2817 GetExtension(path, ext);
2819 if(binaryDocExt.Find(ext))
2821 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2822 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2824 char dirPath[MAX_LOCATION];
2825 StripLastDirectory(path, dirPath);
2830 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2831 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2833 EditBox editBox = codeEditor.editBox;
2834 editBox.GoToLineNum(line - 1);
2835 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2839 else if(fileAttribs.isDirectory)
2843 void OnRedraw(Surface surface)
2845 Bitmap bitmap = back.bitmap;
2847 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2850 void SheetSelected(SheetType sheetSelected)
2852 if(activeChild == sheet)
2854 if(sheetSelected == methods)
2856 viewPropertiesItem.accelerator = f4;
2857 viewPropertiesItem.parent = viewMenu;
2858 viewMethodsItem.parent = null;
2862 viewMethodsItem.accelerator = f4;
2863 viewMethodsItem.parent = viewMenu;
2864 viewPropertiesItem.parent = null;
2869 viewMethodsItem.parent = viewMenu;
2870 viewPropertiesItem.parent = viewMenu;
2871 if(sheetSelected == methods)
2873 viewMethodsItem.accelerator = f4;
2874 viewPropertiesItem.accelerator = 0;
2878 viewMethodsItem.accelerator = 0;
2879 viewPropertiesItem.accelerator = f4;
2884 void OnActivateClient(Window client, Window previous)
2886 //if(!client || client != previous)
2889 if(!client || client != previous)
2892 dataType = previous._class;
2893 if(previous && !strcmp(dataType.name, "CodeEditor"))
2895 ((CodeEditor)previous).UpdateFormCode();
2897 else if(previous && !strcmp(dataType.name, "Designer"))
2899 ((Designer)previous).codeEditor.UpdateFormCode();
2904 dataType = client._class;
2905 if(client && !strcmp(dataType.name, "CodeEditor"))
2907 CodeEditor codeEditor = (CodeEditor)client;
2908 SetPrivateModule(codeEditor.privateModule);
2909 SetCurrentContext(codeEditor.globalContext);
2910 SetTopContext(codeEditor.globalContext);
2911 SetGlobalContext(codeEditor.globalContext);
2913 SetDefines(&codeEditor.defines);
2914 SetImports(&codeEditor.imports);
2916 SetActiveDesigner(codeEditor.designer);
2918 sheet.codeEditor = codeEditor;
2919 toolBox.codeEditor = codeEditor;
2921 viewDesignerItem.parent = viewMenu;
2922 if(activeChild != codeEditor)
2924 viewCodeItem.parent = viewMenu;
2925 viewDesignerItem.accelerator = 0;
2926 viewCodeItem.accelerator = f8;
2930 viewCodeItem.parent = null;
2931 viewDesignerItem.accelerator = f8;
2934 else if(client && !strcmp(dataType.name, "Designer"))
2936 CodeEditor codeEditor = ((Designer)client).codeEditor;
2939 SetPrivateModule(codeEditor.privateModule);
2940 SetCurrentContext(codeEditor.globalContext);
2941 SetTopContext(codeEditor.globalContext);
2942 SetGlobalContext(codeEditor.globalContext);
2943 SetDefines(&codeEditor.defines);
2944 SetImports(&codeEditor.imports);
2948 SetPrivateModule(null);
2949 SetCurrentContext(null);
2950 SetTopContext(null);
2951 SetGlobalContext(null);
2956 SetActiveDesigner((Designer)client);
2958 sheet.codeEditor = codeEditor;
2959 toolBox.codeEditor = codeEditor;
2961 viewCodeItem.parent = viewMenu;
2962 if(activeChild != client)
2964 viewDesignerItem.parent = viewMenu;
2965 viewDesignerItem.accelerator = f8;
2966 viewCodeItem.accelerator = 0;
2970 viewDesignerItem.parent = null;
2971 viewCodeItem.accelerator = f8;
2976 if(!client && !projectView && sheet.visible)
2979 sheet.visible = false;
2980 toolBox.visible = false;
2983 sheet.codeEditor = null;
2984 toolBox.codeEditor = null;
2985 SetActiveDesigner(null);
2987 viewDesignerItem.parent = null;
2988 viewCodeItem.parent = null;
2991 SheetSelected(sheet.sheetSelected);
2994 projectCompileItem = null;
2999 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3001 CodeEditor codeEditor = (CodeEditor)client;
3002 EditBox editBox = codeEditor.editBox;
3004 statusBar.AddField(pos);
3006 caps = { width = 40, text = $"CAPS" };
3007 statusBar.AddField(caps);
3008 UpdateStateLight(caps, app.GetKeyState(capsState));
3010 ovr = { width = 36, text = $"OVR" };
3011 statusBar.AddField(ovr);
3012 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3014 num = { width = 36, text = $"NUM" };
3015 statusBar.AddField(num);
3016 UpdateStateLight(num, app.GetKeyState(numState));
3018 //statusBar.text = "Ready";
3020 if(projectView && projectView.project)
3022 bool isCObject = false;
3023 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3024 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3028 char nodeName[MAX_FILENAME];
3029 char name[MAX_FILENAME+96];
3031 ChangeExtension(node.name, "c", nodeName);
3032 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3033 projectCompileItem =
3035 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3037 bool NotifySelect(MenuItem selection, Modifiers mods)
3041 bool isCObject = false;
3042 bool isExcluded = false;
3043 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3047 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3050 List<ProjectNode> nodes { };
3052 projectView.Compile(node.project, nodes, normal, isCObject ? cObject : normal);
3060 projectMenu.AddDynamic(projectCompileItem, ide, false);
3066 caps = ovr = num = null;
3071 bool OnClose(bool parentClosing)
3073 //return !projectView.buildInProgress;
3074 if(projectView && projectView.buildInProgress)
3076 if(DontTerminateDebugSession($"Close IDE"))
3078 if(findInFilesDialog)
3079 findInFilesDialog.SearchStop();
3082 workspace.timer.Stop();
3085 ideMainFrame.Destroy(0);
3092 bool passThrough = false;
3093 bool debugWorkDir = false;
3094 char * passDebugWorkDir = null;
3095 bool openAsText = false;
3096 DynamicString passArgs { };
3099 for(c = 1; c<app.argc; c++)
3103 const char * arg = app.argv[c];
3104 char * buf = new char[strlen(arg)*2+1];
3106 passArgs.concat(" ");
3108 passArgs.concat(buf);
3111 else if(debugWorkDir)
3113 passDebugWorkDir = CopyString(app.argv[c]);
3114 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3115 debugWorkDir = false;
3117 else if(!strcmp(app.argv[c], "-t"))
3119 else if(!strcmp(app.argv[c], "-no-parsing"))
3120 ide.noParsing = true;
3121 else if(!strcmp(app.argv[c], "-debug-start"))
3122 ide.debugStart = true;
3123 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3124 debugWorkDir = true;
3125 else if(!strcmp(app.argv[c], "-@"))
3129 char fullPath[MAX_LOCATION];
3130 char parentPath[MAX_LOCATION];
3131 char ext[MAX_EXTENSION];
3133 FileAttribs dirAttribs;
3134 GetWorkingDir(fullPath, MAX_LOCATION);
3135 PathCat(fullPath, app.argv[c]);
3136 StripLastDirectory(fullPath, parentPath);
3137 GetExtension(app.argv[c], ext);
3138 isProject = !openAsText && !strcmpi(ext, "epj");
3140 if(isProject && c > 1 + (ide.debugStart ? 1 : 0)) continue;
3142 // Create directory for projects (only)
3143 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3145 if(isProject && !FileExists(fullPath))
3147 char name[MAX_LOCATION];
3148 NewProjectDialog newProjectDialog;
3152 projectView.visible = false;
3153 if(!projectView.Destroy(0))
3157 newProjectDialog = { master = this };
3159 strcpy(name, app.argv[c]);
3160 StripExtension(name);
3161 GetLastDirectory(name, name);
3162 newProjectDialog.projectName.contents = name;
3163 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3164 newProjectDialog.locationEditBox.path = parentPath;
3165 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3167 incref newProjectDialog;
3168 newProjectDialog.Modal();
3171 ideConfig.recentWorkspaces.addRecent(CopyString(projectView.fileName));
3172 ide.updateRecentMenus();
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 UpdateToolBarActiveConfigs(false);
3194 UpdateToolBarActiveCompilers();
3201 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3204 projectView.visible = false;
3205 projectView.Destroy(0);
3208 #ifdef GDB_DEBUG_GUI
3209 gdbDialog.Destroy(0);
3214 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3218 char * oldPaths[128];
3219 String oldList = new char[maxPathLen];
3220 Array<String> newExePaths { };
3221 //Map<String, bool> exePathExists { };
3223 #if defined(__unix__) || defined(__APPLE__)
3224 Array<String> newLibPaths { };
3225 Map<String, bool> libPathExists { };
3230 for(prj : workspace.projects)
3232 DirExpression targetDirExp;
3234 // SKIP FIRST PROJECT...
3235 if(prj == workspace.projects.firstIterator.data) continue;
3237 // NOTE: Right now the additional project config dir will be
3238 // obtained when the debugger is started, so toggling it
3239 // while building will change which library gets used.
3240 // To go with the initial state, e.g. when F5 was pressed,
3241 // we nould need to keep a list of all project's active
3242 // config upon startup.
3243 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3245 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3249 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3250 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3254 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3255 if(cfg.targetType == sharedLibrary && cfg.debug)
3259 if(targetDirExp.dir)
3261 char buffer[MAX_LOCATION];
3262 #if defined(__WIN32__)
3263 Array<String> paths = newExePaths;
3265 Array<String> paths = newLibPaths;
3267 GetSystemPathBuffer(buffer, prj.topNode.path);
3268 PathCat(buffer, targetDirExp.dir);
3271 if(!fstrcmp(p, buffer))
3278 paths.Add(CopyString(buffer));
3280 delete targetDirExp;
3284 for(item : compiler.executableDirs)
3286 DirExpression dirExpr { };
3287 dirExpr.Evaluate(item, null, compiler, null, 0);
3290 for(p : newExePaths)
3292 if(!fstrcmp(p, dirExpr.dir))
3299 newExePaths.Add(CopySystemPath(dirExpr.dir));
3303 GetEnvironment("PATH", oldList, maxPathLen);
3305 printf("Old value of PATH: %s\n", oldList);
3307 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3308 for(c = 0; c < count; c++)
3311 for(p : newExePaths)
3313 if(!fstrcmp(p, oldPaths[c]))
3320 newExePaths.Add(CopySystemPath(oldPaths[c]));
3324 for(path : newExePaths)
3325 len += strlen(path) + 1;
3326 newList = new char[len + 1];
3328 for(path : newExePaths)
3330 strcat(newList, path);
3331 strcat(newList, pathListSep);
3333 newList[len - 1] = '\0';
3334 SetEnvironment("PATH", newList);
3336 printf("New value of PATH: %s\n", newList);
3343 #if defined(__unix__) || defined(__APPLE__)
3345 for(item : compiler.libraryDirs)
3347 if(!libPathExists[item]) // fstrcmp should be used
3349 String s = CopyString(item);
3351 libPathExists[s] = true;
3355 #if defined(__APPLE__)
3356 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3358 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3361 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3363 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3364 for(c = 0; c < count; c++)
3366 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3368 String s = CopyString(oldPaths[c]);
3370 libPathExists[s] = true;
3375 for(path : newLibPaths)
3376 len += strlen(path) + 1;
3377 newList = new char[len + 1];
3379 for(path : newLibPaths)
3381 strcat(newList, path);
3382 strcat(newList, pathListSep);
3384 newList[len - 1] = '\0';
3385 #if defined(__APPLE__)
3386 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3388 SetEnvironment("LD_LIBRARY_PATH", newList);
3391 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3397 delete libPathExists;
3400 if(compiler.distccEnabled && compiler.distccHosts)
3401 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3406 void DestroyTemporaryProjectDir()
3408 if(tmpPrjDir && tmpPrjDir[0])
3410 if(FileExists(tmpPrjDir).isDirectory)
3411 DestroyDir(tmpPrjDir);
3412 property::tmpPrjDir = null;
3418 // Graphics Driver Menu
3421 app.currentSkin.selectionColor = selectionColor;
3422 app.currentSkin.selectionText = selectionText;
3426 driverItems = new MenuItem[app.numDrivers];
3427 for(c = 0; c < app.numDrivers; c++)
3429 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3430 driverItems[c].id = c;
3431 driverItems[c].isRadio = true;
3434 driverItems = new MenuItem[2];
3435 #if defined(__unix__)
3436 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3437 driverItems[0].id = 0;
3438 driverItems[0].isRadio = true;
3440 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3441 driverItems[0].id = 0;
3442 driverItems[0].isRadio = true;
3444 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3445 driverItems[1].id = 1;
3446 driverItems[1].isRadio = true;
3448 /* skinItems = new MenuItem[app.numSkins];
3449 for(c = 0; c < app.numSkins; c++)
3451 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3452 skinItems[c].id = c;
3453 skinItems[c].isRadio = true;
3456 ideFileDialog.master = this;
3457 ideProjectFileDialog.master = this;
3459 //SetDriverAndSkin();
3463 void updateRecentMenus()
3465 updateRecentFilesMenu();
3466 updateRecentProjectsMenu();
3469 void updateRecentFilesMenu()
3472 char * itemPath = new char[MAX_LOCATION];
3473 char * itemName = new char[MAX_LOCATION+4];
3474 Workspace ws = workspace;
3475 RecentPaths recentFiles = ws ? ws.recentFiles : ideConfig.recentFiles;
3476 recentFilesMenu.Clear();
3477 for(recent : recentFiles)
3479 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3480 MakeSystemPath(itemPath);
3481 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3482 recentFilesMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3489 void updateRecentProjectsMenu()
3492 char * itemPath = new char[MAX_LOCATION];
3493 char * itemName = new char[MAX_LOCATION+4];
3494 recentProjectsMenu.Clear();
3495 for(recent : ideConfig.recentWorkspaces)
3497 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3498 MakeSystemPath(itemPath);
3499 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3500 recentProjectsMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3511 delete languageItems;
3515 documentor.Puts("Quit\n");
3522 void DestroyDir(char * path)
3524 RecursiveDeleteFolderFSI fsi { };
3529 #if defined(__WIN32__)
3530 define sdkDirName = "Ecere SDK";
3532 define sdkDirName = "ecere";
3535 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3538 char * v = new char[maxPathLen];
3542 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3543 StripLastDirectory(path, path);
3544 PathCat(path, subDir);
3545 if(name) PathCat(path, name);
3546 if(FileExists(path) & attribs) found = true;
3548 #if defined(__WIN32__)
3551 for(s : [ "ECERE_SDK_SRC", "AppData", "ALLUSERSPROFILE", "USERPROFILE", "HOMEPATH", "ProgramData", "ProgramFiles", "ProgramFiles(x86)", "SystemDrive" ])
3553 GetEnvironment(s, v, maxPathLen);
3556 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3557 if(!strcmp(s, "SystemDrive"))
3558 PathCat(path, "Program Files");
3559 if(strcmp(s, "ECERE_SDK_SRC"))
3560 PathCat(path, sdkDirName);
3561 PathCat(path, subDir);
3562 if(name) PathCat(path, name);
3563 if(FileExists(path) & attribs)
3578 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3579 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3582 p = new char[MAX_LOCATION];
3584 strcat(p, "/usr/share");
3588 for(c=0; c<numTokens; c++)
3590 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3591 PathCat(path, sdkDirName);
3592 PathCat(path, subDir);
3594 PathCat(path, name);
3595 if(FileExists(path) & attribs)
3608 void FindAndShellOpenInstalledFolder(const char * name)
3610 char path[MAX_LOCATION];
3611 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3615 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3617 char path[MAX_LOCATION];
3618 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3622 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3624 bool preserveRootFolder;
3626 void OutFolder(const char * folderPath, bool isRoot)
3628 if(!(preserveRootFolder && isRoot))
3629 RemoveDir(folderPath);
3632 bool OnFile(const char * filePath)
3634 DeleteFile(filePath);
3639 class IDEApp : GuiApplication
3641 //driver = "Win32Console";
3642 // driver = "OpenGL";
3646 TempFile includeFile { };
3651 char ext[MAX_EXTENSION];
3652 SetLoggingMode(stdOut, null);
3653 //SetLoggingMode(debug, null);
3655 settingsContainer.Load();
3657 if(ideSettings.language)
3659 const String language = GetLanguageString();
3660 if(ideSettings.language.OnCompare(language))
3662 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3667 ideConfig.compilers.read();
3668 ideConfig.recentFiles.read();
3669 ideConfig.recentWorkspaces.read();
3671 // First count files arg to decide whether to maximize
3673 bool passThrough = false, debugWorkDir = false;
3676 for(c = 1; c<app.argc; c++)
3679 else if(debugWorkDir)
3680 debugWorkDir = false;
3681 else if(!strcmp(app.argv[c], "-t"));
3682 else if(!strcmp(app.argv[c], "-no-parsing"));
3683 else if(!strcmp(app.argv[c], "-debug-start"));
3684 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3685 debugWorkDir = true;
3686 else if(!strcmp(app.argv[c], "-@"))
3693 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3695 app.driver = "OpenGL";
3696 ide.driverItems[1].checked = true;
3700 #if defined(__unix__) || defined(__APPLE__)
3701 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3703 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3705 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3709 char model[MAX_LOCATION];
3710 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3712 ide.duck.modelFile = model;
3713 ide.duck.parent = ideMainFrame;
3716 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3717 ide.debugRubberDuck.disabled = false;
3721 desktop.caption = titleECEREIDE;
3724 for(c = 1; c<app.argc; c++)
3726 char fullPath[MAX_LOCATION];
3727 GetWorkingDir(fullPath, MAX_LOCATION);
3728 PathCat(fullPath, app.argv[c]);
3729 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3733 globalSettingsDialog.settingsContainer = settingsContainer;
3735 // Default to language specified by environment if no language selected
3736 if(!ideSettings.language)
3738 ideSettings.language = GetLanguageString();
3739 settingsContainer.Save();
3742 // Default to home directory if no directory yet set up
3743 if(!ideSettings.ideProjectFileDialogLocation[0])
3746 char location[MAX_LOCATION];
3747 char * home = getenv("HOME");
3748 char * homeDrive = getenv("HOMEDRIVE");
3749 char * homePath = getenv("HOMEPATH");
3750 char * userProfile = getenv("USERPROFILE");
3751 char * systemDrive = getenv("SystemDrive");
3752 if(home && FileExists(home).isDirectory)
3754 strcpy(location, home);
3757 if(!found && homeDrive && homePath)
3759 strcpy(location, homeDrive);
3760 PathCat(location, homePath);
3761 if(FileExists(location).isDirectory)
3764 if(!found && FileExists(userProfile).isDirectory)
3766 strcpy(location, userProfile);
3769 if(!found && FileExists(systemDrive).isDirectory)
3771 strcpy(location, systemDrive);
3776 ideSettings.ideProjectFileDialogLocation = location;
3777 if(!ideSettings.ideFileDialogLocation[0])
3778 ideSettings.ideFileDialogLocation = location;
3782 if(!LoadIncludeFile())
3783 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3785 // Create language menu
3787 String language = ideSettings.language;
3791 ide.languageItems = new MenuItem[languages.count];
3794 ide.languageItems[i] =
3796 ide.languageMenu, l.name;
3797 bitmap = { l.bitmap };
3801 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3803 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3805 // Re-select previous selected language if aborted
3806 String language = ideSettings.language;
3810 if(((!language || !language[0]) && i == 0) ||
3811 (language && !strcmpi(l.code, language)))
3813 ide.languageItems[i].checked = true;
3825 // Try to find country-specific language first
3831 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3833 ide.languageItems[i].checked = true;
3841 // Try generalizing locale
3842 if(!found && language)
3845 char genericLocale[256];
3847 strncpy(genericLocale, language, sizeof(genericLocale));
3848 genericLocale[sizeof(genericLocale)-1] = 0;
3850 under = strchr(genericLocale, '_');
3853 if(!strcmpi(genericLocale, "zh"))
3854 strcpy(genericLocale, "zh_CN");
3855 if(strcmp(genericLocale, language))
3859 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3861 ide.languageItems[i].checked = true;
3871 ide.languageItems[0].checked = true;
3873 MenuDivider { ide.languageMenu };
3876 ide.languageMenu, "Help Translate";
3878 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3880 ShellOpen("http://translations.launchpad.net/ecere");
3886 ideMainFrame.Create();
3887 if(app.argFilesCount > 1)
3888 ide.MenuWindowTileVert(null, 0);
3892 bool Cycle(bool idle)
3896 if(ide.documentor.Peek())
3899 ide.documentor.GetLine(line, sizeof(line));
3900 if(!strcmpi(line, "Exited"))
3902 ide.documentor.CloseInput();
3903 ide.documentor.CloseOutput();
3904 ide.documentor.Wait();
3905 delete ide.documentor;
3908 if(ide.documentor && ide.documentor.eof)
3910 ide.documentor.CloseInput();
3911 ide.documentor.CloseOutput();
3912 ide.documentor.Wait();
3913 delete ide.documentor;
3919 bool LoadIncludeFile()
3921 bool result = false;
3922 File include = FileOpen(":crossplatform.mk", read);
3925 File f = includeFile;
3928 for(; !include.Eof(); )
3931 int count = include.Read(buffer, 1, 4096);
3932 f.Write(buffer, 1, count);
3942 IDEMainFrame ideMainFrame { };
3944 define app = ((IDEApp)__thisModule);
3946 define titleECEREIDE = $"Ecere IDE (Debug)";
3948 define titleECEREIDE = $"Ecere IDE";