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 IDEConfigHolder ideConfig { };
64 FontResource panelFont { $"Courier New", 10 };
65 FontResource codeFont { $"Courier New", 10 };
67 IDESettings ideSettings;
69 IDESettingsContainer settingsContainer
71 dataOwner = &ideSettings;
72 dataClass = class(IDESettings);
74 void onLoadCompilerConfigs() { ide.UpdateCompilerConfigs(true); }
75 void onLoadRecentFiles() { ide.updateRecentFilesMenu(); }
76 void onLoadRecentProjects() { ide.updateRecentProjectsMenu(); }
77 void onLoad() { ide.ApplyColorScheme(colorScheme); ide.ApplyFont(ideSettings.codeEditorFont, ideSettings.codeEditorFontSize); }
80 define maxPathLen = 65 * MAX_LOCATION;
82 class PathBackup : struct
89 oldPath = new char[maxPathLen];
90 oldLDPath = new char[maxPathLen];
92 GetEnvironment("PATH", oldPath, maxPathLen);
93 #if defined(__APPLE__)
94 GetEnvironment("DYLD_LIBRARY_PATH", oldLDPath, maxPathLen);
96 GetEnvironment("LD_LIBRARY_PATH", oldLDPath, maxPathLen);
102 SetEnvironment("PATH", oldPath);
103 #if defined(__APPLE__)
104 SetEnvironment("DYLD_LIBRARY_PATH", oldLDPath);
106 SetEnvironment("LD_LIBRARY_PATH", oldLDPath);
113 enum OpenCreateIfFails { no, yes, something, whatever };
114 enum OpenMethod { normal, add };
116 static Array<FileFilter> fileFilters
118 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
119 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
120 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
121 { $"Text files (*.txt, *.text, *.nfo, *.info)", "txt, text, nfo, info" },
122 { $"Web files (*.html, *.htm, *.xhtml, *.css, *.php, *.js, *.jsi, *.rb, *.xml)", "html, htm, xhtml, css, php, js, jsi, rb, xml" },
123 { $"Image Files (*.jpg, *.jpeg, *.bmp, *.pcx, *.png, *.gif)", "jpg, jpeg, bmp, pcx, png, gif" },
124 { $"3D Studio Model Files (*.3ds)", "3ds" },
125 { $"All files", null }
128 static Array<FileType> fileTypes
130 { $"Based on extension", null },
133 { $"3D Studio Model", "3ds" }
136 static Array<FileFilter> projectFilters
138 { $"Project Files (*.epj)", ProjectExtension }
141 static Array<FileType> projectTypes
143 { $"Project File", ProjectExtension }
146 static Array<FileFilter> findInFilesFileFilters
148 { $"eC Files (*.ec, *.eh)", "ec, eh" },
149 { $"C/C++/eC Files (*.ec, *.eh, *.c, *.cpp, *.cc, *.cxx, *.h, *.hpp, *.hh, *.hxx)", "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx" },
150 { $"Header Files for eC/C/C++ (*.eh, *.h, *.hpp, *.hh, *.hxx)", "eh, h, hpp, hh, hxx" },
151 { $"C/C++/eC Source Files (*.ec, *.c, *.cpp, *.cc, *.cxx)", "ec, c, cpp, cc, cxx" },
152 { $"Text files (*.txt)", "txt" },
153 { $"All files", null }
156 FileDialog ideFileDialog
158 type = multiOpen, text = $"Open";
159 types = fileTypes.array, sizeTypes = fileTypes.count * sizeof(FileType), filters = fileFilters.array, sizeFilters = fileFilters.count * sizeof(FileFilter);
162 define openProjectFileDialogTitle = $"Open Project";
163 define addProjectFileDialogTitle = $"Open Additional Project";
164 FileDialog ideProjectFileDialog
167 types = projectTypes.array, sizeTypes = projectTypes.count * sizeof(FileType), filters = projectFilters.array, sizeFilters = projectFilters.count * sizeof(FileFilter);
170 GlobalSettingsDialog globalSettingsDialog
172 void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange)
174 switch(globalSettingsChange)
179 for(child = ide.firstChild; child; child = child.next)
181 if(child._class == class(CodeEditor))
183 CodeEditor codeEditor = (CodeEditor) child;
184 codeEditor.editBox.freeCaret = ideSettings.useFreeCaret;
185 // codeEditor.editBox.lineNumbers = ideSettings.showLineNumbers;
186 codeEditor.editBox.caretFollowsScrolling = ideSettings.caretFollowsScrolling;
187 codeEditor.OnPostCreate(); // Update editBox margin size
194 case compilerSettings:
196 ide.UpdateCompilerConfigs(true);
203 void DrawLineMarginIcon(Surface surface, BitmapResource resource, int line, int lineH, int scrollY, int boxH)
208 lineY = (line - 1) * lineH;
209 if(lineY + lineH > scrollY && lineY + lineH < scrollY + boxH)
211 Bitmap bitmap = resource.bitmap;
213 surface.Blit(bitmap, 0, lineY - scrollY + (lineH - bitmap.height) / 2 + 1, 0, 0, bitmap.width, bitmap.height);
218 #define IDEItem(x) (&((IDEWorkSpace)0).x)
220 class IDEToolbar : ToolBar
224 ToolButton buttonNewFile { this, toolTip = $"New file", menuItemPtr = IDEItem(fileNewItem) };
226 ToolButton buttonOpenFile { this, toolTip = $"Open file", menuItemPtr = IDEItem(fileOpenItem) };
228 // ToolButton buttonCloseFile { this, toolTip = $"Close file", menuItemPtr = IDEItem(fileCloseItem) };
230 ToolButton buttonSaveFile { this, toolTip = $"Save file", menuItemPtr = IDEItem(fileSaveItem) };
232 ToolButton buttonSaveAllFile { this, toolTip = $"Save all", menuItemPtr = IDEItem(fileSaveAllItem) };
234 ToolSeparator separator1 { this };
243 // ToolSeparator separator2 { this };
247 ToolButton buttonNewProject { this, toolTip = $"New project", menuItemPtr = IDEItem(projectNewItem) };
249 ToolButton buttonOpenProject { this, toolTip = $"Open project", menuItemPtr = IDEItem(projectOpenItem) };
250 // Add project to workspace
251 ToolButton buttonAddProject { this, toolTip = $"Add project to workspace", menuItemPtr = IDEItem(projectAddItem), disabled = true; };
253 // ToolButton buttonCloseProject { this, toolTip = $"Close project", menuItemPtr = IDEItem(projectCloseItem), disabled = true; };
255 ToolSeparator separator3 { this };
257 // Build/Execution options
259 ToolButton buttonBuild { this, toolTip = $"Build project", menuItemPtr = IDEItem(projectBuildItem), disabled = true; };
261 ToolButton buttonReLink { this, toolTip = $"Relink project", menuItemPtr = IDEItem(projectLinkItem), disabled = true; };
263 ToolButton buttonRebuild { this, toolTip = $"Rebuild project", menuItemPtr = IDEItem(projectRebuildItem), disabled = true; };
265 ToolButton buttonClean { this, toolTip = $"Clean project", menuItemPtr = IDEItem(projectCleanItem), disabled = true; };
267 // ToolButton buttonRealClean { this, toolTip = $"Real clean project", menuItemPtr = IDEItem(projectRealCleanItem), disabled = true; };
268 // Regenerate Makefile
269 ToolButton buttonRegenerateMakefile { this, toolTip = $"Regenerate Makefile", menuItemPtr = IDEItem(projectRegenerateItem), disabled = true; };
270 // Compile actual file
272 ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem), disabled = true; };
273 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
274 ToolButton buttonInstall { this, toolTip = $"Install", menuItemPtr = IDEItem(projectInstallItem), disabled = true; };
277 ToolSeparator separator4 { this };
281 ToolButton buttonDebugStartResume { this, toolTip = $"Start", menuItemPtr = IDEItem(debugStartResumeItem), disabled = true; };
283 ToolButton buttonDebugRestart { this, toolTip = $"Restart", menuItemPtr = IDEItem(debugRestartItem), disabled = true; };
285 ToolButton buttonDebugPause { this, toolTip = $"Break", menuItemPtr = IDEItem(debugBreakItem), disabled = true; };
287 ToolButton buttonDebugStop { this, toolTip = $"Stop", menuItemPtr = IDEItem(debugStopItem), disabled = true; };
289 //ToolButton buttonRun { this, toolTip = $"Run", menuItemPtr = IDEItem(projectRunItem) };
291 ToolButton buttonDebugStepInto { this, toolTip = $"Step Into", menuItemPtr = IDEItem(debugStepIntoItem), disabled = true; };
293 ToolButton buttonDebugStepOver { this, toolTip = $"Step Over", menuItemPtr = IDEItem(debugStepOverItem), disabled = true; };
295 ToolButton buttonDebugStepOut { this, toolTip = $"Step Out", menuItemPtr = IDEItem(debugStepOutItem), disabled = true; };
297 ToolButton buttonDebugSkipStepOver { this, toolTip = $"Step Over Skipping Breakpoints", menuItemPtr = IDEItem(debugSkipStepOverItem), disabled = true; };
299 ToolSeparator separator5 { this };
301 Window spacer5 { this, size = { 4 } };
305 this, toolTip = $"Active Configuration(s)", size = { 160 }, disabled = true;
306 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
309 ide.workspace.SelectActiveConfig(row.string);
314 Window spacer6 { this, size = { 4 } };
316 DropBox activeCompiler
318 this, toolTip = $"Active Compiler", size = { 160 }, disabled = true;
319 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
321 if(ide.workspace && ide.projectView && row && strcmp(row.string, ide.workspace.activeCompiler))
323 bool silent = ide.projectView.buildInProgress == none ? false : true;
324 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(row.string);
325 ide.workspace.activeCompiler = row.string;
326 ide.projectView.ShowOutputBuildLog(!silent);
328 ide.projectView.DisplayCompiler(compiler, false);
329 for(prj : ide.workspace.projects)
330 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
332 ide.workspace.Save();
338 DropBox activeBitDepth
340 this, toolTip = $"Active Bit Length", size = { 60 }, disabled = true;
341 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
343 if(ide.workspace && ide.projectView && row)
345 bool silent = ide.projectView.buildInProgress == none ? false : true;
346 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler);
347 ide.workspace.bitDepth = (int)row.tag;
348 ide.projectView.ShowOutputBuildLog(!silent);
350 ide.projectView.DisplayCompiler(compiler, false);
351 for(prj : ide.workspace.projects)
352 ide.projectView.ProjectPrepareCompiler(prj, compiler, silent);
354 ide.workspace.Save();
360 Window spacer7 { this, size = { 4 } };
365 row = activeBitDepth.AddString("Auto");
367 activeBitDepth.AddString("32 bit").tag = 32;
368 activeBitDepth.AddString("64 bit").tag = 64;
369 activeBitDepth.currentRow = row;
373 class IDEMainFrame : Window
375 background = formColor;
376 borderStyle = sizable;
380 minClientSize = { 600, 300 };
382 icon = { ":icon.png" };
383 text = titleECEREIDE;
387 anchor = { top = 0, right = 0, bottom = 0 };
390 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
397 isActiveClient = true;
399 direction = vertical;
400 background = formColor;
401 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
409 ((IDEWorkSpace)master).toolBar = null;
412 IDEWorkSpace ideWorkSpace { stack, this, toolBar = toolBar };
415 define ide = ideMainFrame.ideWorkSpace;
417 class IDEWorkSpace : Window
419 background = Color { 85, 85, 85 };
422 hasVertScroll = true;
423 hasHorzScroll = true;
425 isActiveClient = true;
426 anchor = { left = 0, top = 0, right = 0, bottom = 0 };
430 MenuItem * driverItems, * skinItems, * languageItems;
431 StatusField pos { width = 150 };
432 StatusField ovr, caps, num;
435 BitmapResource back { ":ecereBack.jpg", window = this };
436 BitmapResource bmpBp { ":codeMarks/breakpoint.png", window = this };
437 BitmapResource bmpBpDisabled { ":codeMarks/breakpointDisabled.png", window = this };
438 BitmapResource bmpBpHalf { ":codeMarks/breakpointHalf.png", window = this };
439 BitmapResource bmpBpHalfDisabled { ":codeMarks/breakpointHalfDisabled.png", window = this };
440 BitmapResource bmpCursor { ":codeMarks/cursor.png", window = this };
441 BitmapResource bmpCursorError { ":codeMarks/cursorError.png", window = this };
442 BitmapResource bmpTopFrame { ":codeMarks/topFrame.png", window = this };
443 BitmapResource bmpTopFrameError { ":codeMarks/topFrameError.png", window = this };
444 BitmapResource bmpTopFrameHalf { ":codeMarks/topFrameHalf.png", window = this };
445 BitmapResource bmpTopFrameHalfError { ":codeMarks/topFrameHalfError.png", window = this };
447 BuildOutputMode rightClickMenuBuildOutputMode;
449 Debugger debugger { };
451 void ApplyFont(const String faceName, float size)
453 panelFont.faceName = faceName;
454 panelFont.size = size;
456 codeFont.faceName = faceName;
457 codeFont.size = size;
461 for(ce = (CodeEditor)firstChild; ce; ce = (CodeEditor)ce.next)
462 if(ce._class == class(CodeEditor))
465 font = { codeFont.faceName, codeFont.size, codeFont.bold, codeFont.italic };
469 ce.editBox.font = font;
474 threadsView.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
475 callStackView.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
476 outputView.buildBox.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
477 outputView.debugBox.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
478 outputView.findBox.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
479 #ifdef GDB_DEBUG_OUTPUT
480 outputView.gdbBox.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
485 gdbDialog.tree.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
486 gdbDialog.output.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
491 void ApplyColorScheme(IDEColorScheme cs)
497 for(ce = (CodeEditor)firstChild; ce; ce = (CodeEditor)ce.next)
498 if(ce._class == class(CodeEditor))
500 EditBox eb = ce.editBox;
501 ce.background = cs.marginColor;
502 eb.selectionColor = cs.selectionColor;
503 eb.selectionText = cs.selectionText;
504 eb.background = cs.codeEditorBG;
505 eb.foreground = cs.codeEditorFG;
506 eb.syntaxColorScheme = cs.syntaxColors;
511 projectView.fileList.background = cs.projectViewBackground;
512 projectView.fileList.foreground = cs.projectViewText;
513 projectView.fileList.selectionColor = cs.selectionColor;
514 projectView.fileList.selectionText = cs.selectionText;
517 sheet.properties.background = cs.viewsBackground;
518 sheet.properties.foreground = cs.viewsText;
519 sheet.properties.selectionText = cs.sheetSelectionText;
520 sheet.properties.selectionColor = cs.sheetSelectionColor;
521 sheet.methods.background = cs.viewsBackground;
522 sheet.methods.foreground = cs.viewsText;
524 threadsView.editBox.background = cs.viewsBackground;
525 threadsView.editBox.foreground = cs.viewsText;
526 threadsView.editBox.selectionColor = cs.selectionColor;
527 threadsView.editBox.selectionText = cs.selectionText;
529 callStackView.editBox.background = cs.viewsBackground;
530 callStackView.editBox.foreground = cs.viewsText;
531 callStackView.editBox.selectionColor = cs.selectionColor;
532 callStackView.editBox.selectionText = cs.selectionText;
534 watchesView.listBox.background = cs.viewsBackground;
535 watchesView.listBox.foreground = cs.viewsText;
536 watchesView.listBox.selectionColor = cs.selectionColor;
537 watchesView.listBox.selectionText = cs.selectionText;
539 breakpointsView.listBox.background = cs.viewsBackground;
540 breakpointsView.listBox.foreground = cs.viewsText;
541 breakpointsView.listBox.selectionColor = cs.selectionColor;
542 breakpointsView.listBox.selectionText = cs.selectionText;
544 outputView.buildBox.background = cs.outputBackground;
545 outputView.buildBox.foreground = cs.outputText;
546 outputView.buildBox.selectionColor = cs.selectionColor;
547 outputView.buildBox.selectionText = cs.selectionText;
549 outputView.debugBox.background = cs.outputBackground;
550 outputView.debugBox.foreground = cs.outputText;
551 outputView.debugBox.selectionColor = cs.selectionColor;
552 outputView.debugBox.selectionText = cs.selectionText;
554 outputView.findBox.background = cs.outputBackground;
555 outputView.findBox.foreground = cs.outputText;
556 outputView.findBox.selectionColor = cs.selectionColor;
557 outputView.findBox.selectionText = cs.selectionText;
560 ProjectView projectView;
562 OutputView outputView
566 void OnGotoError(const char * line, bool noParsing)
568 CompilerConfig compiler = ide.workspace ? ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler) : null;
569 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
570 ide.GoToError(line, noParsing, objectFileExt);
574 void OnCodeLocationParseAndGoTo(const char * line)
576 CompilerConfig compiler = ide.workspace ? ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler) : null;
577 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
578 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir, objectFileExt);
582 bool OnKeyDown(Key key, unichar ch)
587 if(activeBox != findBox || !ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
588 ide.ShowCodeEditor();
592 OutputView::OnKeyDown(key, ch);
599 bool OnClose(bool parentClosing)
603 ide.RepositionWindows(false);
604 return parentClosing;
608 CallStackView callStackView
610 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
612 void OnSelectFrame(int frameIndex)
614 ide.debugger.GoToStackFrameLine(frameIndex, true, true);
616 ide.debugger.SelectFrame(frameIndex);
619 void OnToggleBreakpoint()
621 Debugger debugger = ide.debugger;
622 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
624 int line = debugger.activeFrame.line;
625 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line);
628 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
629 if(codeEditor) { codeEditor.Update(null); Activate(); }
634 bool OnKeyDown(Key key, unichar ch)
638 case escape: ide.ShowCodeEditor(); break;
643 bool OnClose(bool parentClosing)
647 ide.RepositionWindows(false);
648 return parentClosing;
651 void OnRedraw(Surface surface)
653 Debugger debugger = ide.debugger;
654 Frame activeFrame = debugger.activeFrame;
658 int lineCursor, lineTopFrame;
659 int lineH, scrollY, boxH;
661 Breakpoint bp = null;
664 scrollY = editBox.scroll.y;
665 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
666 //activeThread = debugger.activeThread;
667 //hitThread = debugger.hitThread;
668 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
670 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
671 if(activeFrame.absoluteFile)
673 for(i : ide.workspace.breakpoints; i.type == user)
675 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
676 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
677 activeFrame.line == i.line)
685 DrawLineMarginIcon(surface,
686 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
687 lineCursor /*1*/, lineH, scrollY, boxH);
689 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
690 DrawLineMarginIcon(surface,
691 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
692 1, lineH, scrollY, boxH);
694 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
695 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
696 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
698 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
699 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
701 if(editBox.horzScroll && editBox.horzScroll.visible)
703 surface.SetBackground(control);
704 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
709 WatchesView watchesView { parent = this };
710 ThreadsView threadsView
712 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
714 bool OnKeyDown(Key key, unichar ch)
718 case escape: ide.ShowCodeEditor(); break;
723 bool OnClose(bool parentClosing)
727 ide.RepositionWindows(false);
728 return parentClosing;
731 void OnSelectThread(int threadId)
734 ide.debugger.SelectThread(threadId);
737 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
740 Debugger debugger = ide.debugger;
741 *activeThread = debugger.activeThread;
742 *hitThread = debugger.hitThread;
743 *signalThread = debugger.signalThread;
748 BreakpointsView breakpointsView { parent = this };
750 ToolBox toolBox { parent = this, visible = false };
751 Sheet sheet { parent = this, visible = false };
754 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
756 Menu fileMenu { menu, $"File", f, hasMargin = true };
759 fileMenu, $"New", n, ctrlN;
760 bitmap = { ":actions/docNew.png" };
761 bool NotifySelect(MenuItem selection, Modifiers mods)
763 Window currentDoc = activeClient;
764 bool maximizeDoc = ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
765 Window document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, false);
766 RepositionWindows(false);
767 document.NotifySaved = DocumentSaved;
771 MenuItem fileOpenItem
773 fileMenu, $"Open...", o, ctrlO;
774 bitmap = { ":actions/docOpen.png" };
775 bool NotifySelect(MenuItem selection, Modifiers mods)
777 if(!projectView && ideSettings.ideFileDialogLocation)
778 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
781 if(ideFileDialog.Modal() == ok)
783 bool gotWhatWeWant = false;
785 int numSelections = ideFileDialog.numSelections;
786 const char * const * multiFilePaths = ideFileDialog.multiFilePaths;
788 for(c = 0; c < numSelections; c++)
790 if(OpenFile(multiFilePaths[c], false, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
791 gotWhatWeWant = true;
794 MessageBox { type = yesNo, master = this, text = $"Error opening file",
795 contents = $"Open a different file?" }.Modal() == no)
797 if(!projectView && gotWhatWeWant)
798 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
799 ide.RepositionWindows(false);
809 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
810 MenuDivider { fileMenu };
811 MenuItem fileSaveItem
813 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
815 // For the toolbar button; clients can still override that for the menu item
816 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
818 Window w = activeClient;
820 w.MenuFileSave(null, 0);
824 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
825 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
826 MenuDivider { fileMenu };
829 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
830 bool NotifySelect(MenuItem selection, Modifiers mods)
832 findInFilesDialog.replaceMode = false;
833 findInFilesDialog.Show();
837 MenuItem replaceInFiles
839 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
840 bool NotifySelect(MenuItem selection, Modifiers mods)
842 findInFilesDialog.replaceMode = true;
843 findInFilesDialog.Show();
847 MenuDivider { fileMenu };
848 MenuItem globalSettingsItem
850 fileMenu, $"Global Settings...", g;
851 bool NotifySelect(MenuItem selection, Modifiers mods)
853 // Reload configs here until we setup a configs directory monitor
854 ideConfig.compilers.read(settingsContainer);
856 globalSettingsDialog.master = this;
857 if(ide.workspace && ide.workspace.activeCompiler)
858 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.activeCompiler;
859 else if(ideSettings.defaultCompiler)
860 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
861 globalSettingsDialog.Modal();
865 MenuDivider { fileMenu };
866 Menu recentFilesMenu { fileMenu, $"Recent Files", r };
867 Menu recentProjectsMenu { fileMenu, $"Recent Projects", p };
868 MenuDivider { fileMenu };
871 fileMenu, $"Exit", x, altF4;
873 bool NotifySelect(MenuItem selection, Modifiers mods)
875 ideMainFrame.Destroy(0);
880 bool FileRecentFile(MenuItem selection, Modifiers mods)
883 RecentPaths recentFiles = workspace ? workspace.recentFiles : ideConfig.recentFiles;
884 for(file : recentFiles)
886 if(id == selection.id)
889 char extension[MAX_EXTENSION] = "";
890 GetExtension(file, extension);
891 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
892 if(mods.ctrl && !mods.shift)
894 char * command = PrintString("ecere-ide ", isProjectFile ? "-t " : "", file);
900 OpenFile(file, false, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
901 ide.RepositionWindows(false);
910 bool FileRecentProject(MenuItem selection, Modifiers mods)
913 for(file : ideConfig.recentWorkspaces)
915 if(id == selection.id)
917 if(mods.ctrl && !mods.shift)
919 char * command = PrintString("ecere-ide ", file);
924 OpenFile(file, false, true, (mods.ctrl && mods.shift) ? "txt" : null, no, normal, mods.ctrl && mods.shift);
932 MenuPlacement editMenu { menu, $"Edit", e };
934 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
935 MenuItem projectNewItem
937 projectMenu, $"New...", n, Key { n, true, true };
938 bitmap = { ":actions/projNew.png" };
939 bool NotifySelect(MenuItem selection, Modifiers mods)
941 if(!DontTerminateDebugSession($"New Project"))
944 NewProjectDialog newProjectDialog { master = this };
945 incref newProjectDialog;
946 result = newProjectDialog.Modal();
951 newProjectDialog.CreateNewProject();
954 ideConfig.recentWorkspaces.addRecent(projectView.fileName);
955 ideConfig.recentWorkspaces.write(settingsContainer);
956 ide.updateRecentProjectsMenu();
960 delete newProjectDialog;
965 MenuItem projectOpenItem
967 projectMenu, $"Open...", o, Key { o, true, true };
968 bitmap = { ":actions/projOpen.png" };
969 bool NotifySelect(MenuItem selection, Modifiers mods)
971 if(ideSettings.ideProjectFileDialogLocation)
972 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
974 ideProjectFileDialog.text = openProjectFileDialogTitle;
975 if(ideProjectFileDialog.Modal() == ok)
977 OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
978 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
983 MenuItem projectQuickItem
985 projectMenu, $"Quick...", q, f7, disabled = true;
986 bool NotifySelect(MenuItem selection, Modifiers mods)
989 QuickProjectDialog { this }.Modal();
993 MenuItem projectAddItem
995 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
996 bitmap = { ":actions/projAdd.png" };
998 bool NotifySelect(MenuItem selection, Modifiers mods)
1000 if(ideSettings.ideProjectFileDialogLocation)
1001 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
1003 ideProjectFileDialog.text = addProjectFileDialogTitle;
1006 if(ideProjectFileDialog.Modal() == ok)
1008 if(OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
1010 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
1011 contents = $"Add a different project?" }.Modal() == no)
1022 MenuItem projectCloseItem
1024 projectMenu, $"Close", c, disabled = true;
1025 bool NotifySelect(MenuItem selection, Modifiers mods)
1029 if(!ide.DontTerminateDebugSession($"Project Close"))
1035 MenuDivider { projectMenu };
1036 MenuItem projectSettingsItem
1038 projectMenu, $"Settings...", s, altF7, disabled = true;
1039 bool NotifySelect(MenuItem selection, Modifiers mods)
1041 projectView.MenuSettings(projectView.active ? selection : null, mods);
1045 MenuDivider { projectMenu };
1046 MenuItem projectBrowseFolderItem
1048 projectMenu, $"Browse Project Folder", p, disabled = true;
1049 bool NotifySelect(MenuItem selection, Modifiers mods)
1052 projectView.MenuBrowseFolder(null, mods);
1056 MenuDivider { projectMenu };
1057 MenuItem projectRunItem
1059 projectMenu, $"Run", r, ctrlF5, disabled = true;
1060 bitmap = { ":actions/run.png" };
1061 bool NotifySelect(MenuItem selection, Modifiers mods)
1064 projectView.Run(null, mods);
1068 MenuItem projectBuildItem
1070 projectMenu, $"Build", b, f7, disabled = true;
1071 bitmap = { ":actions/build.png" };
1072 bool NotifySelect(MenuItem selection, Modifiers mods)
1076 if(projectView.buildInProgress == none)
1077 projectView.ProjectBuild(projectView.active ? selection : null, mods);
1079 projectView.stopBuild = true;
1084 MenuItem projectLinkItem
1086 projectMenu, $"Relink", l, disabled = true;
1087 bitmap = { ":actions/relink.png" };
1088 bool NotifySelect(MenuItem selection, Modifiers mods)
1091 projectView.ProjectLink(projectView.active ? selection : null, mods);
1095 MenuItem projectRebuildItem
1097 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
1098 bitmap = { ":actions/rebuild.png" };
1099 bool NotifySelect(MenuItem selection, Modifiers mods)
1102 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
1106 MenuItem projectCleanTargetItem
1108 projectMenu, $"Clean Target", g, disabled = true;
1109 bitmap = { ":actions/clean.png" };
1110 bool NotifySelect(MenuItem selection, Modifiers mods)
1115 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
1120 MenuItem projectCleanItem
1122 projectMenu, $"Clean", e, disabled = true;
1123 bitmap = { ":actions/clean.png" };
1124 bool NotifySelect(MenuItem selection, Modifiers mods)
1129 projectView.ProjectClean(projectView.active ? selection : null, mods);
1134 MenuItem projectRealCleanItem
1136 projectMenu, $"Real Clean", disabled = true;
1137 bitmap = { ":actions/clean.png" };
1138 bool NotifySelect(MenuItem selection, Modifiers mods)
1143 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1148 MenuItem projectRegenerateItem
1150 projectMenu, $"Regenerate Makefile", m, disabled = true;
1151 bitmap = { ":actions/regMakefile.png" };
1152 bool NotifySelect(MenuItem selection, Modifiers mods)
1155 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1159 MenuItem projectInstallItem
1161 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
1162 projectMenu, $"Install", t, disabled = true;
1164 bitmap = { ":status/software-update-available.png" };
1165 bool NotifySelect(MenuItem selection, Modifiers mods)
1168 projectView.ProjectInstall(projectView.active ? selection : null, mods);
1172 MenuItem projectCompileItem;
1173 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1174 MenuItem debugStartResumeItem
1176 debugMenu, $"Start", s, f5, disabled = true;
1177 bitmap = { ":actions/debug.png" };
1178 NotifySelect = MenuDebugStart;
1180 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1184 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1185 if(!projectView.DebugStart())
1186 debugStartResumeItem.disabled = false; // same exception
1190 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1193 projectView.DebugResume();
1196 MenuItem debugRestartItem
1198 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1199 bitmap = { ":actions/restart.png" };
1200 bool NotifySelect(MenuItem selection, Modifiers mods)
1203 projectView.DebugRestart();
1207 MenuItem debugBreakItem
1209 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1210 bitmap = { ":actions/pause.png" };
1211 bool NotifySelect(MenuItem selection, Modifiers mods)
1213 if(projectView && projectView.buildInProgress != none)
1216 projectView.DebugBreak();
1220 MenuItem debugStopItem
1222 debugMenu, $"Stop", p, shiftF5, disabled = true;
1223 bitmap = { ":actions/stopDebug.png" };
1224 bool NotifySelect(MenuItem selection, Modifiers mods)
1227 projectView.DebugStop();
1231 MenuDivider { debugMenu };
1235 // nonClient = true,
1242 anchor = { right = 0, bottom = 0 },
1244 isActiveClient = false,
1246 clickThrough = true,
1247 size = { 500, 500 };
1249 bool OnLoadGraphics()
1251 ModelView::OnLoadGraphics();
1252 camera.position.z /= 1.3;
1253 camera.orientation = Euler { yaw = 280, pitch = 20 };
1259 bool OnRightButtonDown(int x, int y, Modifiers mods)
1261 if(!displaySystem.flags.flipping) return true;
1262 MenuWindowMove(null, 0);
1266 bool OnRightButtonUp(int x, int y, Modifiers mods)
1268 position = position;
1273 MenuItem debugRubberDuck
1275 debugMenu, $"Rubber Duck", checkable = true, disabled = true;
1276 bool NotifySelect(MenuItem selection, Modifiers mods)
1278 if(selection.checked)
1286 MenuDivider { debugMenu };
1287 MenuItem debugUseValgrindItem
1289 debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
1290 bool NotifySelect(MenuItem selection, Modifiers mods)
1294 ide.workspace.useValgrind = selection.checked;
1295 ide.workspace.Save();
1297 ide.AdjustValgrindMenus();
1301 Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
1302 MenuItem debugValgrindNoLeakCheckItem { debugValgrindLeakCheckItem, $"No" , f, id = ValgrindLeakCheck::no , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1303 MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; };
1304 MenuItem debugValgrindYesLeakCheckItem { debugValgrindLeakCheckItem, $"Yes" , f, id = ValgrindLeakCheck::yes , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1305 MenuItem debugValgrindFullLeakCheckItem { debugValgrindLeakCheckItem, $"Full" , f, id = ValgrindLeakCheck::full , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1306 bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
1310 if(selection.checked)
1312 ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
1314 debugValgrindNoLeakCheckItem.checked = debugValgrindNoLeakCheckItem.id == vgLeakCheck;
1315 debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
1316 debugValgrindYesLeakCheckItem.checked = debugValgrindYesLeakCheckItem.id == vgLeakCheck;
1317 debugValgrindFullLeakCheckItem.checked = debugValgrindFullLeakCheckItem.id == vgLeakCheck;
1319 ide.workspace.vgLeakCheck = vgLeakCheck;
1320 ide.workspace.Save();
1323 selection.checked = true;
1327 Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
1328 MenuItem debugValgrindRSDefaultItem { debugValgrindRedzoneSizeItem, $"Default", f, id = -1, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; };
1329 MenuItem debugValgrindRS0Item { debugValgrindRedzoneSizeItem, "0" , f, id = 0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1330 MenuItem debugValgrindRS16Item { debugValgrindRedzoneSizeItem, "16" , f, id = 16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1331 MenuItem debugValgrindRS32Item { debugValgrindRedzoneSizeItem, "32" , f, id = 32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1332 MenuItem debugValgrindRS64Item { debugValgrindRedzoneSizeItem, "64" , f, id = 64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1333 MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, "128" , f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1334 MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, "256" , f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1335 MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, "512" , f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1336 bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
1340 if(selection.checked)
1342 int vgRedzoneSize = (int)selection.id;
1344 debugValgrindRSDefaultItem.checked = debugValgrindRSDefaultItem.id == vgRedzoneSize;
1345 debugValgrindRS0Item.checked = debugValgrindRS0Item.id == vgRedzoneSize;
1346 debugValgrindRS16Item.checked = debugValgrindRS16Item.id == vgRedzoneSize;
1347 debugValgrindRS32Item.checked = debugValgrindRS32Item.id == vgRedzoneSize;
1348 debugValgrindRS64Item.checked = debugValgrindRS64Item.id == vgRedzoneSize;
1349 debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
1350 debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
1351 debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
1353 ide.workspace.vgRedzoneSize = vgRedzoneSize;
1354 ide.workspace.Save();
1357 selection.checked = true;
1361 MenuItem debugValgrindTrackOriginsItem
1363 debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
1364 bool NotifySelect(MenuItem selection, Modifiers mods)
1368 ide.workspace.vgTrackOrigins = selection.checked;
1369 ide.workspace.Save();
1375 MenuDivider { debugMenu };
1376 MenuItem debugStepIntoItem
1378 debugMenu, $"Step Into", i, f11, disabled = true;
1379 bitmap = { ":actions/stepInto.png" };
1380 bool NotifySelect(MenuItem selection, Modifiers mods)
1382 if(projectView) projectView.DebugStepInto();
1386 MenuItem debugStepOverItem
1388 debugMenu, $"Step Over", v, f10, disabled = true;
1389 bitmap = { ":actions/stepOver.png" };
1390 bool NotifySelect(MenuItem selection, Modifiers mods)
1392 if(projectView) projectView.DebugStepOver(false);
1396 MenuItem debugSkipStepOverItem
1398 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1399 bitmap = { ":actions/stepOverSkipBreak.png" };
1400 bool NotifySelect(MenuItem selection, Modifiers mods)
1402 if(projectView) projectView.DebugStepOver(true);
1406 MenuItem debugStepOutItem
1408 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1409 bitmap = { ":actions/stepOut.png" };
1410 bool NotifySelect(MenuItem selection, Modifiers mods)
1412 if(projectView) projectView.DebugStepOut(false);
1416 MenuItem debugSkipStepOutItem
1418 debugMenu, $"Step Out Skipping Breakpoints", n, Key { f11, ctrl = true, shift = true }, disabled = true;
1419 bitmap = { ":actions/skipBreaks.png" };
1420 bool NotifySelect(MenuItem selection, Modifiers mods)
1422 if(projectView) projectView.DebugStepOut(true);
1427 MenuItem debugStepUntilItem
1429 debugMenu, $"Step Over Until Next Line", x, disabled = true;
1430 bool NotifySelect(MenuItem selection, Modifiers mods)
1432 if(projectView) projectView.DebugStepUntil(false);
1436 MenuItem debugSkipStepUntilItem
1438 debugMenu, $"Step Over Until Next Line Skipping Breakpoints", e, Key { f10, shift = true, alt = true }, disabled = true;
1439 bool NotifySelect(MenuItem selection, Modifiers mods)
1441 if(projectView) projectView.DebugStepUntil(true);
1446 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1447 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1448 MenuPlacement debugRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level", l };
1449 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", g };
1451 MenuPlacement debugBpRunToCursorItem { debugMenu, $"BP Run To Cursor" };
1452 MenuPlacement debugBpSkipRunToCursorItem { debugMenu, $"BP Run To Cursor Skipping Breakpoints" };
1453 MenuPlacement debugBpRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level" };
1454 MenuPlacement debugBpSkipRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level Skipping Breakpoints" };
1456 //MenuDivider { debugMenu };
1457 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1458 MenuPlacement imageMenu { menu, $"Image", i };
1459 Menu viewMenu { menu, $"View", v };
1460 MenuItem viewProjectItem
1462 viewMenu, $"Project View", j, alt0, disabled = true;
1463 bool NotifySelect(MenuItem selection, Modifiers mods)
1467 projectView.visible = true;
1468 projectView.Activate();
1473 MenuPlacement { viewMenu, $"View Designer" };
1474 MenuPlacement { viewMenu, $"View Code" };
1475 MenuPlacement { viewMenu, $"View Properties" };
1476 MenuPlacement { viewMenu, $"View Methods" };
1477 MenuItem viewDesignerItem
1479 viewMenu, $"View Designer", d, f8;
1480 bool NotifySelect(MenuItem selection, Modifiers mods)
1482 Window client = activeClient;
1483 Class dataType = client._class;
1484 if(!strcmp(dataType.name, "Designer"))
1486 client.visible = true;
1490 ((CodeEditor)client).ViewDesigner();
1494 MenuItem viewCodeItem
1496 viewMenu, $"View Code", c, f8;
1497 bool NotifySelect(MenuItem selection, Modifiers mods)
1499 Window client = activeClient;
1500 Class dataType = client._class;
1501 if(!strcmp(dataType.name, "Designer"))
1502 client = ((Designer)client).codeEditor;
1505 // Do this after so the caret isn't moved yet...
1506 client.visible = true;
1510 MenuItem viewPropertiesItem
1512 viewMenu, $"View Properties", p, f4;
1513 bool NotifySelect(MenuItem selection, Modifiers mods)
1515 sheet.visible = true;
1516 sheet.sheetSelected = properties;
1521 MenuItem viewMethodsItem
1523 viewMenu, $"View Methods", m, f4;
1524 bool NotifySelect(MenuItem selection, Modifiers mods)
1526 sheet.visible = true;
1527 sheet.sheetSelected = methods;
1532 MenuItem viewToolBoxItem
1534 viewMenu, $"View Toolbox", x, f12;
1535 bool NotifySelect(MenuItem selection, Modifiers mods)
1537 toolBox.visible = true;
1542 MenuItem viewOutputItem
1544 viewMenu, $"Output", o, alt2;
1545 bool NotifySelect(MenuItem selection, Modifiers mods)
1551 MenuItem viewWatchesItem
1553 viewMenu, $"Watches", w, alt3;
1554 bool NotifySelect(MenuItem selection, Modifiers mods)
1560 MenuItem viewThreadsItem
1562 viewMenu, $"Threads", t, alt4;
1563 bool NotifySelect(MenuItem selection, Modifiers mods)
1569 MenuItem viewBreakpointsItem
1571 viewMenu, $"Breakpoints", b, alt5;
1572 bool NotifySelect(MenuItem selection, Modifiers mods)
1574 breakpointsView.Show();
1578 MenuItem viewCallStackItem
1580 viewMenu, $"Call Stack", s, alt7;
1581 bool NotifySelect(MenuItem selection, Modifiers mods)
1583 callStackView.Show();
1587 MenuItem viewAllDebugViews
1589 viewMenu, $"All Debug Views", a, alt9;
1590 bool NotifySelect(MenuItem selection, Modifiers mods)
1595 callStackView.Show();
1596 breakpointsView.Show();
1600 #ifdef GDB_DEBUG_GUI
1601 MenuDivider { viewMenu };
1602 MenuItem viewGDBItem
1604 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1605 bool NotifySelect(MenuItem selection, Modifiers mods)
1612 MenuDivider { viewMenu };
1613 MenuItem viewColorPicker
1615 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1616 bool NotifySelect(MenuItem selection, Modifiers mods)
1618 ColorPicker colorPicker { master = this };
1619 colorPicker.Modal();
1623 MenuDivider { viewMenu };
1627 viewMenu, "Full Screen", f, checkable = true;
1629 bool NotifySelect(MenuItem selection, Modifiers mods)
1631 app.fullScreen ^= true;
1633 anchor = { 0, 0, 0, 0 };
1638 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1640 MenuDivider { viewMenu };
1642 Menu languageMenu { viewMenu, "Language", l };
1644 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1645 Menu windowMenu { menu, $"Window", w };
1646 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1647 MenuDivider { windowMenu };
1648 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1649 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1650 MenuDivider { windowMenu };
1651 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1652 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1653 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1654 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1655 MenuDivider { windowMenu };
1656 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1657 Menu helpMenu { menu, $"Help", h };
1660 helpMenu, $"API Reference", r, f1;
1661 bool NotifySelect(MenuItem selection, Modifiers mods)
1665 char * p = new char[MAX_LOCATION];
1667 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1668 PathCat(p, "documentor");
1669 #if defined(__WIN32__)
1670 ChangeExtension(p, "exe", p);
1672 if(!FileExists(p).isFile)
1673 strcpy(p, "documentor");
1675 documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
1680 Process_ShowWindows(documentor.GetProcessID());
1681 // documentor.Puts("Activate\n");
1686 MenuDivider { helpMenu };
1689 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1690 bool NotifySelect(MenuItem selection, Modifiers mods)
1692 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1696 MenuDivider { helpMenu };
1699 helpMenu, $"Documentation Folder", d;
1700 bool NotifySelect(MenuItem selection, Modifiers mods)
1702 FindAndShellOpenInstalledFolder("doc");
1708 helpMenu, $"Samples Folder", s;
1709 bool NotifySelect(MenuItem selection, Modifiers mods)
1711 FindAndShellOpenInstalledFolder("samples");
1717 helpMenu, $"Extras Folder", x;
1718 bool NotifySelect(MenuItem selection, Modifiers mods)
1720 FindAndShellOpenInstalledFolder("extras");
1724 MenuDivider { helpMenu };
1727 helpMenu, $"Community Forums", f;
1728 bool NotifySelect(MenuItem selection, Modifiers mods)
1730 ShellOpen("http://ecere.com/forums");
1734 MenuDivider { helpMenu };
1737 helpMenu, $"About...", a;
1738 bool NotifySelect(MenuItem selection, Modifiers mods)
1740 AboutIDE { master = this }.Modal();
1745 property ToolBox toolBox
1747 get { return toolBox; }
1750 property Sheet sheet
1752 get { return sheet; }
1755 property Project project
1757 get { return projectView ? projectView.project : null; }
1760 property Workspace workspace
1762 get { return projectView ? projectView.workspace : null; }
1765 FindInFilesDialog findInFilesDialog
1768 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1775 #ifdef GDB_DEBUG_GUI
1778 master = this, parent = this;
1779 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1781 void OnCommand(const char * string)
1784 ide.debugger.SendGDBCommand(string);
1789 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1791 //app.driver = app.drivers[selection.id];
1792 #if defined(__unix__) || defined(__APPLE__)
1793 app.driver = selection.id ? "OpenGL" : "X";
1795 app.driver = selection.id ? "OpenGL" : "GDI";
1797 delete ideSettings.displayDriver;
1798 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1800 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1802 settingsContainer.Save();
1803 //SetDriverAndSkin();
1807 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1809 app.skin = app.skins[selection.id];
1814 void SetDriverAndSkin()
1817 for(c = 0; c < app.numSkins; c++)
1818 if(!strcmp(app.skins[c], app.skin))
1820 skinItems[c].checked = true;
1823 for(c = 0; c < app.numDrivers; c++)
1824 if(!strcmp(app.drivers[c], app.driver))
1826 driverItems[c].checked = true;
1831 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1833 Project project = workspace.projects.firstIterator.data;
1834 projectView = ProjectView
1837 fileName = fileName;
1839 void NotifyDestroyed(Window window, DialogResult result)
1842 text = titleECEREIDE;
1847 projectView.Create();
1848 RepositionWindows(false);
1850 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1851 projectView.workspace = workspace;
1852 projectView.project = project;
1853 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1856 updateRecentMenus();
1858 ide.breakpointsView.LoadFromWorkspace();
1859 ide.watchesView.LoadFromWorkspace();
1861 findInFilesDialog.projectNodeField.userData = projectView;
1864 char fileName[MAX_LOCATION];
1865 strcpy(fileName, project.topNode.path);
1866 PathCat(fileName, project.topNode.name);
1873 projectView.visible = false;
1874 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1876 if(findInFilesDialog)
1878 char workingDir[MAX_LOCATION];
1879 GetWorkingDir(workingDir, MAX_LOCATION);
1880 findInFilesDialog.SearchStop();
1881 findInFilesDialog.currentDirectory = workingDir;
1883 sheet.visible = false;
1884 toolBox.visible = false;
1885 outputView.visible = false;
1886 ideMainFrame.text = titleECEREIDE;
1888 ide.updateRecentMenus();
1894 void RepositionWindows(bool expand)
1899 bool callStackVisible = expand ? false : callStackView.visible;
1900 bool threadsVisible = expand ? false : threadsView.visible;
1901 bool watchesVisible = expand ? false : watchesView.visible;
1902 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1903 bool toolBoxVisible = toolBox.visible;
1904 bool outputVisible = expand ? false : outputView.visible;
1905 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1906 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1908 for(child = firstChild; child; child = child.next)
1910 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1911 child._class == class(Sheet) || child._class == class(ProjectView))
1913 Anchor anchor = child.anchor;
1914 anchor.top = topDistance;
1915 anchor.bottom = bottomDistance;
1916 if(child._class == class(CodeEditor) || child._class == class(Designer))
1918 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1919 anchor.right = toolBoxVisible ? 150 : 0;
1922 child.anchor = anchor;
1926 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1927 child._class == class(BreakpointsView))
1928 child.visible = false;
1931 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1933 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1937 bool ShowCodeEditor()
1940 activeClient.Activate();
1941 else if(projectView)
1943 projectView.visible = true;
1944 projectView.Activate();
1946 else if(sheet.visible)
1949 outputView.visible = false;
1953 void DocumentSaved(Window document, const char * fileName)
1955 ideConfig.recentFiles.addRecent(fileName);
1956 ideConfig.recentFiles.write(settingsContainer);
1957 ide.updateRecentFilesMenu();
1958 ide.AdjustFileMenus();
1961 bool Window::OnFileModified(FileChange fileChange, const char * param)
1964 sprintf(temp, $"The document %s was modified by another application.\n"
1965 "Would you like to reload it and lose your changes?", this.fileName);
1966 if(MessageBox { creationActivation = flash, type = yesNo, master = this/*.parent*/,
1967 text = $"Document has been modified", contents = temp }.Modal() == yes)
1969 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1970 char * fileName = CopyString(this.fileName);
1971 WindowState state = this.state;
1972 Anchor anchor = this.anchor;
1973 Size size = this.size;
1975 this.modifiedDocument = false;
1977 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1980 this.anchor = anchor;
1982 this.SetState(state, true, 0);
1990 void UpdateMakefiles()
1994 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
1995 for(prj : workspace.projects)
1996 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2001 void UpdateCompilerConfigs(bool mute)
2003 UpdateToolBarActiveCompilers();
2006 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
2007 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
2010 projectView.ShowOutputBuildLog(true);
2011 projectView.DisplayCompiler(compiler, false);
2013 for(prj : workspace.projects)
2014 projectView.ProjectPrepareCompiler(prj, compiler, silent);
2019 void UpdateToolBarActiveCompilers()
2021 toolBar.activeCompiler.Clear();
2022 for(compiler : ideConfig.compilers)
2024 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
2025 if(workspace && workspace.activeCompiler && !strcmp(compiler.name, workspace.activeCompiler))
2026 toolBar.activeCompiler.currentRow = row;
2028 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
2029 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
2030 toolBar.activeBitDepth.SelectRow(toolBar.activeBitDepth.FindRow(workspace ? workspace.bitDepth : 0));
2033 void UpdateToolBarActiveConfigs(bool selectionOnly)
2035 bool commonSelected = false;
2036 DataRow row = toolBar.activeConfig.currentRow;
2038 row = toolBar.activeConfig.FindRow(1);
2041 toolBar.activeConfig.Clear();
2042 row = toolBar.activeConfig.AddString($"(Mixed)");
2047 char * configName = null;
2050 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
2051 for(prj : workspace.projects)
2053 for(cfg : prj.configurations)
2056 configs[cfg.name] = 1;
2061 toolBar.activeConfig.AddString(&name);
2065 if(projectView && projectView.project)
2067 for(prj : workspace.projects)
2069 if(prj.config && prj.config.name)
2071 configName = prj.config.name;
2077 commonSelected = true;
2078 for(prj : workspace.projects)
2080 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
2082 commonSelected = false;
2090 commonSelected = false;
2091 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
2093 if(!strcmp(row.string, configName))
2095 toolBar.activeConfig.currentRow = row;
2096 commonSelected = true;
2103 toolBar.activeConfig.Sort(null, 0);
2105 toolBar.activeConfig.currentRow = row;
2110 bool unavailable = !project;
2112 projectAddItem.disabled = unavailable;
2113 toolBar.buttonAddProject.disabled = unavailable;
2115 projectSettingsItem.disabled = unavailable;
2117 projectBrowseFolderItem.disabled = unavailable;
2119 viewProjectItem.disabled = unavailable;
2121 toolBar.activeConfig.disabled = unavailable;
2122 toolBar.activeCompiler.disabled = unavailable;
2123 toolBar.activeBitDepth.disabled = unavailable;
2126 debugUseValgrindItem.disabled = unavailable;
2127 AdjustValgrindMenus();
2136 void AdjustValgrindMenus()
2138 bool unavailable = !project || !debugUseValgrindItem.checked;
2139 debugValgrindNoLeakCheckItem.disabled = unavailable;
2140 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2141 debugValgrindYesLeakCheckItem.disabled = unavailable;
2142 debugValgrindFullLeakCheckItem.disabled = unavailable;
2144 debugValgrindTrackOriginsItem.disabled = unavailable;
2146 debugValgrindRSDefaultItem.disabled = unavailable;
2147 debugValgrindRS0Item.disabled = unavailable;
2148 debugValgrindRS16Item.disabled = unavailable;
2149 debugValgrindRS32Item.disabled = unavailable;
2150 debugValgrindRS64Item.disabled = unavailable;
2151 debugValgrindRS128Item.disabled = unavailable;
2152 debugValgrindRS256Item.disabled = unavailable;
2153 debugValgrindRS512Item.disabled = unavailable;
2157 property bool hasOpenedCodeEditors
2162 for(w = firstChild; w; w = w.next)
2163 if(w._class == class(CodeEditor) &&
2164 w.isDocument && !w.closing && w.visible && w.created &&
2165 w.fileName && w.fileName[0])
2171 void AdjustFileMenus()
2173 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2175 projectQuickItem.disabled = unavailable;
2178 void AdjustBuildMenus()
2180 bool unavailable = project && projectView.buildInProgress;
2181 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2182 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2184 projectNewItem.disabled = unavailable;
2185 toolBar.buttonNewProject.disabled = unavailable;
2186 projectOpenItem.disabled = unavailable;
2187 toolBar.buttonOpenProject.disabled = unavailable;
2189 unavailable = !project || projectView.buildInProgress;
2191 projectCloseItem.disabled = unavailable;
2192 // toolBar.buttonCloseProject.disabled = unavailable;
2194 projectRunItem.disabled = naForRun;
2195 toolBar.buttonRun.disabled = naForRun;
2197 projectBuildItem.disabled = false;
2198 projectBuildItem.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2199 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2201 projectLinkItem.disabled = unavailable;
2202 toolBar.buttonReLink.disabled = unavailable;
2203 projectRebuildItem.disabled = unavailable;
2204 toolBar.buttonRebuild.disabled = unavailable;
2205 projectCleanItem.disabled = unavailable;
2206 toolBar.buttonClean.disabled = unavailable;
2207 projectCleanTargetItem.disabled = unavailable;
2208 projectRealCleanItem.disabled = unavailable;
2209 // toolBar.buttonRealClean.disabled = unavailable;
2210 projectRegenerateItem.disabled = unavailable;
2211 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2212 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2213 projectInstallItem.disabled = unavailable;
2214 toolBar.buttonInstall.disabled = unavailable;
2216 projectCompileItem.disabled = unavailable;
2218 AdjustPopupBuildMenus();
2221 void AdjustPopupBuildMenus()
2223 bool unavailable = !project || projectView.buildInProgress;
2225 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2228 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2229 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, mode);
2232 menu.disabled = false;
2233 menu.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2234 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2237 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, mode); if(menu) menu.disabled = unavailable;
2238 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, mode); if(menu) menu.disabled = unavailable;
2239 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, mode); if(menu) menu.disabled = unavailable;
2240 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, mode); if(menu) menu.disabled = unavailable;
2241 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, mode); if(menu) menu.disabled = unavailable;
2242 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, mode); if(menu) menu.disabled = unavailable;
2243 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, mode); if(menu) menu.disabled = unavailable;
2244 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, mode); if(menu) menu.disabled = unavailable;
2245 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, mode); if(menu) menu.disabled = unavailable;
2246 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, mode); if(menu) menu.disabled = unavailable;
2247 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, mode); if(menu) menu.disabled = unavailable;
2248 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, mode); if(menu) menu.disabled = unavailable;
2249 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, mode); if(menu) menu.disabled = unavailable;
2250 projectView.popupMenu.Update(null);
2254 property bool areDebugMenusUnavailable { get {
2256 project.GetTargetType(project.config) != executable ||
2257 projectView.buildInProgress == buildingMainProject;
2260 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2261 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2262 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2264 void AdjustDebugMenus()
2266 bool unavailable = areDebugMenusUnavailable;
2267 bool running = isDebuggerRunning;
2268 bool stopped = isDebuggerStopped;
2269 bool active = debugger.isActive;
2271 bool isNotRunning = unavailable || !running;
2272 bool isNotNotRunning = unavailable || running;
2273 bool isNotStopped = unavailable || !stopped;
2274 bool isNotActive = unavailable || !active;
2276 debugStartResumeItem.disabled = isNotNotRunning;
2277 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2278 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2281 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2282 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2285 debugBreakItem.disabled = isNotRunning;
2286 debugStopItem.disabled = isNotActive;
2287 debugRestartItem.disabled = isNotActive;
2290 toolBar.buttonDebugPause.disabled = isNotRunning;
2291 toolBar.buttonDebugStop.disabled = isNotActive;
2292 toolBar.buttonDebugRestart.disabled = isNotActive;
2295 debugStepIntoItem.disabled = isNotNotRunning;
2296 debugStepOverItem.disabled = isNotNotRunning;
2297 debugSkipStepOverItem.disabled = isNotNotRunning;
2298 debugStepOutItem.disabled = isNotStopped;
2299 debugSkipStepOutItem.disabled = isNotStopped;
2301 debugStepUntilItem.disabled = isNotStopped;
2302 debugSkipStepUntilItem.disabled = isNotStopped;
2306 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2307 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2308 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2309 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2310 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2312 if((Designer)GetActiveDesigner())
2314 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2316 codeEditor.AdjustDebugMenus();
2320 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2322 char tempString[MAX_LOCATION];
2323 strcpy(tempString, directory);
2324 if(saveSettings && !projectView)
2326 ideSettings.ideFileDialogLocation = directory;
2327 settingsContainer.Save();
2330 ideFileDialog.currentDirectory = tempString;
2331 codeEditorFileDialog.currentDirectory = tempString;
2332 codeEditorFormFileDialog.currentDirectory = tempString;
2335 void ChangeProjectFileDialogDirectory(char * directory)
2337 ideSettings.ideProjectFileDialogLocation = directory;
2338 settingsContainer.Save();
2341 Window FindWindow(const char * filePath)
2343 Window document = null;
2345 // TOCHECK: Do we need to change slashes here?
2346 for(document = firstChild; document; document = document.next)
2348 const char * fileName = document.fileName;
2349 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2351 document.visible = true;
2352 document.Activate();
2359 bool DontTerminateDebugSession(const char * title)
2361 if(debugger.isActive)
2363 if(MessageBox { type = yesNo, master = ide,
2364 contents = $"Do you want to terminate the debugging session in progress?",
2365 text = title }.Modal() == no)
2368 MessageBox msg { type = yesNo, master = ide,
2369 contents = "Do you want to terminate the debugging session in progress?",
2371 if(msg.Modal() == no)
2383 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2385 char extension[MAX_EXTENSION] = "";
2386 Window document = null;
2387 bool isProject = false;
2388 bool needFileModified = true;
2389 char winFilePath[MAX_LOCATION];
2390 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2391 Window currentDoc = activeClient;
2392 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2395 GetExtension(filePath, extension);
2399 strcpy(extension, type);
2401 if(strcmp(extension, ProjectExtension))
2403 for(document = firstChild; document; document = document.next)
2405 const char * fileName = document.fileName;
2406 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2408 document.visible = true;
2410 document.Activate();
2416 if(createIfFails == whatever)
2418 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2420 needFileModified = false;
2421 if(openMethod == normal)
2423 if(DontTerminateDebugSession($"Open Project"))
2432 Workspace workspace = null;
2434 if(FileExists(filePath))
2436 if(!strcmp(extension, ProjectExtension))
2438 char workspaceFile[MAX_LOCATION];
2439 strcpy(workspaceFile, filePath);
2440 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2441 workspace = LoadWorkspace(workspaceFile, filePath);
2443 else if(!strcmp(extension, WorkspaceExtension))
2444 workspace = LoadWorkspace(filePath, null);
2451 CreateProjectView(workspace, filePath);
2452 document = projectView;
2454 toolBox.visible = true;
2455 sheet.visible = true;
2456 projectView.MakeActive();
2458 workspace.ParseLoadedBreakpoints();
2459 workspace.DropInvalidBreakpoints(null);
2462 ide.projectView.ShowOutputBuildLog(true);
2464 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler);
2465 ide.projectView.DisplayCompiler(compiler, false);
2468 UpdateCompilerConfigs(false);
2471 char newWorkingDir[MAX_LOCATION];
2472 StripLastDirectory(filePath, newWorkingDir);
2473 ChangeFileDialogsDirectory(newWorkingDir, false);
2476 document.fileName = filePath;
2478 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2480 // this crashes on starting ide with epj file, solution please?
2481 // app.UpdateDisplay();
2483 workspace.OpenPreviouslyOpenedFiles(noParsing);
2484 workspace.holdTracking = true;
2485 ide.RepositionWindows(false);
2486 workspace.holdTracking = false;
2488 workspace.timer.Start();
2490 #if !defined(__WIN32__)
2491 // Valgrind Debug menu updates
2492 debugUseValgrindItem.checked = workspace.useValgrind;
2494 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2495 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2496 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2497 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2499 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2500 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2501 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2502 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2503 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2504 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2505 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2506 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2508 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2511 findInFilesDialog.mode = FindInFilesMode::project;
2512 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2515 char location[MAX_LOCATION];
2516 StripLastDirectory(ide.project.topNode.path, location);
2517 ChangeProjectFileDialogDirectory(location);
2524 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2526 ideProjectFileDialog.text = openProjectFileDialogTitle;
2527 if(ideProjectFileDialog.Modal() == cancel)
2529 filePath = ideProjectFileDialog.filePath;
2530 GetExtension(filePath, extension);
2541 else if(openMethod == add)
2546 char slashFilePath[MAX_LOCATION];
2547 GetSlashPathBuffer(slashFilePath, filePath);
2548 for(p : workspace.projects)
2550 if(!fstrcmp(p.filePath, slashFilePath))
2558 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2559 contents = $"This project is already present in workspace." }.Modal();
2563 prj = LoadProject(filePath, null);
2566 const char * activeConfigName = null;
2567 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
2568 prj.StartMonitoring();
2569 workspace.AddProject(prj, null);
2570 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2571 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2572 activeConfigName = toolBar.activeConfig.currentRow.string;
2573 if(activeConfigName)
2575 for(cfg : prj.configurations)
2577 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2585 projectView.AddNode(prj.topNode, null);
2586 workspace.modified = true;
2588 findInFilesDialog.AddProjectItem(prj);
2589 projectView.ShowOutputBuildLog(true);
2590 projectView.DisplayCompiler(compiler, false);
2591 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2595 char location[MAX_LOCATION];
2596 StripLastDirectory(prj.topNode.path, location);
2597 ChangeProjectFileDialogDirectory(location);
2600 // projectView is associated with the main project and not with the one just added but
2601 return projectView; // just to let the caller know something was opened
2609 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2610 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2611 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2613 if(FileExists(filePath))
2614 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2615 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2616 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2619 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2622 else if(!strcmp(extension, "3ds"))
2624 if(FileExists(filePath))
2625 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2626 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2627 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2631 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2634 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2635 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2636 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2637 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2638 !strcmp(extension, "js"))
2640 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2641 editor.updatingCode = true;
2642 if(editor.LoadFile(filePath))
2645 editor.visible = true;
2649 needFileModified = false;
2653 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2654 if(editor.LoadFile(filePath))
2657 editor.visible = true;
2661 needFileModified = false;
2664 if(document && (document._class == class(PictureEdit) ||
2665 document._class == class(ModelView)))
2670 document.fileName = filePath;
2671 if(workspace && !workspace.holdTracking)
2672 workspace.UpdateOpenedFileInfo(filePath, opened, true);
2676 if(!document && createIfFails != no)
2678 if(createIfFails != yes && !needFileModified &&
2679 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2680 createIfFails = yes;
2681 if(createIfFails == yes || createIfFails == whatever)
2683 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2685 document.fileName = filePath;
2691 if(projectView && document._class == class(CodeEditor) && workspace)
2692 workspace.RestorePreviouslyOpenedFileState((CodeEditor)document);
2694 if(needFileModified)
2695 document.OnFileModified = OnFileModified;
2696 document.NotifySaved = DocumentSaved;
2697 if(maximizeDoc && document.hasMaximize)
2698 document.state = maximized;
2702 ideConfig.recentWorkspaces.addRecent(document.fileName);
2703 ideConfig.recentWorkspaces.write(settingsContainer);
2704 ide.updateRecentProjectsMenu();
2707 workspace.recentFiles.addRecent(document.fileName);
2710 ideConfig.recentFiles.addRecent(document.fileName);
2711 ideConfig.recentFiles.write(settingsContainer);
2713 ide.updateRecentFilesMenu();
2714 ide.AdjustFileMenus();
2721 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2722 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2724 if(!parentClosing && ide.workspace)
2725 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2728 bool ModelView::ModelViewOnClose(bool parentClosing)
2730 if(!parentClosing && ide.workspace)
2731 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2734 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2736 if(!parentClosing && ide.workspace)
2737 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2742 void OnUnloadGraphics(Window window)
2744 display.ClearMaterials();
2745 display.ClearTextures();
2746 display.ClearMeshes();
2750 void UpdateStateLight(StatusField fld, bool on)
2752 fld.color = on ? lime : Color { 128,128,128 };
2753 fld.backColor = on ? dimGray : 0;
2757 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2759 UpdateStateLight(caps, app.GetKeyState(capsState));
2760 UpdateStateLight(num, app.GetKeyState(numState));
2764 bool OnKeyDown(Key key, unichar ch)
2768 case b: projectView.Update(null); break;
2769 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2770 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2775 bool OnKeyUp(Key key, unichar ch)
2779 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2780 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2785 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2788 projectView.GoToError(line, noParsing, objectFileExt);
2791 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2793 FileAttribs result { };
2794 FileAttribs fileAttribs;
2798 strcpy(selectedPath, prj.topNode.path);
2799 else if(dir && dir[0])
2800 strcpy(selectedPath, dir);
2802 selectedPath[0] = '\0';
2803 PathCat(selectedPath, filePath);
2805 if((fileAttribs = FileExists(selectedPath)).isFile)
2806 result = fileAttribs;
2810 for(p : workspace.projects)
2812 strcpy(selectedPath, p.topNode.path);
2813 PathCat(selectedPath, filePath);
2814 if((fileAttribs = FileExists(selectedPath)).isFile)
2817 result = fileAttribs;
2824 ProjectNode n = null;
2825 for(p : workspace.projects)
2827 if((n = p.topNode.Find(filePath, false)))
2829 n.GetFullFilePath(selectedPath, true);
2830 if((fileAttribs = FileExists(selectedPath)).isFile)
2833 result = fileAttribs;
2838 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2839 (fileAttribs = FileExists(selectedPath)).isFile)
2842 result = fileAttribs;
2850 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2853 const char *path = text;
2854 char *colon = strchr(text, ':');
2855 char filePath[MAX_LOCATION] = "";
2856 char completePath[MAX_LOCATION];
2857 int line = 0, col = 0;
2858 int len = strlen(text);
2860 FileAttribs fileAttribs;
2862 // support for valgrind output
2863 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2874 /*for(s=colon; *s; s++)
2883 //line = atoi(colon+1);
2885 // support for "Found n match(es) in "file/path";
2886 else if(len > 0 && 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)
2892 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2894 path = (colon - 1 > path) ? colon - 1 : path;
2895 colon = strstr(colon + 1, ":");
2897 if(*path == '*' && (s = strchr(path+1, '*')))
2899 while(isspace(*path)) path++;
2903 char * close = strchr(path, ')');
2907 strncpy(name, path+1, close - path - 1);
2908 name[close - path - 1] = '\0';
2909 for(p : ide.workspace.projects)
2911 if(!strcmp(p.name, name))
2921 prj = project ? project : (dir ? null : ide.project);
2924 strncpy(filePath, path, colon - path);
2925 filePath[colon - path] = '\0';
2926 line = atoi(colon + 1);
2927 colon = strstr(colon + 1, ":");
2929 col = atoi(colon + 1);
2931 else if(path - 1 >= text && *(path - 1) == '\"')
2933 colon = strchr(path, '\"');
2936 strncpy(filePath, path, colon - path);
2937 filePath[colon - path] = '\0';
2940 else if(path && !colon)
2942 strcpy(filePath, path);
2945 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2946 CodeLocationGoTo(completePath, fileAttribs, line, col);
2949 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2951 if(fileAttribs.isFile)
2953 char ext[MAX_EXTENSION];
2954 GetExtension(path, ext);
2956 if(binaryDocExt.Find(ext))
2958 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2959 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2961 char dirPath[MAX_LOCATION];
2962 StripLastDirectory(path, dirPath);
2967 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2968 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2970 EditBox editBox = codeEditor.editBox;
2971 editBox.GoToLineNum(line - 1);
2972 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2976 else if(fileAttribs.isDirectory)
2980 void OnRedraw(Surface surface)
2982 Bitmap bitmap = back.bitmap;
2984 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2987 void SheetSelected(SheetType sheetSelected)
2989 if(activeChild == sheet)
2991 if(sheetSelected == methods)
2993 viewPropertiesItem.accelerator = f4;
2994 viewPropertiesItem.parent = viewMenu;
2995 viewMethodsItem.parent = null;
2999 viewMethodsItem.accelerator = f4;
3000 viewMethodsItem.parent = viewMenu;
3001 viewPropertiesItem.parent = null;
3006 viewMethodsItem.parent = viewMenu;
3007 viewPropertiesItem.parent = viewMenu;
3008 if(sheetSelected == methods)
3010 viewMethodsItem.accelerator = f4;
3011 viewPropertiesItem.accelerator = 0;
3015 viewMethodsItem.accelerator = 0;
3016 viewPropertiesItem.accelerator = f4;
3021 void OnActivateClient(Window client, Window previous)
3023 //if(!client || client != previous)
3026 if(!client || client != previous)
3029 dataType = previous._class;
3030 if(previous && !strcmp(dataType.name, "CodeEditor"))
3032 ((CodeEditor)previous).UpdateFormCode();
3034 else if(previous && !strcmp(dataType.name, "Designer"))
3036 ((Designer)previous).codeEditor.UpdateFormCode();
3041 dataType = client._class;
3042 if(client && !strcmp(dataType.name, "CodeEditor"))
3044 CodeEditor codeEditor = (CodeEditor)client;
3045 SetPrivateModule(codeEditor.privateModule);
3046 SetCurrentContext(codeEditor.globalContext);
3047 SetTopContext(codeEditor.globalContext);
3048 SetGlobalContext(codeEditor.globalContext);
3050 SetDefines(&codeEditor.defines);
3051 SetImports(&codeEditor.imports);
3053 SetActiveDesigner(codeEditor.designer);
3055 sheet.codeEditor = codeEditor;
3056 toolBox.codeEditor = codeEditor;
3058 viewDesignerItem.parent = viewMenu;
3059 if(activeChild != codeEditor)
3061 viewCodeItem.parent = viewMenu;
3062 viewDesignerItem.accelerator = 0;
3063 viewCodeItem.accelerator = f8;
3067 viewCodeItem.parent = null;
3068 viewDesignerItem.accelerator = f8;
3071 else if(client && !strcmp(dataType.name, "Designer"))
3073 CodeEditor codeEditor = ((Designer)client).codeEditor;
3076 SetPrivateModule(codeEditor.privateModule);
3077 SetCurrentContext(codeEditor.globalContext);
3078 SetTopContext(codeEditor.globalContext);
3079 SetGlobalContext(codeEditor.globalContext);
3080 SetDefines(&codeEditor.defines);
3081 SetImports(&codeEditor.imports);
3085 SetPrivateModule(null);
3086 SetCurrentContext(null);
3087 SetTopContext(null);
3088 SetGlobalContext(null);
3093 SetActiveDesigner((Designer)client);
3095 sheet.codeEditor = codeEditor;
3096 toolBox.codeEditor = codeEditor;
3098 viewCodeItem.parent = viewMenu;
3099 if(activeChild != client)
3101 viewDesignerItem.parent = viewMenu;
3102 viewDesignerItem.accelerator = f8;
3103 viewCodeItem.accelerator = 0;
3107 viewDesignerItem.parent = null;
3108 viewCodeItem.accelerator = f8;
3113 if(!client && !projectView && sheet.visible)
3116 sheet.visible = false;
3117 toolBox.visible = false;
3120 sheet.codeEditor = null;
3121 toolBox.codeEditor = null;
3122 SetActiveDesigner(null);
3124 viewDesignerItem.parent = null;
3125 viewCodeItem.parent = null;
3128 SheetSelected(sheet.sheetSelected);
3131 projectCompileItem = null;
3136 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3138 CodeEditor codeEditor = (CodeEditor)client;
3139 EditBox editBox = codeEditor.editBox;
3141 statusBar.AddField(pos);
3143 caps = { width = 40, text = $"CAPS" };
3144 statusBar.AddField(caps);
3145 UpdateStateLight(caps, app.GetKeyState(capsState));
3147 ovr = { width = 36, text = $"OVR" };
3148 statusBar.AddField(ovr);
3149 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3151 num = { width = 36, text = $"NUM" };
3152 statusBar.AddField(num);
3153 UpdateStateLight(num, app.GetKeyState(numState));
3155 //statusBar.text = "Ready";
3157 if(projectView && projectView.project)
3159 bool isCObject = false;
3160 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3161 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3165 char nodeName[MAX_FILENAME];
3166 char name[MAX_FILENAME+96];
3168 ChangeExtension(node.name, "c", nodeName);
3169 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3170 projectCompileItem =
3172 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3174 bool NotifySelect(MenuItem selection, Modifiers mods)
3178 bool isCObject = false;
3179 bool isExcluded = false;
3180 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3184 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3187 List<ProjectNode> nodes { };
3189 projectView.Compile(node.project, nodes, normal, isCObject ? cObject : normal);
3197 projectMenu.AddDynamic(projectCompileItem, ide, false);
3203 caps = ovr = num = null;
3208 bool OnClose(bool parentClosing)
3210 //return !projectView.buildInProgress;
3211 if(projectView && projectView.buildInProgress)
3213 if(DontTerminateDebugSession($"Close IDE"))
3215 if(findInFilesDialog)
3216 findInFilesDialog.SearchStop();
3219 workspace.timer.Stop();
3222 ideMainFrame.Destroy(0);
3229 bool passThrough = false;
3230 bool debugWorkDir = false;
3231 char * passDebugWorkDir = null;
3232 bool openAsText = false;
3233 DynamicString passArgs { };
3236 for(c = 1; c<app.argc; c++)
3240 const char * arg = app.argv[c];
3241 char * buf = new char[strlen(arg)*2+1];
3243 passArgs.concat(" ");
3245 passArgs.concat(buf);
3248 else if(debugWorkDir)
3250 passDebugWorkDir = CopyString(app.argv[c]);
3251 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3252 debugWorkDir = false;
3254 else if(!strcmp(app.argv[c], "-t"))
3256 else if(!strcmp(app.argv[c], "-no-parsing"))
3257 ide.noParsing = true;
3258 else if(!strcmp(app.argv[c], "-debug-start"))
3259 ide.debugStart = true;
3260 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3261 debugWorkDir = true;
3262 else if(!strcmp(app.argv[c], "-@"))
3266 char fullPath[MAX_LOCATION];
3267 char parentPath[MAX_LOCATION];
3268 char ext[MAX_EXTENSION];
3270 FileAttribs dirAttribs;
3271 GetWorkingDir(fullPath, MAX_LOCATION);
3272 PathCat(fullPath, app.argv[c]);
3273 StripLastDirectory(fullPath, parentPath);
3274 GetExtension(app.argv[c], ext);
3275 isProject = !openAsText && !strcmpi(ext, "epj");
3277 if(isProject && c > 1 + (ide.debugStart ? 1 : 0)) continue;
3279 // Create directory for projects (only)
3280 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3282 if(isProject && !FileExists(fullPath))
3284 char name[MAX_LOCATION];
3285 NewProjectDialog newProjectDialog;
3289 projectView.visible = false;
3290 if(!projectView.Destroy(0))
3294 newProjectDialog = { master = this };
3296 strcpy(name, app.argv[c]);
3297 StripExtension(name);
3298 GetLastDirectory(name, name);
3299 newProjectDialog.projectName.contents = name;
3300 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3301 newProjectDialog.locationEditBox.path = parentPath;
3302 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3304 incref newProjectDialog;
3305 newProjectDialog.Modal();
3308 ideConfig.recentWorkspaces.addRecent(projectView.fileName);
3309 ideConfig.recentWorkspaces.write(settingsContainer);
3310 ide.updateRecentMenus();
3312 delete newProjectDialog;
3313 // Open only one project
3317 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3319 else if(strstr(fullPath, "http://") == fullPath)
3320 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3323 if(passThrough && projectView && projectView.project && workspace)
3324 workspace.commandLineArgs = passArgs;
3325 if(passDebugWorkDir && projectView && projectView.project && workspace)
3327 workspace.debugDir = passDebugWorkDir;
3328 delete passDebugWorkDir;
3331 UpdateToolBarActiveConfigs(false);
3332 UpdateToolBarActiveCompilers();
3339 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3342 projectView.visible = false;
3343 projectView.Destroy(0);
3346 #ifdef GDB_DEBUG_GUI
3347 gdbDialog.Destroy(0);
3352 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3356 char * oldPaths[128];
3357 String oldList = new char[maxPathLen];
3358 Array<String> newExePaths { };
3359 //Map<String, bool> exePathExists { };
3361 #if defined(__unix__) || defined(__APPLE__)
3362 Array<String> newLibPaths { };
3363 Map<String, bool> libPathExists { };
3368 for(prj : workspace.projects)
3370 DirExpression targetDirExp;
3372 // SKIP FIRST PROJECT...
3373 if(prj == workspace.projects.firstIterator.data) continue;
3375 // NOTE: Right now the additional project config dir will be
3376 // obtained when the debugger is started, so toggling it
3377 // while building will change which library gets used.
3378 // To go with the initial state, e.g. when F5 was pressed,
3379 // we nould need to keep a list of all project's active
3380 // config upon startup.
3381 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3383 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3387 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3388 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3392 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3393 if(cfg.targetType == sharedLibrary && cfg.debug)
3397 if(targetDirExp.dir)
3399 char buffer[MAX_LOCATION];
3400 #if defined(__WIN32__)
3401 Array<String> paths = newExePaths;
3403 Array<String> paths = newLibPaths;
3405 GetSystemPathBuffer(buffer, prj.topNode.path);
3406 PathCat(buffer, targetDirExp.dir);
3409 if(!fstrcmp(p, buffer))
3416 paths.Add(CopyString(buffer));
3418 delete targetDirExp;
3422 for(item : compiler.executableDirs)
3424 DirExpression dirExpr { };
3425 dirExpr.Evaluate(item, null, compiler, null, 0);
3428 for(p : newExePaths)
3430 if(!fstrcmp(p, dirExpr.dir))
3437 newExePaths.Add(CopySystemPath(dirExpr.dir));
3441 GetEnvironment("PATH", oldList, maxPathLen);
3443 printf("Old value of PATH: %s\n", oldList);
3445 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3446 for(c = 0; c < count; c++)
3449 for(p : newExePaths)
3451 if(!fstrcmp(p, oldPaths[c]))
3458 newExePaths.Add(CopySystemPath(oldPaths[c]));
3462 for(path : newExePaths)
3463 len += strlen(path) + 1;
3464 newList = new char[len + 1];
3466 for(path : newExePaths)
3468 strcat(newList, path);
3469 strcat(newList, pathListSep);
3471 newList[len - 1] = '\0';
3472 SetEnvironment("PATH", newList);
3474 printf("New value of PATH: %s\n", newList);
3481 #if defined(__unix__) || defined(__APPLE__)
3483 for(item : compiler.libraryDirs)
3485 if(!libPathExists[item]) // fstrcmp should be used
3487 String s = CopyString(item);
3489 libPathExists[s] = true;
3493 #if defined(__APPLE__)
3494 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3496 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3499 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3501 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3502 for(c = 0; c < count; c++)
3504 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3506 String s = CopyString(oldPaths[c]);
3508 libPathExists[s] = true;
3513 for(path : newLibPaths)
3514 len += strlen(path) + 1;
3515 newList = new char[len + 1];
3517 for(path : newLibPaths)
3519 strcat(newList, path);
3520 strcat(newList, pathListSep);
3522 newList[len - 1] = '\0';
3523 #if defined(__APPLE__)
3524 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3526 SetEnvironment("LD_LIBRARY_PATH", newList);
3529 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3535 delete libPathExists;
3538 if(compiler.distccEnabled && compiler.distccHosts)
3539 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3544 void DestroyTemporaryProjectDir()
3546 if(tmpPrjDir && tmpPrjDir[0])
3548 if(FileExists(tmpPrjDir).isDirectory)
3549 DestroyDir(tmpPrjDir);
3550 property::tmpPrjDir = null;
3556 // Graphics Driver Menu
3559 app.currentSkin.selectionColor = selectionColor;
3560 app.currentSkin.selectionText = selectionText;
3564 driverItems = new MenuItem[app.numDrivers];
3565 for(c = 0; c < app.numDrivers; c++)
3567 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3568 driverItems[c].id = c;
3569 driverItems[c].isRadio = true;
3572 driverItems = new MenuItem[2];
3573 #if defined(__unix__)
3574 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3575 driverItems[0].id = 0;
3576 driverItems[0].isRadio = true;
3578 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3579 driverItems[0].id = 0;
3580 driverItems[0].isRadio = true;
3582 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3583 driverItems[1].id = 1;
3584 driverItems[1].isRadio = true;
3586 /* skinItems = new MenuItem[app.numSkins];
3587 for(c = 0; c < app.numSkins; c++)
3589 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3590 skinItems[c].id = c;
3591 skinItems[c].isRadio = true;
3594 ideFileDialog.master = this;
3595 ideProjectFileDialog.master = this;
3597 //SetDriverAndSkin();
3601 void updateRecentMenus()
3603 updateRecentFilesMenu();
3604 updateRecentProjectsMenu();
3607 void updateRecentFilesMenu()
3610 char * itemPath = new char[MAX_LOCATION];
3611 char * itemName = new char[MAX_LOCATION+4];
3612 Workspace ws = workspace;
3613 RecentPaths recentFiles = ws ? ws.recentFiles : ideConfig.recentFiles;
3614 recentFilesMenu.Clear();
3615 for(recent : recentFiles)
3617 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3618 MakeSystemPath(itemPath);
3619 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3620 recentFilesMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3627 void updateRecentProjectsMenu()
3630 char * itemPath = new char[MAX_LOCATION];
3631 char * itemName = new char[MAX_LOCATION+4];
3632 recentProjectsMenu.Clear();
3633 for(recent : ideConfig.recentWorkspaces)
3635 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3636 MakeSystemPath(itemPath);
3637 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3638 recentProjectsMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3649 delete languageItems;
3653 documentor.Puts("Quit\n");
3660 void DestroyDir(char * path)
3662 RecursiveDeleteFolderFSI fsi { };
3667 #if defined(__WIN32__)
3668 define sdkDirName = "Ecere SDK";
3670 define sdkDirName = "ecere";
3673 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3676 char * v = new char[maxPathLen];
3680 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3681 StripLastDirectory(path, path);
3682 PathCat(path, subDir);
3683 if(name) PathCat(path, name);
3684 if(FileExists(path) & attribs) found = true;
3686 #if defined(__WIN32__)
3689 for(s : [ "ECERE_SDK_SRC", "AppData", "ALLUSERSPROFILE", "USERPROFILE", "HOMEPATH", "ProgramData", "ProgramFiles", "ProgramFiles(x86)", "SystemDrive" ])
3691 GetEnvironment(s, v, maxPathLen);
3694 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3695 if(!strcmp(s, "SystemDrive"))
3696 PathCat(path, "Program Files");
3697 if(strcmp(s, "ECERE_SDK_SRC"))
3698 PathCat(path, sdkDirName);
3699 PathCat(path, subDir);
3700 if(name) PathCat(path, name);
3701 if(FileExists(path) & attribs)
3716 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3717 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3720 p = new char[MAX_LOCATION];
3722 strcat(p, "/usr/share");
3726 for(c=0; c<numTokens; c++)
3728 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3729 PathCat(path, sdkDirName);
3730 PathCat(path, subDir);
3732 PathCat(path, name);
3733 if(FileExists(path) & attribs)
3746 void FindAndShellOpenInstalledFolder(const char * name)
3748 char path[MAX_LOCATION];
3749 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3753 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3755 char path[MAX_LOCATION];
3756 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3760 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3762 bool preserveRootFolder;
3764 void OutFolder(const char * folderPath, bool isRoot)
3766 if(!(preserveRootFolder && isRoot))
3767 RemoveDir(folderPath);
3770 bool OnFile(const char * filePath)
3772 DeleteFile(filePath);
3777 class IDEApp : GuiApplication
3779 //driver = "Win32Console";
3780 // driver = "OpenGL";
3784 TempFile includeFile { };
3789 char ext[MAX_EXTENSION];
3790 SetLoggingMode(stdOut, null);
3791 //SetLoggingMode(debug, null);
3793 settingsContainer.Load();
3795 if(ideSettings.language)
3797 const String language = GetLanguageString();
3798 if(ideSettings.language.OnCompare(language))
3800 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3805 ide.ApplyFont(ideSettings.codeEditorFont, ideSettings.codeEditorFontSize);
3806 ide.ApplyColorScheme(colorScheme);
3808 ideConfig.compilers.read(settingsContainer);
3809 ideConfig.recentFiles.read(settingsContainer);
3810 ideConfig.recentWorkspaces.read(settingsContainer);
3812 // First count files arg to decide whether to maximize
3814 bool passThrough = false, debugWorkDir = false;
3817 for(c = 1; c<app.argc; c++)
3820 else if(debugWorkDir)
3821 debugWorkDir = false;
3822 else if(!strcmp(app.argv[c], "-t"));
3823 else if(!strcmp(app.argv[c], "-no-parsing"));
3824 else if(!strcmp(app.argv[c], "-debug-start"));
3825 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3826 debugWorkDir = true;
3827 else if(!strcmp(app.argv[c], "-@"))
3834 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3836 app.driver = "OpenGL";
3837 ide.driverItems[1].checked = true;
3841 #if defined(__unix__) || defined(__APPLE__)
3842 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3844 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3846 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3850 char model[MAX_LOCATION];
3851 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3853 ide.duck.modelFile = model;
3854 ide.duck.parent = ideMainFrame;
3857 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3858 ide.debugRubberDuck.disabled = false;
3862 desktop.caption = titleECEREIDE;
3865 for(c = 1; c<app.argc; c++)
3867 char fullPath[MAX_LOCATION];
3868 GetWorkingDir(fullPath, MAX_LOCATION);
3869 PathCat(fullPath, app.argv[c]);
3870 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3874 // Default to language specified by environment if no language selected
3875 if(!ideSettings.language)
3877 ideSettings.language = GetLanguageString();
3878 settingsContainer.Save();
3881 // Default to home directory if no directory yet set up
3882 if(!ideSettings.ideProjectFileDialogLocation[0])
3885 char location[MAX_LOCATION];
3886 char * home = getenv("HOME");
3887 char * homeDrive = getenv("HOMEDRIVE");
3888 char * homePath = getenv("HOMEPATH");
3889 char * userProfile = getenv("USERPROFILE");
3890 char * systemDrive = getenv("SystemDrive");
3891 if(home && FileExists(home).isDirectory)
3893 strcpy(location, home);
3896 if(!found && homeDrive && homePath)
3898 strcpy(location, homeDrive);
3899 PathCat(location, homePath);
3900 if(FileExists(location).isDirectory)
3903 if(!found && FileExists(userProfile).isDirectory)
3905 strcpy(location, userProfile);
3908 if(!found && FileExists(systemDrive).isDirectory)
3910 strcpy(location, systemDrive);
3915 ideSettings.ideProjectFileDialogLocation = location;
3916 if(!ideSettings.ideFileDialogLocation[0])
3917 ideSettings.ideFileDialogLocation = location;
3921 if(!LoadIncludeFile())
3922 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3924 // Create language menu
3926 String language = ideSettings.language;
3930 ide.languageItems = new MenuItem[languages.count];
3933 ide.languageItems[i] =
3935 ide.languageMenu, l.name;
3936 bitmap = { l.bitmap };
3940 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3942 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3944 // Re-select previous selected language if aborted
3945 String language = ideSettings.language;
3949 if(((!language || !language[0]) && i == 0) ||
3950 (language && !strcmpi(l.code, language)))
3952 ide.languageItems[i].checked = true;
3964 // Try to find country-specific language first
3970 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3972 ide.languageItems[i].checked = true;
3980 // Try generalizing locale
3981 if(!found && language)
3984 char genericLocale[256];
3986 strncpy(genericLocale, language, sizeof(genericLocale));
3987 genericLocale[sizeof(genericLocale)-1] = 0;
3989 under = strchr(genericLocale, '_');
3992 if(!strcmpi(genericLocale, "zh"))
3993 strcpy(genericLocale, "zh_CN");
3994 if(strcmp(genericLocale, language))
3998 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
4000 ide.languageItems[i].checked = true;
4010 ide.languageItems[0].checked = true;
4012 MenuDivider { ide.languageMenu };
4015 ide.languageMenu, "Help Translate";
4017 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
4019 ShellOpen("http://translations.launchpad.net/ecere");
4025 ideMainFrame.Create();
4026 if(app.argFilesCount > 1)
4027 ide.MenuWindowTileVert(null, 0);
4031 bool Cycle(bool idle)
4035 if(ide.documentor.Peek())
4038 ide.documentor.GetLine(line, sizeof(line));
4039 if(!strcmpi(line, "Exited"))
4041 ide.documentor.CloseInput();
4042 ide.documentor.CloseOutput();
4043 ide.documentor.Wait();
4044 delete ide.documentor;
4047 if(ide.documentor && ide.documentor.eof)
4049 ide.documentor.CloseInput();
4050 ide.documentor.CloseOutput();
4051 ide.documentor.Wait();
4052 delete ide.documentor;
4058 bool LoadIncludeFile()
4060 bool result = false;
4061 File include = FileOpen(":crossplatform.mk", read);
4064 File f = includeFile;
4067 for(; !include.Eof(); )
4070 int count = include.Read(buffer, 1, 4096);
4071 f.Write(buffer, 1, count);
4081 IDEMainFrame ideMainFrame { };
4083 define app = ((IDEApp)__thisModule);
4085 define titleECEREIDE = $"Ecere IDE (Debug)";
4087 define titleECEREIDE = $"Ecere IDE";