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))
464 ce.font = { codeFont.faceName, codeFont.size, codeFont.bold, codeFont.italic };
465 ce.editBox.font = ce.font;
470 threadsView.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
471 callStackView.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
472 outputView.buildBox.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
473 outputView.debugBox.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
474 outputView.findBox.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
475 #ifdef GDB_DEBUG_OUTPUT
476 outputView.gdbBox.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
481 gdbDialog.tree.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
482 gdbDialog.output.font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
487 void ApplyColorScheme(IDEColorScheme cs)
493 for(ce = (CodeEditor)firstChild; ce; ce = (CodeEditor)ce.next)
494 if(ce._class == class(CodeEditor))
496 EditBox eb = ce.editBox;
497 ce.background = cs.marginColor;
498 eb.selectionColor = cs.selectionColor;
499 eb.selectionText = cs.selectionText;
500 eb.background = cs.codeEditorBG;
501 eb.foreground = cs.codeEditorFG;
502 eb.syntaxColorScheme = cs.syntaxColors;
507 projectView.fileList.background = cs.projectViewBackground;
508 projectView.fileList.foreground = cs.projectViewText;
509 projectView.fileList.selectionColor = cs.selectionColor;
510 projectView.fileList.selectionText = cs.selectionText;
513 sheet.properties.background = cs.viewsBackground;
514 sheet.properties.foreground = cs.viewsText;
515 sheet.properties.selectionText = cs.sheetSelectionText;
516 sheet.properties.selectionColor = cs.sheetSelectionColor;
517 sheet.methods.background = cs.viewsBackground;
518 sheet.methods.foreground = cs.viewsText;
520 threadsView.editBox.background = cs.viewsBackground;
521 threadsView.editBox.foreground = cs.viewsText;
522 threadsView.editBox.selectionColor = cs.selectionColor;
523 threadsView.editBox.selectionText = cs.selectionText;
525 callStackView.editBox.background = cs.viewsBackground;
526 callStackView.editBox.foreground = cs.viewsText;
527 callStackView.editBox.selectionColor = cs.selectionColor;
528 callStackView.editBox.selectionText = cs.selectionText;
530 watchesView.listBox.background = cs.viewsBackground;
531 watchesView.listBox.foreground = cs.viewsText;
532 watchesView.listBox.selectionColor = cs.selectionColor;
533 watchesView.listBox.selectionText = cs.selectionText;
535 breakpointsView.listBox.background = cs.viewsBackground;
536 breakpointsView.listBox.foreground = cs.viewsText;
537 breakpointsView.listBox.selectionColor = cs.selectionColor;
538 breakpointsView.listBox.selectionText = cs.selectionText;
540 outputView.buildBox.background = cs.outputBackground;
541 outputView.buildBox.foreground = cs.outputText;
542 outputView.buildBox.selectionColor = cs.selectionColor;
543 outputView.buildBox.selectionText = cs.selectionText;
545 outputView.debugBox.background = cs.outputBackground;
546 outputView.debugBox.foreground = cs.outputText;
547 outputView.debugBox.selectionColor = cs.selectionColor;
548 outputView.debugBox.selectionText = cs.selectionText;
550 outputView.findBox.background = cs.outputBackground;
551 outputView.findBox.foreground = cs.outputText;
552 outputView.findBox.selectionColor = cs.selectionColor;
553 outputView.findBox.selectionText = cs.selectionText;
556 ProjectView projectView;
558 OutputView outputView
562 void OnGotoError(const char * line, bool noParsing)
564 CompilerConfig compiler = ide.workspace ? ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler) : null;
565 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
566 ide.GoToError(line, noParsing, objectFileExt);
570 void OnCodeLocationParseAndGoTo(const char * line)
572 CompilerConfig compiler = ide.workspace ? ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler) : null;
573 const char * objectFileExt = compiler ? compiler.objectFileExt : objectDefaultFileExt;
574 ide.CodeLocationParseAndGoTo(line, ide.findInFilesDialog.findProject, ide.findInFilesDialog.findDir, objectFileExt);
578 bool OnKeyDown(Key key, unichar ch)
583 if(activeBox != findBox || !ide.findInFilesDialog || !ide.findInFilesDialog.SearchAbort())
584 ide.ShowCodeEditor();
588 OutputView::OnKeyDown(key, ch);
595 bool OnClose(bool parentClosing)
599 ide.RepositionWindows(false);
600 return parentClosing;
604 CallStackView callStackView
606 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
608 void OnSelectFrame(int frameIndex)
610 ide.debugger.GoToStackFrameLine(frameIndex, true, true);
612 ide.debugger.SelectFrame(frameIndex);
615 void OnToggleBreakpoint()
617 Debugger debugger = ide.debugger;
618 if(debugger.activeFrame && debugger.activeFrame.absoluteFile)
620 int line = debugger.activeFrame.line;
621 debugger.ToggleBreakpoint(debugger.activeFrame.absoluteFile, line);
624 CodeEditor codeEditor = (CodeEditor)ide.FindWindow(debugger.activeFrame.absoluteFile);
625 if(codeEditor) { codeEditor.Update(null); Activate(); }
630 bool OnKeyDown(Key key, unichar ch)
634 case escape: ide.ShowCodeEditor(); break;
639 bool OnClose(bool parentClosing)
643 ide.RepositionWindows(false);
644 return parentClosing;
647 void OnRedraw(Surface surface)
649 Debugger debugger = ide.debugger;
650 Frame activeFrame = debugger.activeFrame;
654 int lineCursor, lineTopFrame;
655 int lineH, scrollY, boxH;
657 Breakpoint bp = null;
660 scrollY = editBox.scroll.y;
661 displaySystem.FontExtent(editBox.font.font, " ", 1, null, &lineH);
662 //activeThread = debugger.activeThread;
663 //hitThread = debugger.hitThread;
664 debugger.GetCallStackCursorLine(&error, &lineCursor, &lineTopFrame);
666 // TODO: improve bp drawing... it should be visible even if it's not on the activeFrame
667 if(activeFrame.absoluteFile)
669 for(i : ide.workspace.breakpoints; i.type == user)
671 if(i.absoluteFilePath && i.absoluteFilePath[0] &&
672 !fstrcmp(i.absoluteFilePath, activeFrame.absoluteFile) &&
673 activeFrame.line == i.line)
681 DrawLineMarginIcon(surface,
682 /*(lineCursor == 1 || lineTopFrame == 1) ? */ide.bmpBpHalf/* : ide.bmpBp*/,
683 lineCursor /*1*/, lineH, scrollY, boxH);
685 if(activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
686 DrawLineMarginIcon(surface,
687 (lineCursor == 1 || lineTopFrame == 1) ? ide.bmpBpHalf : ide.bmpBp,
688 1, lineH, scrollY, boxH);
690 DrawLineMarginIcon(surface, error ? ide.bmpCursorError : ide.bmpCursor, lineCursor, lineH, scrollY, boxH);
691 if(bp && lineCursor == 1) //activeThread && activeThread == hitThread && debugger.bpHit && debugger.bpHit.type == user)
692 bmp = error ? ide.bmpTopFrameHalfError : ide.bmpTopFrameHalf;
694 bmp = error ? ide.bmpTopFrameError : ide.bmpTopFrame;
695 DrawLineMarginIcon(surface, bmp, lineTopFrame, lineH, scrollY, boxH);
697 if(editBox.horzScroll && editBox.horzScroll.visible)
699 surface.SetBackground(control);
700 surface.Area(0, editBox.clientSize.h, 20 - 1, clientSize.h - 1);
705 WatchesView watchesView { parent = this };
706 ThreadsView threadsView
708 parent = this, font = { panelFont.faceName, panelFont.size, panelFont.bold, panelFont.italic };
710 bool OnKeyDown(Key key, unichar ch)
714 case escape: ide.ShowCodeEditor(); break;
719 bool OnClose(bool parentClosing)
723 ide.RepositionWindows(false);
724 return parentClosing;
727 void OnSelectThread(int threadId)
730 ide.debugger.SelectThread(threadId);
733 bool OnGetThreadsInfo(int * activeThread, int * hitThread, int * signalThread)
736 Debugger debugger = ide.debugger;
737 *activeThread = debugger.activeThread;
738 *hitThread = debugger.hitThread;
739 *signalThread = debugger.signalThread;
744 BreakpointsView breakpointsView { parent = this };
746 ToolBox toolBox { parent = this, visible = false };
747 Sheet sheet { parent = this, visible = false };
750 property char * tmpPrjDir { set { delete tmpPrjDir; if(value) tmpPrjDir = CopyString(value); } get { return tmpPrjDir; } };
752 Menu fileMenu { menu, $"File", f, hasMargin = true };
755 fileMenu, $"New", n, ctrlN;
756 bitmap = { ":actions/docNew.png" };
757 bool NotifySelect(MenuItem selection, Modifiers mods)
759 Window currentDoc = activeClient;
760 bool maximizeDoc = ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
761 Window document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, false);
762 RepositionWindows(false);
763 document.NotifySaved = DocumentSaved;
767 MenuItem fileOpenItem
769 fileMenu, $"Open...", o, ctrlO;
770 bitmap = { ":actions/docOpen.png" };
771 bool NotifySelect(MenuItem selection, Modifiers mods)
773 if(!projectView && ideSettings.ideFileDialogLocation)
774 ideFileDialog.currentDirectory = ideSettings.ideFileDialogLocation;
777 if(ideFileDialog.Modal() == ok)
779 bool gotWhatWeWant = false;
781 int numSelections = ideFileDialog.numSelections;
782 const char * const * multiFilePaths = ideFileDialog.multiFilePaths;
784 for(c = 0; c < numSelections; c++)
786 if(OpenFile(multiFilePaths[c], false, true, fileTypes[ideFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift))
787 gotWhatWeWant = true;
790 MessageBox { type = yesNo, master = this, text = $"Error opening file",
791 contents = $"Open a different file?" }.Modal() == no)
793 if(!projectView && gotWhatWeWant)
794 ChangeFileDialogsDirectory(ideFileDialog.currentDirectory, true);
795 ide.RepositionWindows(false);
805 MenuItem fileCloseItem { fileMenu, $"Close", c, ctrlF4, NotifySelect = MenuFileClose };
806 MenuDivider { fileMenu };
807 MenuItem fileSaveItem
809 fileMenu, $"Save", s, ctrlS, bitmap = { ":actions/docSave.png" };
811 // For the toolbar button; clients can still override that for the menu item
812 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
814 Window w = activeClient;
816 w.MenuFileSave(null, 0);
820 MenuItem fileSaveAsItem { fileMenu, $"Save As...", a };
821 MenuItem fileSaveAllItem { fileMenu, $"Save All", l, NotifySelect = MenuFileSaveAll, bitmap = { ":actions/docSaveAll.png" } };
822 MenuDivider { fileMenu };
825 fileMenu, $"Find In Files...", f, Key { f, ctrl = true , shift = true };
826 bool NotifySelect(MenuItem selection, Modifiers mods)
828 findInFilesDialog.replaceMode = false;
829 findInFilesDialog.Show();
833 MenuItem replaceInFiles
835 fileMenu, $"Replace In Files...", e, Key { r, ctrl = true , shift = true };
836 bool NotifySelect(MenuItem selection, Modifiers mods)
838 findInFilesDialog.replaceMode = true;
839 findInFilesDialog.Show();
843 MenuDivider { fileMenu };
844 MenuItem globalSettingsItem
846 fileMenu, $"Global Settings...", g;
847 bool NotifySelect(MenuItem selection, Modifiers mods)
849 // Reload configs here until we setup a configs directory monitor
850 ideConfig.compilers.read(settingsContainer);
852 globalSettingsDialog.master = this;
853 if(ide.workspace && ide.workspace.activeCompiler)
854 globalSettingsDialog.workspaceActiveCompiler = ide.workspace.activeCompiler;
855 else if(ideSettings.defaultCompiler)
856 globalSettingsDialog.workspaceActiveCompiler = ideSettings.defaultCompiler;
857 globalSettingsDialog.Modal();
861 MenuDivider { fileMenu };
862 Menu recentFilesMenu { fileMenu, $"Recent Files", r };
863 Menu recentProjectsMenu { fileMenu, $"Recent Projects", p };
864 MenuDivider { fileMenu };
867 fileMenu, $"Exit", x, altF4;
869 bool NotifySelect(MenuItem selection, Modifiers mods)
871 ideMainFrame.Destroy(0);
876 bool FileRecentFile(MenuItem selection, Modifiers mods)
879 RecentPaths recentFiles = workspace ? workspace.recentFiles : ideConfig.recentFiles;
880 for(file : recentFiles)
882 if(id == selection.id)
885 char extension[MAX_EXTENSION] = "";
886 GetExtension(file, extension);
887 isProjectFile = (!strcmpi(extension, "epj") || !strcmpi(extension, "ews"));
888 if(mods.ctrl && !mods.shift)
890 char * command = PrintString("ecere-ide ", isProjectFile ? "-t " : "", file);
896 OpenFile(file, false, true, isProjectFile ? "txt" : null, no, normal, mods.ctrl && mods.shift);
897 ide.RepositionWindows(false);
906 bool FileRecentProject(MenuItem selection, Modifiers mods)
909 for(file : ideConfig.recentWorkspaces)
911 if(id == selection.id)
913 if(mods.ctrl && !mods.shift)
915 char * command = PrintString("ecere-ide ", file);
920 OpenFile(file, false, true, (mods.ctrl && mods.shift) ? "txt" : null, no, normal, mods.ctrl && mods.shift);
928 MenuPlacement editMenu { menu, $"Edit", e };
930 Menu projectMenu { menu, $"Menu"."Project", p, hasMargin = true };
931 MenuItem projectNewItem
933 projectMenu, $"New...", n, Key { n, true, true };
934 bitmap = { ":actions/projNew.png" };
935 bool NotifySelect(MenuItem selection, Modifiers mods)
937 if(!DontTerminateDebugSession($"New Project"))
940 NewProjectDialog newProjectDialog { master = this };
941 incref newProjectDialog;
942 result = newProjectDialog.Modal();
947 newProjectDialog.CreateNewProject();
950 ideConfig.recentWorkspaces.addRecent(projectView.fileName);
951 ideConfig.recentWorkspaces.write(settingsContainer);
952 ide.updateRecentProjectsMenu();
956 delete newProjectDialog;
961 MenuItem projectOpenItem
963 projectMenu, $"Open...", o, Key { o, true, true };
964 bitmap = { ":actions/projOpen.png" };
965 bool NotifySelect(MenuItem selection, Modifiers mods)
967 if(ideSettings.ideProjectFileDialogLocation)
968 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
970 ideProjectFileDialog.text = openProjectFileDialogTitle;
971 if(ideProjectFileDialog.Modal() == ok)
973 OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, normal, mods.ctrl && mods.shift);
974 //ChangeProjectFileDialogDirectory(ideProjectFileDialog.currentDirectory);
979 MenuItem projectQuickItem
981 projectMenu, $"Quick...", q, f7, disabled = true;
982 bool NotifySelect(MenuItem selection, Modifiers mods)
985 QuickProjectDialog { this }.Modal();
989 MenuItem projectAddItem
991 projectMenu, $"Add project to workspace...", a, Key { a, true, true };
992 bitmap = { ":actions/projAdd.png" };
994 bool NotifySelect(MenuItem selection, Modifiers mods)
996 if(ideSettings.ideProjectFileDialogLocation)
997 ideProjectFileDialog.currentDirectory = ideSettings.ideProjectFileDialogLocation;
999 ideProjectFileDialog.text = addProjectFileDialogTitle;
1002 if(ideProjectFileDialog.Modal() == ok)
1004 if(OpenFile(ideProjectFileDialog.filePath, false, true, projectTypes[ideProjectFileDialog.fileType].typeExtension, no, add, mods.ctrl && mods.shift))
1006 if(MessageBox { type = yesNo, master = this, text = $"Error opening project file",
1007 contents = $"Add a different project?" }.Modal() == no)
1018 MenuItem projectCloseItem
1020 projectMenu, $"Close", c, disabled = true;
1021 bool NotifySelect(MenuItem selection, Modifiers mods)
1025 if(!ide.DontTerminateDebugSession($"Project Close"))
1031 MenuDivider { projectMenu };
1032 MenuItem projectSettingsItem
1034 projectMenu, $"Settings...", s, altF7, disabled = true;
1035 bool NotifySelect(MenuItem selection, Modifiers mods)
1037 projectView.MenuSettings(projectView.active ? selection : null, mods);
1041 MenuDivider { projectMenu };
1042 MenuItem projectBrowseFolderItem
1044 projectMenu, $"Browse Project Folder", p, disabled = true;
1045 bool NotifySelect(MenuItem selection, Modifiers mods)
1048 projectView.MenuBrowseFolder(null, mods);
1052 MenuDivider { projectMenu };
1053 MenuItem projectRunItem
1055 projectMenu, $"Run", r, ctrlF5, disabled = true;
1056 bitmap = { ":actions/run.png" };
1057 bool NotifySelect(MenuItem selection, Modifiers mods)
1060 projectView.Run(null, mods);
1064 MenuItem projectBuildItem
1066 projectMenu, $"Build", b, f7, disabled = true;
1067 bitmap = { ":actions/build.png" };
1068 bool NotifySelect(MenuItem selection, Modifiers mods)
1072 if(projectView.buildInProgress == none)
1073 projectView.ProjectBuild(projectView.active ? selection : null, mods);
1075 projectView.stopBuild = true;
1080 MenuItem projectLinkItem
1082 projectMenu, $"Relink", l, disabled = true;
1083 bitmap = { ":actions/relink.png" };
1084 bool NotifySelect(MenuItem selection, Modifiers mods)
1087 projectView.ProjectLink(projectView.active ? selection : null, mods);
1091 MenuItem projectRebuildItem
1093 projectMenu, $"Rebuild", d, shiftF7, disabled = true;
1094 bitmap = { ":actions/rebuild.png" };
1095 bool NotifySelect(MenuItem selection, Modifiers mods)
1098 projectView.ProjectRebuild(projectView.active ? selection : null, mods);
1102 MenuItem projectCleanTargetItem
1104 projectMenu, $"Clean Target", g, disabled = true;
1105 bitmap = { ":actions/clean.png" };
1106 bool NotifySelect(MenuItem selection, Modifiers mods)
1111 projectView.ProjectCleanTarget(projectView.active ? selection : null, mods);
1116 MenuItem projectCleanItem
1118 projectMenu, $"Clean", e, disabled = true;
1119 bitmap = { ":actions/clean.png" };
1120 bool NotifySelect(MenuItem selection, Modifiers mods)
1125 projectView.ProjectClean(projectView.active ? selection : null, mods);
1130 MenuItem projectRealCleanItem
1132 projectMenu, $"Real Clean", disabled = true;
1133 bitmap = { ":actions/clean.png" };
1134 bool NotifySelect(MenuItem selection, Modifiers mods)
1139 projectView.ProjectRealClean(projectView.active ? selection : null, mods);
1144 MenuItem projectRegenerateItem
1146 projectMenu, $"Regenerate Makefile", m, disabled = true;
1147 bitmap = { ":actions/regMakefile.png" };
1148 bool NotifySelect(MenuItem selection, Modifiers mods)
1151 projectView.ProjectRegenerate(projectView.active ? selection : null, mods);
1155 MenuItem projectInstallItem
1157 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
1158 projectMenu, $"Install", t, disabled = true;
1160 bitmap = { ":status/software-update-available.png" };
1161 bool NotifySelect(MenuItem selection, Modifiers mods)
1164 projectView.ProjectInstall(projectView.active ? selection : null, mods);
1168 MenuItem projectCompileItem;
1169 Menu debugMenu { menu, $"Debug", d, hasMargin = true };
1170 MenuItem debugStartResumeItem
1172 debugMenu, $"Start", s, f5, disabled = true;
1173 bitmap = { ":actions/debug.png" };
1174 NotifySelect = MenuDebugStart;
1176 bool MenuDebugStart(MenuItem selection, Modifiers mods)
1180 debugStartResumeItem.disabled = true; // a very rare exception to calling AdjustDebugMenus
1181 if(!projectView.DebugStart())
1182 debugStartResumeItem.disabled = false; // same exception
1186 bool MenuDebugResume(MenuItem selection, Modifiers mods)
1189 projectView.DebugResume();
1192 MenuItem debugRestartItem
1194 debugMenu, $"Restart", r, Key { f5, ctrl = true, shift = true }, disabled = true;
1195 bitmap = { ":actions/restart.png" };
1196 bool NotifySelect(MenuItem selection, Modifiers mods)
1199 projectView.DebugRestart();
1203 MenuItem debugBreakItem
1205 debugMenu, $"Break", b, Key { pauseBreak, ctrl = true }, disabled = true;
1206 bitmap = { ":actions/pause.png" };
1207 bool NotifySelect(MenuItem selection, Modifiers mods)
1209 if(projectView && projectView.buildInProgress != none)
1212 projectView.DebugBreak();
1216 MenuItem debugStopItem
1218 debugMenu, $"Stop", p, shiftF5, disabled = true;
1219 bitmap = { ":actions/stopDebug.png" };
1220 bool NotifySelect(MenuItem selection, Modifiers mods)
1223 projectView.DebugStop();
1227 MenuDivider { debugMenu };
1231 // nonClient = true,
1238 anchor = { right = 0, bottom = 0 },
1240 isActiveClient = false,
1242 clickThrough = true,
1243 size = { 500, 500 };
1245 bool OnLoadGraphics()
1247 ModelView::OnLoadGraphics();
1248 camera.position.z /= 1.3;
1249 camera.orientation = Euler { yaw = 280, pitch = 20 };
1255 bool OnRightButtonDown(int x, int y, Modifiers mods)
1257 if(!displaySystem.flags.flipping) return true;
1258 MenuWindowMove(null, 0);
1262 bool OnRightButtonUp(int x, int y, Modifiers mods)
1264 position = position;
1269 MenuItem debugRubberDuck
1271 debugMenu, $"Rubber Duck", checkable = true, disabled = true;
1272 bool NotifySelect(MenuItem selection, Modifiers mods)
1274 if(selection.checked)
1282 MenuDivider { debugMenu };
1283 MenuItem debugUseValgrindItem
1285 debugMenu, $"Use Valgrind", d, disabled = true, checkable = true;
1286 bool NotifySelect(MenuItem selection, Modifiers mods)
1290 ide.workspace.useValgrind = selection.checked;
1291 ide.workspace.Save();
1293 ide.AdjustValgrindMenus();
1297 Menu debugValgrindLeakCheckItem { debugMenu, $"Valgrind Leak Check", h };
1298 MenuItem debugValgrindNoLeakCheckItem { debugValgrindLeakCheckItem, $"No" , f, id = ValgrindLeakCheck::no , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1299 MenuItem debugValgrindSummaryLeakCheckItem { debugValgrindLeakCheckItem, $"Summary", f, id = ValgrindLeakCheck::summary, checkable = true, disabled = true; NotifySelect = ValgrindLCSelect, checked = true; };
1300 MenuItem debugValgrindYesLeakCheckItem { debugValgrindLeakCheckItem, $"Yes" , f, id = ValgrindLeakCheck::yes , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1301 MenuItem debugValgrindFullLeakCheckItem { debugValgrindLeakCheckItem, $"Full" , f, id = ValgrindLeakCheck::full , checkable = true, disabled = true; NotifySelect = ValgrindLCSelect; };
1302 bool ValgrindLCSelect(MenuItem selection, Modifiers mods)
1306 if(selection.checked)
1308 ValgrindLeakCheck vgLeakCheck = (ValgrindLeakCheck)selection.id;
1310 debugValgrindNoLeakCheckItem.checked = debugValgrindNoLeakCheckItem.id == vgLeakCheck;
1311 debugValgrindSummaryLeakCheckItem.checked = debugValgrindSummaryLeakCheckItem.id == vgLeakCheck;
1312 debugValgrindYesLeakCheckItem.checked = debugValgrindYesLeakCheckItem.id == vgLeakCheck;
1313 debugValgrindFullLeakCheckItem.checked = debugValgrindFullLeakCheckItem.id == vgLeakCheck;
1315 ide.workspace.vgLeakCheck = vgLeakCheck;
1316 ide.workspace.Save();
1319 selection.checked = true;
1323 Menu debugValgrindRedzoneSizeItem { debugMenu, $"Valgrind Redzone Size", z };
1324 MenuItem debugValgrindRSDefaultItem { debugValgrindRedzoneSizeItem, $"Default", f, id = -1, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect, checked = true; };
1325 MenuItem debugValgrindRS0Item { debugValgrindRedzoneSizeItem, "0" , f, id = 0, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1326 MenuItem debugValgrindRS16Item { debugValgrindRedzoneSizeItem, "16" , f, id = 16, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1327 MenuItem debugValgrindRS32Item { debugValgrindRedzoneSizeItem, "32" , f, id = 32, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1328 MenuItem debugValgrindRS64Item { debugValgrindRedzoneSizeItem, "64" , f, id = 64, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1329 MenuItem debugValgrindRS128Item { debugValgrindRedzoneSizeItem, "128" , f, id = 128, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1330 MenuItem debugValgrindRS256Item { debugValgrindRedzoneSizeItem, "256" , f, id = 256, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1331 MenuItem debugValgrindRS512Item { debugValgrindRedzoneSizeItem, "512" , f, id = 512, checkable = true, disabled = true; NotifySelect = ValgrindRSSelect; };
1332 bool ValgrindRSSelect(MenuItem selection, Modifiers mods)
1336 if(selection.checked)
1338 int vgRedzoneSize = (int)selection.id;
1340 debugValgrindRSDefaultItem.checked = debugValgrindRSDefaultItem.id == vgRedzoneSize;
1341 debugValgrindRS0Item.checked = debugValgrindRS0Item.id == vgRedzoneSize;
1342 debugValgrindRS16Item.checked = debugValgrindRS16Item.id == vgRedzoneSize;
1343 debugValgrindRS32Item.checked = debugValgrindRS32Item.id == vgRedzoneSize;
1344 debugValgrindRS64Item.checked = debugValgrindRS64Item.id == vgRedzoneSize;
1345 debugValgrindRS128Item.checked = debugValgrindRS128Item.id == vgRedzoneSize;
1346 debugValgrindRS256Item.checked = debugValgrindRS256Item.id == vgRedzoneSize;
1347 debugValgrindRS512Item.checked = debugValgrindRS512Item.id == vgRedzoneSize;
1349 ide.workspace.vgRedzoneSize = vgRedzoneSize;
1350 ide.workspace.Save();
1353 selection.checked = true;
1357 MenuItem debugValgrindTrackOriginsItem
1359 debugMenu, $"Valgrind Track Origins", k, checkable = true, disabled = true;
1360 bool NotifySelect(MenuItem selection, Modifiers mods)
1364 ide.workspace.vgTrackOrigins = selection.checked;
1365 ide.workspace.Save();
1371 MenuDivider { debugMenu };
1372 MenuItem debugStepIntoItem
1374 debugMenu, $"Step Into", i, f11, disabled = true;
1375 bitmap = { ":actions/stepInto.png" };
1376 bool NotifySelect(MenuItem selection, Modifiers mods)
1378 if(projectView) projectView.DebugStepInto();
1382 MenuItem debugStepOverItem
1384 debugMenu, $"Step Over", v, f10, disabled = true;
1385 bitmap = { ":actions/stepOver.png" };
1386 bool NotifySelect(MenuItem selection, Modifiers mods)
1388 if(projectView) projectView.DebugStepOver(false);
1392 MenuItem debugSkipStepOverItem
1394 debugMenu, $"Step Over Skipping Breakpoints", e, shiftF10, disabled = true;
1395 bitmap = { ":actions/stepOverSkipBreak.png" };
1396 bool NotifySelect(MenuItem selection, Modifiers mods)
1398 if(projectView) projectView.DebugStepOver(true);
1402 MenuItem debugStepOutItem
1404 debugMenu, $"Step Out", o, shiftF11, disabled = true;
1405 bitmap = { ":actions/stepOut.png" };
1406 bool NotifySelect(MenuItem selection, Modifiers mods)
1408 if(projectView) projectView.DebugStepOut(false);
1412 MenuItem debugSkipStepOutItem
1414 debugMenu, $"Step Out Skipping Breakpoints", n, Key { f11, ctrl = true, shift = true }, disabled = true;
1415 bitmap = { ":actions/skipBreaks.png" };
1416 bool NotifySelect(MenuItem selection, Modifiers mods)
1418 if(projectView) projectView.DebugStepOut(true);
1423 MenuItem debugStepUntilItem
1425 debugMenu, $"Step Over Until Next Line", x, disabled = true;
1426 bool NotifySelect(MenuItem selection, Modifiers mods)
1428 if(projectView) projectView.DebugStepUntil(false);
1432 MenuItem debugSkipStepUntilItem
1434 debugMenu, $"Step Over Until Next Line Skipping Breakpoints", e, Key { f10, shift = true, alt = true }, disabled = true;
1435 bool NotifySelect(MenuItem selection, Modifiers mods)
1437 if(projectView) projectView.DebugStepUntil(true);
1442 MenuPlacement debugRunToCursorItem { debugMenu, $"Run To Cursor", c };
1443 MenuPlacement debugSkipRunToCursorItem { debugMenu, $"Run To Cursor Skipping Breakpoints", u };
1444 MenuPlacement debugRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level", l };
1445 MenuPlacement debugSkipRunToCursorAtSameLevelItem { debugMenu, $"Run To Cursor At Same Level Skipping Breakpoints", g };
1447 MenuPlacement debugBpRunToCursorItem { debugMenu, $"BP Run To Cursor" };
1448 MenuPlacement debugBpSkipRunToCursorItem { debugMenu, $"BP Run To Cursor Skipping Breakpoints" };
1449 MenuPlacement debugBpRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level" };
1450 MenuPlacement debugBpSkipRunToCursorAtSameLevelItem { debugMenu, $"BP Run To Cursor At Same Level Skipping Breakpoints" };
1452 //MenuDivider { debugMenu };
1453 //MenuPlacement debugToggleBreakpoint { debugMenu, "Toggle Breakpoint", t };
1454 MenuPlacement imageMenu { menu, $"Image", i };
1455 Menu viewMenu { menu, $"View", v };
1456 MenuItem viewProjectItem
1458 viewMenu, $"Project View", j, alt0, disabled = true;
1459 bool NotifySelect(MenuItem selection, Modifiers mods)
1463 projectView.visible = true;
1464 projectView.Activate();
1469 MenuPlacement { viewMenu, $"View Designer" };
1470 MenuPlacement { viewMenu, $"View Code" };
1471 MenuPlacement { viewMenu, $"View Properties" };
1472 MenuPlacement { viewMenu, $"View Methods" };
1473 MenuItem viewDesignerItem
1475 viewMenu, $"View Designer", d, f8;
1476 bool NotifySelect(MenuItem selection, Modifiers mods)
1478 Window client = activeClient;
1479 Class dataType = client._class;
1480 if(!strcmp(dataType.name, "Designer"))
1482 client.visible = true;
1486 ((CodeEditor)client).ViewDesigner();
1490 MenuItem viewCodeItem
1492 viewMenu, $"View Code", c, f8;
1493 bool NotifySelect(MenuItem selection, Modifiers mods)
1495 Window client = activeClient;
1496 Class dataType = client._class;
1497 if(!strcmp(dataType.name, "Designer"))
1498 client = ((Designer)client).codeEditor;
1501 // Do this after so the caret isn't moved yet...
1502 client.visible = true;
1506 MenuItem viewPropertiesItem
1508 viewMenu, $"View Properties", p, f4;
1509 bool NotifySelect(MenuItem selection, Modifiers mods)
1511 sheet.visible = true;
1512 sheet.sheetSelected = properties;
1517 MenuItem viewMethodsItem
1519 viewMenu, $"View Methods", m, f4;
1520 bool NotifySelect(MenuItem selection, Modifiers mods)
1522 sheet.visible = true;
1523 sheet.sheetSelected = methods;
1528 MenuItem viewToolBoxItem
1530 viewMenu, $"View Toolbox", x, f12;
1531 bool NotifySelect(MenuItem selection, Modifiers mods)
1533 toolBox.visible = true;
1538 MenuItem viewOutputItem
1540 viewMenu, $"Output", o, alt2;
1541 bool NotifySelect(MenuItem selection, Modifiers mods)
1547 MenuItem viewWatchesItem
1549 viewMenu, $"Watches", w, alt3;
1550 bool NotifySelect(MenuItem selection, Modifiers mods)
1556 MenuItem viewThreadsItem
1558 viewMenu, $"Threads", t, alt4;
1559 bool NotifySelect(MenuItem selection, Modifiers mods)
1565 MenuItem viewBreakpointsItem
1567 viewMenu, $"Breakpoints", b, alt5;
1568 bool NotifySelect(MenuItem selection, Modifiers mods)
1570 breakpointsView.Show();
1574 MenuItem viewCallStackItem
1576 viewMenu, $"Call Stack", s, alt7;
1577 bool NotifySelect(MenuItem selection, Modifiers mods)
1579 callStackView.Show();
1583 MenuItem viewAllDebugViews
1585 viewMenu, $"All Debug Views", a, alt9;
1586 bool NotifySelect(MenuItem selection, Modifiers mods)
1591 callStackView.Show();
1592 breakpointsView.Show();
1596 #ifdef GDB_DEBUG_GUI
1597 MenuDivider { viewMenu };
1598 MenuItem viewGDBItem
1600 viewMenu, $"GDB Dialog", g, Key { f9, shift = true, ctrl = true };
1601 bool NotifySelect(MenuItem selection, Modifiers mods)
1608 MenuDivider { viewMenu };
1609 MenuItem viewColorPicker
1611 viewMenu, $"Color Picker...", c, Key { c, ctrl = true , shift = true };
1612 bool NotifySelect(MenuItem selection, Modifiers mods)
1614 ColorPicker colorPicker { master = this };
1615 colorPicker.Modal();
1619 MenuDivider { viewMenu };
1623 viewMenu, "Full Screen", f, checkable = true;
1625 bool NotifySelect(MenuItem selection, Modifiers mods)
1627 app.fullScreen ^= true;
1629 anchor = { 0, 0, 0, 0 };
1634 Menu driversMenu { viewMenu, $"Graphics Driver", v };
1636 MenuDivider { viewMenu };
1638 Menu languageMenu { viewMenu, "Language", l };
1640 //Menu skinsMenu { viewMenu, "GUI Skins", k };
1641 Menu windowMenu { menu, $"Window", w };
1642 MenuItem { windowMenu, $"Close All", l, NotifySelect = MenuWindowCloseAll };
1643 MenuDivider { windowMenu };
1644 MenuItem { windowMenu, $"Next", n, f6, NotifySelect = MenuWindowNext };
1645 MenuItem { windowMenu, $"Previous", p, shiftF6, NotifySelect = MenuWindowPrevious };
1646 MenuDivider { windowMenu };
1647 MenuItem { windowMenu, $"Cascade", c, NotifySelect = MenuWindowCascade };
1648 MenuItem { windowMenu, $"Tile Horizontally", h, NotifySelect = MenuWindowTileHorz };
1649 MenuItem { windowMenu, $"Tile Vertically", v, NotifySelect = MenuWindowTileVert };
1650 MenuItem { windowMenu, $"Arrange Icons", a, NotifySelect = MenuWindowArrangeIcons };
1651 MenuDivider { windowMenu };
1652 MenuItem { windowMenu, $"Windows...", w, NotifySelect = MenuWindowWindows };
1653 Menu helpMenu { menu, $"Help", h };
1656 helpMenu, $"API Reference", r, f1;
1657 bool NotifySelect(MenuItem selection, Modifiers mods)
1661 char * p = new char[MAX_LOCATION];
1663 strncpy(p, settingsContainer.moduleLocation, MAX_LOCATION); p[MAX_LOCATION-1] = '\0';
1664 PathCat(p, "documentor");
1665 #if defined(__WIN32__)
1666 ChangeExtension(p, "exe", p);
1668 if(!FileExists(p).isFile)
1669 strcpy(p, "documentor");
1671 documentor = DualPipeOpen({ input = true, output = true, showWindow = true }, p);
1676 Process_ShowWindows(documentor.GetProcessID());
1677 // documentor.Puts("Activate\n");
1682 MenuDivider { helpMenu };
1685 helpMenu, $"Ecere Tao of Programming [work in progress]", t;
1686 bool NotifySelect(MenuItem selection, Modifiers mods)
1688 FindAndShellOpenInstalledFile("doc", "Ecere Tao of Programming [work in progress].pdf");
1692 MenuDivider { helpMenu };
1695 helpMenu, $"Documentation Folder", d;
1696 bool NotifySelect(MenuItem selection, Modifiers mods)
1698 FindAndShellOpenInstalledFolder("doc");
1704 helpMenu, $"Samples Folder", s;
1705 bool NotifySelect(MenuItem selection, Modifiers mods)
1707 FindAndShellOpenInstalledFolder("samples");
1713 helpMenu, $"Extras Folder", x;
1714 bool NotifySelect(MenuItem selection, Modifiers mods)
1716 FindAndShellOpenInstalledFolder("extras");
1720 MenuDivider { helpMenu };
1723 helpMenu, $"Community Forums", f;
1724 bool NotifySelect(MenuItem selection, Modifiers mods)
1726 ShellOpen("http://ecere.com/forums");
1730 MenuDivider { helpMenu };
1733 helpMenu, $"About...", a;
1734 bool NotifySelect(MenuItem selection, Modifiers mods)
1736 AboutIDE { master = this }.Modal();
1741 property ToolBox toolBox
1743 get { return toolBox; }
1746 property Sheet sheet
1748 get { return sheet; }
1751 property Project project
1753 get { return projectView ? projectView.project : null; }
1756 property Workspace workspace
1758 get { return projectView ? projectView.workspace : null; }
1761 FindInFilesDialog findInFilesDialog
1764 filters = findInFilesFileFilters.array, sizeFilters = findInFilesFileFilters.count * sizeof(FileFilter);
1771 #ifdef GDB_DEBUG_GUI
1774 master = this, parent = this;
1775 //anchor = { left = 100, top = 100, right = 100, bottom = 100 };
1777 void OnCommand(const char * string)
1780 ide.debugger.SendGDBCommand(string);
1785 bool NotifySelectDisplayDriver(MenuItem selection, Modifiers mods)
1787 //app.driver = app.drivers[selection.id];
1788 #if defined(__unix__) || defined(__APPLE__)
1789 app.driver = selection.id ? "OpenGL" : "X";
1791 app.driver = selection.id ? "OpenGL" : "GDI";
1793 delete ideSettings.displayDriver;
1794 ideSettings.displayDriver = CopyString(selection.id ? "OpenGL" : "Default");
1796 ide.debugRubberDuck.disabled = !ide.duck.modelFile || strcmpi(app.driver, "OpenGL");
1798 settingsContainer.Save();
1799 //SetDriverAndSkin();
1803 bool NotifySelectDisplaySkin(MenuItem selection, Modifiers mods)
1805 app.skin = app.skins[selection.id];
1810 void SetDriverAndSkin()
1813 for(c = 0; c < app.numSkins; c++)
1814 if(!strcmp(app.skins[c], app.skin))
1816 skinItems[c].checked = true;
1819 for(c = 0; c < app.numDrivers; c++)
1820 if(!strcmp(app.drivers[c], app.driver))
1822 driverItems[c].checked = true;
1827 ProjectView CreateProjectView(Workspace workspace, const char * fileName)
1829 Project project = workspace.projects.firstIterator.data;
1830 projectView = ProjectView
1833 fileName = fileName;
1835 void NotifyDestroyed(Window window, DialogResult result)
1838 text = titleECEREIDE;
1843 projectView.Create();
1844 RepositionWindows(false);
1846 // Leave it after Create to avoid flicker due to seeing IDE without a project view
1847 projectView.workspace = workspace;
1848 projectView.project = project;
1849 ideMainFrame.SetText("%s - %s", project.topNode.name, titleECEREIDE);
1852 updateRecentMenus();
1854 ide.breakpointsView.LoadFromWorkspace();
1855 ide.watchesView.LoadFromWorkspace();
1857 findInFilesDialog.projectNodeField.userData = projectView;
1860 char fileName[MAX_LOCATION];
1861 strcpy(fileName, project.topNode.path);
1862 PathCat(fileName, project.topNode.name);
1869 projectView.visible = false;
1870 if((!projectView || projectView.created == false || projectView.Destroy(0)) && MenuWindowCloseAll(null, 0))
1872 if(findInFilesDialog)
1874 char workingDir[MAX_LOCATION];
1875 GetWorkingDir(workingDir, MAX_LOCATION);
1876 findInFilesDialog.SearchStop();
1877 findInFilesDialog.currentDirectory = workingDir;
1879 sheet.visible = false;
1880 toolBox.visible = false;
1881 outputView.visible = false;
1882 ideMainFrame.text = titleECEREIDE;
1884 ide.updateRecentMenus();
1890 void RepositionWindows(bool expand)
1895 bool callStackVisible = expand ? false : callStackView.visible;
1896 bool threadsVisible = expand ? false : threadsView.visible;
1897 bool watchesVisible = expand ? false : watchesView.visible;
1898 bool breakpointsVisible = expand ? false : breakpointsView.visible;
1899 bool toolBoxVisible = toolBox.visible;
1900 bool outputVisible = expand ? false : outputView.visible;
1901 int topDistance = (callStackVisible || threadsVisible) ? 200 : 0;
1902 int bottomDistance = (outputVisible || watchesVisible || breakpointsVisible) ? 240 : 0;
1904 for(child = firstChild; child; child = child.next)
1906 if(child._class == class(CodeEditor) || child._class == class(Designer) ||
1907 child._class == class(Sheet) || child._class == class(ProjectView))
1909 Anchor anchor = child.anchor;
1910 anchor.top = topDistance;
1911 anchor.bottom = bottomDistance;
1912 if(child._class == class(CodeEditor) || child._class == class(Designer))
1914 anchor.left = (sheet.visible || (projectView && projectView.visible)) ? 300 : 0;
1915 anchor.right = toolBoxVisible ? 150 : 0;
1918 child.anchor = anchor;
1922 if(child._class == class(OutputView) || child._class == class(CallStackView) || child._class == class(ThreadsView) || child._class == class(WatchesView) ||
1923 child._class == class(BreakpointsView))
1924 child.visible = false;
1927 // If this is not here, the IDE is not updated when doing Debug/Break then Alt-4 to show call stack (IDE not updated)
1929 if(duck.visible) duck.Update(null); // TOFIX: If this is not here, the duck disappears -- Why?
1933 bool ShowCodeEditor()
1936 activeClient.Activate();
1937 else if(projectView)
1939 projectView.visible = true;
1940 projectView.Activate();
1942 else if(sheet.visible)
1945 outputView.visible = false;
1949 void DocumentSaved(Window document, const char * fileName)
1951 ideConfig.recentFiles.addRecent(fileName);
1952 ideConfig.recentFiles.write(settingsContainer);
1953 ide.updateRecentFilesMenu();
1954 ide.AdjustFileMenus();
1957 bool Window::OnFileModified(FileChange fileChange, const char * param)
1960 sprintf(temp, $"The document %s was modified by another application.\n"
1961 "Would you like to reload it and lose your changes?", this.fileName);
1962 if(MessageBox { creationActivation = flash, type = yesNo, master = this/*.parent*/,
1963 text = $"Document has been modified", contents = temp }.Modal() == yes)
1965 bool noParsing = (this._class == class(CodeEditor) && ((CodeEditor)this).noParsing) ? true : false;
1966 char * fileName = CopyString(this.fileName);
1967 WindowState state = this.state;
1968 Anchor anchor = this.anchor;
1969 Size size = this.size;
1971 this.modifiedDocument = false;
1973 this = ide.OpenFile(fileName, false, true, null, no, normal, noParsing);
1976 this.anchor = anchor;
1978 this.SetState(state, true, 0);
1986 void UpdateMakefiles()
1990 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
1991 for(prj : workspace.projects)
1992 projectView.ProjectUpdateMakefileForAllConfigs(prj);
1997 void UpdateCompilerConfigs(bool mute)
1999 UpdateToolBarActiveCompilers();
2002 bool silent = mute || (ide.projectView.buildInProgress == none ? false : true);
2003 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
2006 projectView.ShowOutputBuildLog(true);
2007 projectView.DisplayCompiler(compiler, false);
2009 for(prj : workspace.projects)
2010 projectView.ProjectPrepareCompiler(prj, compiler, silent);
2015 void UpdateToolBarActiveCompilers()
2017 toolBar.activeCompiler.Clear();
2018 for(compiler : ideConfig.compilers)
2020 DataRow row = toolBar.activeCompiler.AddString(compiler.name);
2021 if(workspace && workspace.activeCompiler && !strcmp(compiler.name, workspace.activeCompiler))
2022 toolBar.activeCompiler.currentRow = row;
2024 if(!toolBar.activeCompiler.currentRow && toolBar.activeCompiler.firstRow)
2025 toolBar.activeCompiler.SelectRow(toolBar.activeCompiler.firstRow);
2026 toolBar.activeBitDepth.SelectRow(toolBar.activeBitDepth.FindRow(workspace ? workspace.bitDepth : 0));
2029 void UpdateToolBarActiveConfigs(bool selectionOnly)
2031 bool commonSelected = false;
2032 DataRow row = toolBar.activeConfig.currentRow;
2034 row = toolBar.activeConfig.FindRow(1);
2037 toolBar.activeConfig.Clear();
2038 row = toolBar.activeConfig.AddString($"(Mixed)");
2043 char * configName = null;
2046 Map<String, int> configs { }; // TOIMP: just need sort but using map until containers have sort
2047 for(prj : workspace.projects)
2049 for(cfg : prj.configurations)
2052 configs[cfg.name] = 1;
2057 toolBar.activeConfig.AddString(&name);
2061 if(projectView && projectView.project)
2063 for(prj : workspace.projects)
2065 if(prj.config && prj.config.name)
2067 configName = prj.config.name;
2073 commonSelected = true;
2074 for(prj : workspace.projects)
2076 if(prj.config && (!prj.config.name || strcmp(prj.config.name, configName)))
2078 commonSelected = false;
2086 commonSelected = false;
2087 for(row = toolBar.activeConfig.firstRow; row; row = row.next)
2089 if(!strcmp(row.string, configName))
2091 toolBar.activeConfig.currentRow = row;
2092 commonSelected = true;
2099 toolBar.activeConfig.Sort(null, 0);
2101 toolBar.activeConfig.currentRow = row;
2106 bool unavailable = !project;
2108 projectAddItem.disabled = unavailable;
2109 toolBar.buttonAddProject.disabled = unavailable;
2111 projectSettingsItem.disabled = unavailable;
2113 projectBrowseFolderItem.disabled = unavailable;
2115 viewProjectItem.disabled = unavailable;
2117 toolBar.activeConfig.disabled = unavailable;
2118 toolBar.activeCompiler.disabled = unavailable;
2119 toolBar.activeBitDepth.disabled = unavailable;
2122 debugUseValgrindItem.disabled = unavailable;
2123 AdjustValgrindMenus();
2132 void AdjustValgrindMenus()
2134 bool unavailable = !project || !debugUseValgrindItem.checked;
2135 debugValgrindNoLeakCheckItem.disabled = unavailable;
2136 debugValgrindSummaryLeakCheckItem.disabled = unavailable;
2137 debugValgrindYesLeakCheckItem.disabled = unavailable;
2138 debugValgrindFullLeakCheckItem.disabled = unavailable;
2140 debugValgrindTrackOriginsItem.disabled = unavailable;
2142 debugValgrindRSDefaultItem.disabled = unavailable;
2143 debugValgrindRS0Item.disabled = unavailable;
2144 debugValgrindRS16Item.disabled = unavailable;
2145 debugValgrindRS32Item.disabled = unavailable;
2146 debugValgrindRS64Item.disabled = unavailable;
2147 debugValgrindRS128Item.disabled = unavailable;
2148 debugValgrindRS256Item.disabled = unavailable;
2149 debugValgrindRS512Item.disabled = unavailable;
2153 property bool hasOpenedCodeEditors
2158 for(w = firstChild; w; w = w.next)
2159 if(w._class == class(CodeEditor) &&
2160 w.isDocument && !w.closing && w.visible && w.created &&
2161 w.fileName && w.fileName[0])
2167 void AdjustFileMenus()
2169 bool unavailable = project != null || !hasOpenedCodeEditors; // are they supported source code (ec, c, cpp, etc) ?
2171 projectQuickItem.disabled = unavailable;
2174 void AdjustBuildMenus()
2176 bool unavailable = project && projectView.buildInProgress;
2177 bool naForRun = unavailable || !project || project.GetTargetType(project.config) != executable;
2178 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2180 projectNewItem.disabled = unavailable;
2181 toolBar.buttonNewProject.disabled = unavailable;
2182 projectOpenItem.disabled = unavailable;
2183 toolBar.buttonOpenProject.disabled = unavailable;
2185 unavailable = !project || projectView.buildInProgress;
2187 projectCloseItem.disabled = unavailable;
2188 // toolBar.buttonCloseProject.disabled = unavailable;
2190 projectRunItem.disabled = naForRun;
2191 toolBar.buttonRun.disabled = naForRun;
2193 projectBuildItem.disabled = false;
2194 projectBuildItem.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2195 projectBuildItem.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2197 projectLinkItem.disabled = unavailable;
2198 toolBar.buttonReLink.disabled = unavailable;
2199 projectRebuildItem.disabled = unavailable;
2200 toolBar.buttonRebuild.disabled = unavailable;
2201 projectCleanItem.disabled = unavailable;
2202 toolBar.buttonClean.disabled = unavailable;
2203 projectCleanTargetItem.disabled = unavailable;
2204 projectRealCleanItem.disabled = unavailable;
2205 // toolBar.buttonRealClean.disabled = unavailable;
2206 projectRegenerateItem.disabled = unavailable;
2207 toolBar.buttonRegenerateMakefile.disabled = unavailable;
2208 #ifdef IDE_SHOW_INSTALL_MENU_BUTTON
2209 projectInstallItem.disabled = unavailable;
2210 toolBar.buttonInstall.disabled = unavailable;
2212 projectCompileItem.disabled = unavailable;
2214 AdjustPopupBuildMenus();
2217 void AdjustPopupBuildMenus()
2219 bool unavailable = !project || projectView.buildInProgress;
2221 if(projectView && projectView.popupMenu && projectView.popupMenu.menu && projectView.popupMenu.created)
2224 BuildOutputMode mode = ide.rightClickMenuBuildOutputMode;
2225 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectBuild, mode);
2228 menu.disabled = false;
2229 menu.text = unavailable ? $"Stop Build" : bldMnuStrBuild[mode];
2230 menu.accelerator = unavailable ? Key { pauseBreak, ctrl = true } : f7;
2233 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectLink, mode); if(menu) menu.disabled = unavailable;
2234 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRebuild, mode); if(menu) menu.disabled = unavailable;
2235 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectCleanTarget, mode); if(menu) menu.disabled = unavailable;
2236 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectClean, mode); if(menu) menu.disabled = unavailable;
2237 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRealClean, mode); if(menu) menu.disabled = unavailable;
2238 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRegenerate, mode); if(menu) menu.disabled = unavailable;
2239 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectInstall, mode); if(menu) menu.disabled = unavailable;
2240 menu = projectView.popupMenu.menu.FindItem(ProjectView::ProjectRemove, mode); if(menu) menu.disabled = unavailable;
2241 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileClean, mode); if(menu) menu.disabled = unavailable;
2242 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileCompile, mode); if(menu) menu.disabled = unavailable;
2243 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugPrecompile, mode); if(menu) menu.disabled = unavailable;
2244 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugCompile, mode); if(menu) menu.disabled = unavailable;
2245 menu = projectView.popupMenu.menu.FindItem(ProjectView::FileDebugGenerateSymbols, mode); if(menu) menu.disabled = unavailable;
2246 projectView.popupMenu.Update(null);
2250 property bool areDebugMenusUnavailable { get {
2252 project.GetTargetType(project.config) != executable ||
2253 projectView.buildInProgress == buildingMainProject;
2256 property bool isBreakpointTogglingUnavailable { get { return !project; } }
2257 property bool isDebuggerRunning { get { if(ide.debugger) return ide.debugger.state == running; return false; } }
2258 property bool isDebuggerStopped { get { if(ide.debugger) return ide.debugger.state == stopped; return false; } }
2260 void AdjustDebugMenus()
2262 bool unavailable = areDebugMenusUnavailable;
2263 bool running = isDebuggerRunning;
2264 bool stopped = isDebuggerStopped;
2265 bool active = debugger.isActive;
2267 bool isNotRunning = unavailable || !running;
2268 bool isNotNotRunning = unavailable || running;
2269 bool isNotStopped = unavailable || !stopped;
2270 bool isNotActive = unavailable || !active;
2272 debugStartResumeItem.disabled = isNotNotRunning;
2273 debugStartResumeItem.text = active ? $"Resume" : $"Start";
2274 debugStartResumeItem.NotifySelect = active ? MenuDebugResume : MenuDebugStart;
2277 toolBar.buttonDebugStartResume.disabled = isNotNotRunning;
2278 toolBar.buttonDebugStartResume.toolTip = active ? $"Resume" : $"Start";
2281 debugBreakItem.disabled = isNotRunning;
2282 debugStopItem.disabled = isNotActive;
2283 debugRestartItem.disabled = isNotActive;
2286 toolBar.buttonDebugPause.disabled = isNotRunning;
2287 toolBar.buttonDebugStop.disabled = isNotActive;
2288 toolBar.buttonDebugRestart.disabled = isNotActive;
2291 debugStepIntoItem.disabled = isNotNotRunning;
2292 debugStepOverItem.disabled = isNotNotRunning;
2293 debugSkipStepOverItem.disabled = isNotNotRunning;
2294 debugStepOutItem.disabled = isNotStopped;
2295 debugSkipStepOutItem.disabled = isNotStopped;
2297 debugStepUntilItem.disabled = isNotStopped;
2298 debugSkipStepUntilItem.disabled = isNotStopped;
2302 toolBar.buttonDebugStepInto.disabled = isNotNotRunning;
2303 toolBar.buttonDebugStepOver.disabled = isNotNotRunning;
2304 toolBar.buttonDebugSkipStepOver.disabled = isNotNotRunning;
2305 toolBar.buttonDebugStepOut.disabled = isNotStopped;
2306 //toolBar.buttonDebugSkipStepOutItem.disabled = isNotNotRunning;
2308 if((Designer)GetActiveDesigner())
2310 CodeEditor codeEditor = ((Designer)GetActiveDesigner()).codeEditor;
2312 codeEditor.AdjustDebugMenus();
2316 void ChangeFileDialogsDirectory(const char * directory, bool saveSettings)
2318 char tempString[MAX_LOCATION];
2319 strcpy(tempString, directory);
2320 if(saveSettings && !projectView)
2322 ideSettings.ideFileDialogLocation = directory;
2323 settingsContainer.Save();
2326 ideFileDialog.currentDirectory = tempString;
2327 codeEditorFileDialog.currentDirectory = tempString;
2328 codeEditorFormFileDialog.currentDirectory = tempString;
2331 void ChangeProjectFileDialogDirectory(char * directory)
2333 ideSettings.ideProjectFileDialogLocation = directory;
2334 settingsContainer.Save();
2337 Window FindWindow(const char * filePath)
2339 Window document = null;
2341 // TOCHECK: Do we need to change slashes here?
2342 for(document = firstChild; document; document = document.next)
2344 const char * fileName = document.fileName;
2345 if(document.isDocument && fileName && !fstrcmp(fileName, filePath))
2347 document.visible = true;
2348 document.Activate();
2355 bool DontTerminateDebugSession(const char * title)
2357 if(debugger.isActive)
2359 if(MessageBox { type = yesNo, master = ide,
2360 contents = $"Do you want to terminate the debugging session in progress?",
2361 text = title }.Modal() == no)
2364 MessageBox msg { type = yesNo, master = ide,
2365 contents = "Do you want to terminate the debugging session in progress?",
2367 if(msg.Modal() == no)
2379 Window OpenFile(const char * origFilePath, bool dontMaximize, bool visible, const char * type, OpenCreateIfFails createIfFails, OpenMethod openMethod, bool noParsing)
2381 char extension[MAX_EXTENSION] = "";
2382 Window document = null;
2383 bool isProject = false;
2384 bool needFileModified = true;
2385 char winFilePath[MAX_LOCATION];
2386 const char * filePath = strstr(origFilePath, "http://") == origFilePath ? strcpy(winFilePath, origFilePath) : GetSystemPathBuffer(winFilePath, origFilePath);
2387 Window currentDoc = activeClient;
2388 bool maximizeDoc = !dontMaximize && ((currentDoc && currentDoc.state == maximized) || (!currentDoc && !projectView));
2391 GetExtension(filePath, extension);
2395 strcpy(extension, type);
2397 if(strcmp(extension, ProjectExtension))
2399 for(document = firstChild; document; document = document.next)
2401 const char * fileName = document.fileName;
2402 if(document.isDocument && fileName && !fstrcmp(fileName, filePath) && document.created)
2404 document.visible = true;
2406 document.Activate();
2412 if(createIfFails == whatever)
2414 else if(!strcmp(extension, ProjectExtension) || !strcmp(extension, WorkspaceExtension))
2416 needFileModified = false;
2417 if(openMethod == normal)
2419 if(DontTerminateDebugSession($"Open Project"))
2428 Workspace workspace = null;
2430 if(FileExists(filePath))
2432 if(!strcmp(extension, ProjectExtension))
2434 char workspaceFile[MAX_LOCATION];
2435 strcpy(workspaceFile, filePath);
2436 ChangeExtension(workspaceFile, WorkspaceExtension, workspaceFile);
2437 workspace = LoadWorkspace(workspaceFile, filePath);
2439 else if(!strcmp(extension, WorkspaceExtension))
2440 workspace = LoadWorkspace(filePath, null);
2447 CreateProjectView(workspace, filePath);
2448 document = projectView;
2450 toolBox.visible = true;
2451 sheet.visible = true;
2452 projectView.MakeActive();
2454 workspace.ParseLoadedBreakpoints();
2455 workspace.DropInvalidBreakpoints(null);
2458 ide.projectView.ShowOutputBuildLog(true);
2460 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(ide.workspace.activeCompiler);
2461 ide.projectView.DisplayCompiler(compiler, false);
2464 UpdateCompilerConfigs(false);
2467 char newWorkingDir[MAX_LOCATION];
2468 StripLastDirectory(filePath, newWorkingDir);
2469 ChangeFileDialogsDirectory(newWorkingDir, false);
2472 document.fileName = filePath;
2474 ideMainFrame.SetText("%s - %s", filePath, titleECEREIDE);
2476 // this crashes on starting ide with epj file, solution please?
2477 // app.UpdateDisplay();
2479 workspace.OpenPreviouslyOpenedFiles(noParsing);
2480 workspace.holdTracking = true;
2481 ide.RepositionWindows(false);
2482 workspace.holdTracking = false;
2484 workspace.timer.Start();
2486 #if !defined(__WIN32__)
2487 // Valgrind Debug menu updates
2488 debugUseValgrindItem.checked = workspace.useValgrind;
2490 debugValgrindNoLeakCheckItem.checked = workspace.vgLeakCheck == no;
2491 debugValgrindSummaryLeakCheckItem.checked = workspace.vgLeakCheck == summary;
2492 debugValgrindYesLeakCheckItem.checked = workspace.vgLeakCheck == yes;
2493 debugValgrindFullLeakCheckItem.checked = workspace.vgLeakCheck == full;
2495 debugValgrindRSDefaultItem.checked = workspace.vgRedzoneSize == -1;
2496 debugValgrindRS0Item.checked = workspace.vgRedzoneSize == 0;
2497 debugValgrindRS16Item.checked = workspace.vgRedzoneSize == 16;
2498 debugValgrindRS32Item.checked = workspace.vgRedzoneSize == 32;
2499 debugValgrindRS64Item.checked = workspace.vgRedzoneSize == 64;
2500 debugValgrindRS128Item.checked = workspace.vgRedzoneSize == 128;
2501 debugValgrindRS256Item.checked = workspace.vgRedzoneSize == 256;
2502 debugValgrindRS512Item.checked = workspace.vgRedzoneSize == 512;
2504 debugValgrindTrackOriginsItem.checked = workspace.vgTrackOrigins;
2507 findInFilesDialog.mode = FindInFilesMode::project;
2508 findInFilesDialog.currentDirectory = ide.project.topNode.path;
2511 char location[MAX_LOCATION];
2512 StripLastDirectory(ide.project.topNode.path, location);
2513 ChangeProjectFileDialogDirectory(location);
2520 if(MessageBox { type = yesNo, master = this, text = $"Error opening project", contents = $"Open a different project?" }.Modal() == yes)
2522 ideProjectFileDialog.text = openProjectFileDialogTitle;
2523 if(ideProjectFileDialog.Modal() == cancel)
2525 filePath = ideProjectFileDialog.filePath;
2526 GetExtension(filePath, extension);
2537 else if(openMethod == add)
2542 char slashFilePath[MAX_LOCATION];
2543 GetSlashPathBuffer(slashFilePath, filePath);
2544 for(p : workspace.projects)
2546 if(!fstrcmp(p.filePath, slashFilePath))
2554 MessageBox { type = ok, parent = parent, master = this, text = $"Same Project",
2555 contents = $"This project is already present in workspace." }.Modal();
2559 prj = LoadProject(filePath, null);
2562 const char * activeConfigName = null;
2563 CompilerConfig compiler = ideConfig.compilers.GetCompilerConfig(workspace.activeCompiler);
2564 prj.StartMonitoring();
2565 workspace.AddProject(prj, null);
2566 if(toolBar.activeConfig.currentRow && toolBar.activeConfig.currentRow != toolBar.activeConfig.firstRow &&
2567 toolBar.activeConfig.currentRow.string && toolBar.activeConfig.currentRow.string[0])
2568 activeConfigName = toolBar.activeConfig.currentRow.string;
2569 if(activeConfigName)
2571 for(cfg : prj.configurations)
2573 if(cfg.name && !strcmp(cfg.name, activeConfigName))
2581 projectView.AddNode(prj.topNode, null);
2582 workspace.modified = true;
2584 findInFilesDialog.AddProjectItem(prj);
2585 projectView.ShowOutputBuildLog(true);
2586 projectView.DisplayCompiler(compiler, false);
2587 projectView.ProjectUpdateMakefileForAllConfigs(prj);
2591 char location[MAX_LOCATION];
2592 StripLastDirectory(prj.topNode.path, location);
2593 ChangeProjectFileDialogDirectory(location);
2596 // projectView is associated with the main project and not with the one just added but
2597 return projectView; // just to let the caller know something was opened
2605 else if(!strcmp(extension, "bmp") || !strcmp(extension, "pcx") ||
2606 !strcmp(extension, "jpg") || !strcmp(extension, "gif") ||
2607 !strcmp(extension, "jpeg") || !strcmp(extension, "png"))
2609 if(FileExists(filePath))
2610 document = PictureEdit { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2611 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2612 visible = visible, bitmapFile = filePath, OnClose = PictureEditOnClose/*why?--GenericDocumentOnClose*/;
2615 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2618 else if(!strcmp(extension, "3ds"))
2620 if(FileExists(filePath))
2621 document = ModelView { hasMaximize = true, hasMinimize = true, hasClose = true, borderStyle = sizable,
2622 hasVertScroll = true, hasHorzScroll = true, parent = this, state = state,
2623 visible = visible, modelFile = filePath, OnClose = ModelViewOnClose/*why?--GenericDocumentOnClose*/
2627 MessageBox { type = ok, master = this, text = filePath, contents = $"File doesn't exist." }.Modal();
2630 else if(!strcmp(extension, "txt") || !strcmp(extension, "text") ||
2631 !strcmp(extension, "nfo") || !strcmp(extension, "info") ||
2632 !strcmp(extension, "htm") || !strcmp(extension, "html") ||
2633 !strcmp(extension, "css") || !strcmp(extension, "php") ||
2634 !strcmp(extension, "js"))
2636 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2637 editor.updatingCode = true;
2638 if(editor.LoadFile(filePath))
2641 editor.visible = true;
2645 needFileModified = false;
2649 CodeEditor editor { parent = this, state = state, visible = false, noParsing = noParsing };
2650 if(editor.LoadFile(filePath))
2653 editor.visible = true;
2657 needFileModified = false;
2660 if(document && (document._class == class(PictureEdit) ||
2661 document._class == class(ModelView)))
2666 document.fileName = filePath;
2667 if(workspace && !workspace.holdTracking)
2668 workspace.UpdateOpenedFileInfo(filePath, opened, true);
2672 if(!document && createIfFails != no)
2674 if(createIfFails != yes && !needFileModified &&
2675 MessageBox { type = yesNo, master = this, text = filePath, contents = $"File doesn't exist. Create?" }.Modal() == yes)
2676 createIfFails = yes;
2677 if(createIfFails == yes || createIfFails == whatever)
2679 document = (Window)NewCodeEditor(this, maximizeDoc ? maximized : normal, true);
2681 document.fileName = filePath;
2687 if(projectView && document._class == class(CodeEditor) && workspace)
2688 workspace.RestorePreviouslyOpenedFileState((CodeEditor)document);
2690 if(needFileModified)
2691 document.OnFileModified = OnFileModified;
2692 document.NotifySaved = DocumentSaved;
2693 if(maximizeDoc && document.hasMaximize)
2694 document.state = maximized;
2698 ideConfig.recentWorkspaces.addRecent(document.fileName);
2699 ideConfig.recentWorkspaces.write(settingsContainer);
2700 ide.updateRecentProjectsMenu();
2703 workspace.recentFiles.addRecent(document.fileName);
2706 ideConfig.recentFiles.addRecent(document.fileName);
2707 ideConfig.recentFiles.write(settingsContainer);
2709 ide.updateRecentFilesMenu();
2710 ide.AdjustFileMenus();
2717 // TOCHECK: I can't use a generic one for both ModelView and PictureEdit both derived from Window
2718 /*bool Window::GenericDocumentOnClose(bool parentClosing)
2720 if(!parentClosing && ide.workspace)
2721 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2724 bool ModelView::ModelViewOnClose(bool parentClosing)
2726 if(!parentClosing && ide.workspace)
2727 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2730 bool PictureEdit::PictureEditOnClose(bool parentClosing)
2732 if(!parentClosing && ide.workspace)
2733 ide.workspace.UpdateOpenedFileInfo(fileName, unknown, false);
2738 void OnUnloadGraphics(Window window)
2740 display.ClearMaterials();
2741 display.ClearTextures();
2742 display.ClearMeshes();
2746 void UpdateStateLight(StatusField fld, bool on)
2748 fld.color = on ? lime : Color { 128,128,128 };
2749 fld.backColor = on ? dimGray : 0;
2753 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
2755 UpdateStateLight(caps, app.GetKeyState(capsState));
2756 UpdateStateLight(num, app.GetKeyState(numState));
2760 bool OnKeyDown(Key key, unichar ch)
2764 case b: projectView.Update(null); break;
2765 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2766 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2771 bool OnKeyUp(Key key, unichar ch)
2775 case capsLock: UpdateStateLight(caps, app.GetKeyState(capsState)); break;
2776 case numLock: UpdateStateLight(num, app.GetKeyState(numState)); break;
2781 void GoToError(const char * line, bool noParsing, const char * objectFileExt)
2784 projectView.GoToError(line, noParsing, objectFileExt);
2787 FileAttribs GoToCodeSelectFile(const char * filePath, const char * dir, Project prj, ProjectNode * node, char * selectedPath, const char * objectFileExt)
2789 FileAttribs result { };
2790 FileAttribs fileAttribs;
2794 strcpy(selectedPath, prj.topNode.path);
2795 else if(dir && dir[0])
2796 strcpy(selectedPath, dir);
2798 selectedPath[0] = '\0';
2799 PathCat(selectedPath, filePath);
2801 if((fileAttribs = FileExists(selectedPath)).isFile)
2802 result = fileAttribs;
2806 for(p : workspace.projects)
2808 strcpy(selectedPath, p.topNode.path);
2809 PathCat(selectedPath, filePath);
2810 if((fileAttribs = FileExists(selectedPath)).isFile)
2813 result = fileAttribs;
2820 ProjectNode n = null;
2821 for(p : workspace.projects)
2823 if((n = p.topNode.Find(filePath, false)))
2825 n.GetFullFilePath(selectedPath, true);
2826 if((fileAttribs = FileExists(selectedPath)).isFile)
2829 result = fileAttribs;
2834 if(!n && (n = workspace.GetObjectFileNode(filePath, &project, selectedPath, objectFileExt)) && project &&
2835 (fileAttribs = FileExists(selectedPath)).isFile)
2838 result = fileAttribs;
2846 void CodeLocationParseAndGoTo(const char * text, Project project, const char * dir, const char * objectFileExt)
2849 const char *path = text;
2850 char *colon = strchr(text, ':');
2851 char filePath[MAX_LOCATION] = "";
2852 char completePath[MAX_LOCATION];
2853 int line = 0, col = 0;
2854 int len = strlen(text);
2856 FileAttribs fileAttribs;
2858 // support for valgrind output
2859 if((s = strstr(text, "==")) && s == text && (s = strstr(s+2, "==")) && (s = strstr(s+2, ":")) && (s = strstr(s+1, ":")))
2870 /*for(s=colon; *s; s++)
2879 //line = atoi(colon+1);
2881 // support for "Found n match(es) in "file/path";
2882 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)
2888 if(colon && (colon[1] == '/' || colon[1] == '\\'))
2890 path = (colon - 1 > path) ? colon - 1 : path;
2891 colon = strstr(colon + 1, ":");
2893 if(*path == '*' && (s = strchr(path+1, '*')))
2895 while(isspace(*path)) path++;
2899 char * close = strchr(path, ')');
2903 strncpy(name, path+1, close - path - 1);
2904 name[close - path - 1] = '\0';
2905 for(p : ide.workspace.projects)
2907 if(!strcmp(p.name, name))
2917 prj = project ? project : (dir ? null : ide.project);
2920 strncpy(filePath, path, colon - path);
2921 filePath[colon - path] = '\0';
2922 line = atoi(colon + 1);
2923 colon = strstr(colon + 1, ":");
2925 col = atoi(colon + 1);
2927 else if(path - 1 >= text && *(path - 1) == '\"')
2929 colon = strchr(path, '\"');
2932 strncpy(filePath, path, colon - path);
2933 filePath[colon - path] = '\0';
2936 else if(path && !colon)
2938 strcpy(filePath, path);
2941 if((fileAttribs = GoToCodeSelectFile(filePath, dir, prj, null, completePath, objectFileExt)))
2942 CodeLocationGoTo(completePath, fileAttribs, line, col);
2945 void CodeLocationGoTo(const char * path, const FileAttribs fileAttribs, int line, int col)
2947 if(fileAttribs.isFile)
2949 char ext[MAX_EXTENSION];
2950 GetExtension(path, ext);
2952 if(binaryDocExt.Find(ext))
2954 else if(!strcmp(ext, "a") || !strcmp(ext, "o") || !strcmp(ext, "bc") ||
2955 !strcmp(ext, "lib") || !strcmp(ext, "dll") || !strcmp(ext, "exe"))
2957 char dirPath[MAX_LOCATION];
2958 StripLastDirectory(path, dirPath);
2963 CodeEditor codeEditor = (CodeEditor)OpenFile(path, false, true, !strcmpi(ext, "epj") ? "txt" : ext, no, normal, false);
2964 if(codeEditor && codeEditor._class == class(CodeEditor) && line)
2966 EditBox editBox = codeEditor.editBox;
2967 editBox.GoToLineNum(line - 1);
2968 editBox.GoToPosition(editBox.line, line - 1, col ? (col - 1) : 0);
2972 else if(fileAttribs.isDirectory)
2976 void OnRedraw(Surface surface)
2978 Bitmap bitmap = back.bitmap;
2980 surface.Blit(bitmap, (clientSize.w - bitmap.width) / 2, (clientSize.h - bitmap.height) / 2, 0, 0, bitmap.width, bitmap.height);
2983 void SheetSelected(SheetType sheetSelected)
2985 if(activeChild == sheet)
2987 if(sheetSelected == methods)
2989 viewPropertiesItem.accelerator = f4;
2990 viewPropertiesItem.parent = viewMenu;
2991 viewMethodsItem.parent = null;
2995 viewMethodsItem.accelerator = f4;
2996 viewMethodsItem.parent = viewMenu;
2997 viewPropertiesItem.parent = null;
3002 viewMethodsItem.parent = viewMenu;
3003 viewPropertiesItem.parent = viewMenu;
3004 if(sheetSelected == methods)
3006 viewMethodsItem.accelerator = f4;
3007 viewPropertiesItem.accelerator = 0;
3011 viewMethodsItem.accelerator = 0;
3012 viewPropertiesItem.accelerator = f4;
3017 void OnActivateClient(Window client, Window previous)
3019 //if(!client || client != previous)
3022 if(!client || client != previous)
3025 dataType = previous._class;
3026 if(previous && !strcmp(dataType.name, "CodeEditor"))
3028 ((CodeEditor)previous).UpdateFormCode();
3030 else if(previous && !strcmp(dataType.name, "Designer"))
3032 ((Designer)previous).codeEditor.UpdateFormCode();
3037 dataType = client._class;
3038 if(client && !strcmp(dataType.name, "CodeEditor"))
3040 CodeEditor codeEditor = (CodeEditor)client;
3041 SetPrivateModule(codeEditor.privateModule);
3042 SetCurrentContext(codeEditor.globalContext);
3043 SetTopContext(codeEditor.globalContext);
3044 SetGlobalContext(codeEditor.globalContext);
3046 SetDefines(&codeEditor.defines);
3047 SetImports(&codeEditor.imports);
3049 SetActiveDesigner(codeEditor.designer);
3051 sheet.codeEditor = codeEditor;
3052 toolBox.codeEditor = codeEditor;
3054 viewDesignerItem.parent = viewMenu;
3055 if(activeChild != codeEditor)
3057 viewCodeItem.parent = viewMenu;
3058 viewDesignerItem.accelerator = 0;
3059 viewCodeItem.accelerator = f8;
3063 viewCodeItem.parent = null;
3064 viewDesignerItem.accelerator = f8;
3067 else if(client && !strcmp(dataType.name, "Designer"))
3069 CodeEditor codeEditor = ((Designer)client).codeEditor;
3072 SetPrivateModule(codeEditor.privateModule);
3073 SetCurrentContext(codeEditor.globalContext);
3074 SetTopContext(codeEditor.globalContext);
3075 SetGlobalContext(codeEditor.globalContext);
3076 SetDefines(&codeEditor.defines);
3077 SetImports(&codeEditor.imports);
3081 SetPrivateModule(null);
3082 SetCurrentContext(null);
3083 SetTopContext(null);
3084 SetGlobalContext(null);
3089 SetActiveDesigner((Designer)client);
3091 sheet.codeEditor = codeEditor;
3092 toolBox.codeEditor = codeEditor;
3094 viewCodeItem.parent = viewMenu;
3095 if(activeChild != client)
3097 viewDesignerItem.parent = viewMenu;
3098 viewDesignerItem.accelerator = f8;
3099 viewCodeItem.accelerator = 0;
3103 viewDesignerItem.parent = null;
3104 viewCodeItem.accelerator = f8;
3109 if(!client && !projectView && sheet.visible)
3112 sheet.visible = false;
3113 toolBox.visible = false;
3116 sheet.codeEditor = null;
3117 toolBox.codeEditor = null;
3118 SetActiveDesigner(null);
3120 viewDesignerItem.parent = null;
3121 viewCodeItem.parent = null;
3124 SheetSelected(sheet.sheetSelected);
3127 projectCompileItem = null;
3132 if(client && client._class == eSystem_FindClass(__thisModule, "CodeEditor")) // !strcmp(client._class.name, "CodeEditor")
3134 CodeEditor codeEditor = (CodeEditor)client;
3135 EditBox editBox = codeEditor.editBox;
3137 statusBar.AddField(pos);
3139 caps = { width = 40, text = $"CAPS" };
3140 statusBar.AddField(caps);
3141 UpdateStateLight(caps, app.GetKeyState(capsState));
3143 ovr = { width = 36, text = $"OVR" };
3144 statusBar.AddField(ovr);
3145 UpdateStateLight(ovr, (editBox && editBox.overwrite));
3147 num = { width = 36, text = $"NUM" };
3148 statusBar.AddField(num);
3149 UpdateStateLight(num, app.GetKeyState(numState));
3151 //statusBar.text = "Ready";
3153 if(projectView && projectView.project)
3155 bool isCObject = false;
3156 ProjectNode node = projectView.GetNodeFromWindow(client, null, true, false, null);
3157 if(!node && (node = projectView.GetNodeFromWindow(client, null, true, true, null)))
3161 char nodeName[MAX_FILENAME];
3162 char name[MAX_FILENAME+96];
3164 ChangeExtension(node.name, "c", nodeName);
3165 sprintf(name, $"Compile %s", isCObject ? nodeName : node.name);
3166 projectCompileItem =
3168 copyText = true, text = name, c, ctrlF7, disabled = projectView.buildInProgress;
3170 bool NotifySelect(MenuItem selection, Modifiers mods)
3174 bool isCObject = false;
3175 bool isExcluded = false;
3176 ProjectNode node = projectView.GetNodeForCompilationFromWindow(activeClient, true, &isExcluded, &isCObject);
3180 ide.outputView.buildBox.Logf($"%s %s is excluded from current build configuration.\n", isCObject ? "Object file" : "File", node.name);
3183 List<ProjectNode> nodes { };
3185 projectView.Compile(node.project, nodes, normal, isCObject ? cObject : normal);
3193 projectMenu.AddDynamic(projectCompileItem, ide, false);
3199 caps = ovr = num = null;
3204 bool OnClose(bool parentClosing)
3206 //return !projectView.buildInProgress;
3207 if(projectView && projectView.buildInProgress)
3209 if(DontTerminateDebugSession($"Close IDE"))
3211 if(findInFilesDialog)
3212 findInFilesDialog.SearchStop();
3215 workspace.timer.Stop();
3218 ideMainFrame.Destroy(0);
3225 bool passThrough = false;
3226 bool debugWorkDir = false;
3227 char * passDebugWorkDir = null;
3228 bool openAsText = false;
3229 DynamicString passArgs { };
3232 for(c = 1; c<app.argc; c++)
3236 const char * arg = app.argv[c];
3237 char * buf = new char[strlen(arg)*2+1];
3239 passArgs.concat(" ");
3241 passArgs.concat(buf);
3244 else if(debugWorkDir)
3246 passDebugWorkDir = CopyString(app.argv[c]);
3247 StripQuotes(passDebugWorkDir, passDebugWorkDir);
3248 debugWorkDir = false;
3250 else if(!strcmp(app.argv[c], "-t"))
3252 else if(!strcmp(app.argv[c], "-no-parsing"))
3253 ide.noParsing = true;
3254 else if(!strcmp(app.argv[c], "-debug-start"))
3255 ide.debugStart = true;
3256 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3257 debugWorkDir = true;
3258 else if(!strcmp(app.argv[c], "-@"))
3262 char fullPath[MAX_LOCATION];
3263 char parentPath[MAX_LOCATION];
3264 char ext[MAX_EXTENSION];
3266 FileAttribs dirAttribs;
3267 GetWorkingDir(fullPath, MAX_LOCATION);
3268 PathCat(fullPath, app.argv[c]);
3269 StripLastDirectory(fullPath, parentPath);
3270 GetExtension(app.argv[c], ext);
3271 isProject = !openAsText && !strcmpi(ext, "epj");
3273 if(isProject && c > 1 + (ide.debugStart ? 1 : 0)) continue;
3275 // Create directory for projects (only)
3276 if(((dirAttribs = FileExists(parentPath)) && dirAttribs.isDirectory) || isProject)
3278 if(isProject && !FileExists(fullPath))
3280 char name[MAX_LOCATION];
3281 NewProjectDialog newProjectDialog;
3285 projectView.visible = false;
3286 if(!projectView.Destroy(0))
3290 newProjectDialog = { master = this };
3292 strcpy(name, app.argv[c]);
3293 StripExtension(name);
3294 GetLastDirectory(name, name);
3295 newProjectDialog.projectName.contents = name;
3296 newProjectDialog.projectName.NotifyModified(newProjectDialog, newProjectDialog.projectName);
3297 newProjectDialog.locationEditBox.path = parentPath;
3298 newProjectDialog.NotifyModifiedLocation(newProjectDialog.locationEditBox);
3300 incref newProjectDialog;
3301 newProjectDialog.Modal();
3304 ideConfig.recentWorkspaces.addRecent(projectView.fileName);
3305 ideConfig.recentWorkspaces.write(settingsContainer);
3306 ide.updateRecentMenus();
3308 delete newProjectDialog;
3309 // Open only one project
3313 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3315 else if(strstr(fullPath, "http://") == fullPath)
3316 ide.OpenFile(fullPath, app.argFilesCount > 1, true, openAsText ? "txt" : null, yes, normal, false);
3319 if(passThrough && projectView && projectView.project && workspace)
3320 workspace.commandLineArgs = passArgs;
3321 if(passDebugWorkDir && projectView && projectView.project && workspace)
3323 workspace.debugDir = passDebugWorkDir;
3324 delete passDebugWorkDir;
3327 UpdateToolBarActiveConfigs(false);
3328 UpdateToolBarActiveCompilers();
3335 // IS THIS NEEDED? WASN'T HERE BEFORE... Crashes on getting node's projectView otherwise
3338 projectView.visible = false;
3339 projectView.Destroy(0);
3342 #ifdef GDB_DEBUG_GUI
3343 gdbDialog.Destroy(0);
3348 void SetPath(bool projectsDirs, CompilerConfig compiler, ProjectConfig config, int bitDepth)
3352 char * oldPaths[128];
3353 String oldList = new char[maxPathLen];
3354 Array<String> newExePaths { };
3355 //Map<String, bool> exePathExists { };
3357 #if defined(__unix__) || defined(__APPLE__)
3358 Array<String> newLibPaths { };
3359 Map<String, bool> libPathExists { };
3364 for(prj : workspace.projects)
3366 DirExpression targetDirExp;
3368 // SKIP FIRST PROJECT...
3369 if(prj == workspace.projects.firstIterator.data) continue;
3371 // NOTE: Right now the additional project config dir will be
3372 // obtained when the debugger is started, so toggling it
3373 // while building will change which library gets used.
3374 // To go with the initial state, e.g. when F5 was pressed,
3375 // we nould need to keep a list of all project's active
3376 // config upon startup.
3377 targetDirExp = prj.GetTargetDir(compiler, prj.config, bitDepth);
3379 /*if(prj.config.targetType == sharedLibrary && prj.config.debug)
3383 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3384 if(cfg.targetType == sharedLibrary && cfg.debug && !strcmpi(cfg.name, "Debug"))
3388 for(cfg = prj.configurations.first; cfg; cfg = cfg.next)
3389 if(cfg.targetType == sharedLibrary && cfg.debug)
3393 if(targetDirExp.dir)
3395 char buffer[MAX_LOCATION];
3396 #if defined(__WIN32__)
3397 Array<String> paths = newExePaths;
3399 Array<String> paths = newLibPaths;
3401 GetSystemPathBuffer(buffer, prj.topNode.path);
3402 PathCat(buffer, targetDirExp.dir);
3405 if(!fstrcmp(p, buffer))
3412 paths.Add(CopyString(buffer));
3414 delete targetDirExp;
3418 for(item : compiler.executableDirs)
3420 DirExpression dirExpr { };
3421 dirExpr.Evaluate(item, null, compiler, null, 0);
3424 for(p : newExePaths)
3426 if(!fstrcmp(p, dirExpr.dir))
3433 newExePaths.Add(CopySystemPath(dirExpr.dir));
3437 GetEnvironment("PATH", oldList, maxPathLen);
3439 printf("Old value of PATH: %s\n", oldList);
3441 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3442 for(c = 0; c < count; c++)
3445 for(p : newExePaths)
3447 if(!fstrcmp(p, oldPaths[c]))
3454 newExePaths.Add(CopySystemPath(oldPaths[c]));
3458 for(path : newExePaths)
3459 len += strlen(path) + 1;
3460 newList = new char[len + 1];
3462 for(path : newExePaths)
3464 strcat(newList, path);
3465 strcat(newList, pathListSep);
3467 newList[len - 1] = '\0';
3468 SetEnvironment("PATH", newList);
3470 printf("New value of PATH: %s\n", newList);
3477 #if defined(__unix__) || defined(__APPLE__)
3479 for(item : compiler.libraryDirs)
3481 if(!libPathExists[item]) // fstrcmp should be used
3483 String s = CopyString(item);
3485 libPathExists[s] = true;
3489 #if defined(__APPLE__)
3490 GetEnvironment("DYLD_LIBRARY_PATH", oldList, maxPathLen);
3492 GetEnvironment("LD_LIBRARY_PATH", oldList, maxPathLen);
3495 printf("Old value of [DY]LD_LIBRARY_PATH: %s\n", oldList);
3497 count = TokenizeWith(oldList, sizeof(oldPaths) / sizeof(char *), oldPaths, pathListSep, false);
3498 for(c = 0; c < count; c++)
3500 if(!libPathExists[oldPaths[c]]) // fstrcmp should be used
3502 String s = CopyString(oldPaths[c]);
3504 libPathExists[s] = true;
3509 for(path : newLibPaths)
3510 len += strlen(path) + 1;
3511 newList = new char[len + 1];
3513 for(path : newLibPaths)
3515 strcat(newList, path);
3516 strcat(newList, pathListSep);
3518 newList[len - 1] = '\0';
3519 #if defined(__APPLE__)
3520 SetEnvironment("DYLD_LIBRARY_PATH", newList);
3522 SetEnvironment("LD_LIBRARY_PATH", newList);
3525 printf("New value of [DY]LD_LIBRARY_PATH: %s\n", newList);
3531 delete libPathExists;
3534 if(compiler.distccEnabled && compiler.distccHosts)
3535 SetEnvironment("DISTCC_HOSTS", compiler.distccHosts);
3540 void DestroyTemporaryProjectDir()
3542 if(tmpPrjDir && tmpPrjDir[0])
3544 if(FileExists(tmpPrjDir).isDirectory)
3545 DestroyDir(tmpPrjDir);
3546 property::tmpPrjDir = null;
3552 // Graphics Driver Menu
3555 app.currentSkin.selectionColor = selectionColor;
3556 app.currentSkin.selectionText = selectionText;
3560 driverItems = new MenuItem[app.numDrivers];
3561 for(c = 0; c < app.numDrivers; c++)
3563 driverItems[c] = MenuItem { driversMenu, app.drivers[c], NotifySelect = NotifySelectDisplayDriver };
3564 driverItems[c].id = c;
3565 driverItems[c].isRadio = true;
3568 driverItems = new MenuItem[2];
3569 #if defined(__unix__)
3570 driverItems[0] = MenuItem { driversMenu, "X", NotifySelect = NotifySelectDisplayDriver };
3571 driverItems[0].id = 0;
3572 driverItems[0].isRadio = true;
3574 driverItems[0] = MenuItem { driversMenu, "GDI", NotifySelect = NotifySelectDisplayDriver };
3575 driverItems[0].id = 0;
3576 driverItems[0].isRadio = true;
3578 driverItems[1] = MenuItem { driversMenu, "OpenGL", NotifySelect = NotifySelectDisplayDriver };
3579 driverItems[1].id = 1;
3580 driverItems[1].isRadio = true;
3582 /* skinItems = new MenuItem[app.numSkins];
3583 for(c = 0; c < app.numSkins; c++)
3585 skinItems[c] = MenuItem {skinsMenu, app.skins[c], NotifySelect = NotifySelectDisplaySkin };
3586 skinItems[c].id = c;
3587 skinItems[c].isRadio = true;
3590 ideFileDialog.master = this;
3591 ideProjectFileDialog.master = this;
3593 //SetDriverAndSkin();
3597 void updateRecentMenus()
3599 updateRecentFilesMenu();
3600 updateRecentProjectsMenu();
3603 void updateRecentFilesMenu()
3606 char * itemPath = new char[MAX_LOCATION];
3607 char * itemName = new char[MAX_LOCATION+4];
3608 Workspace ws = workspace;
3609 RecentPaths recentFiles = ws ? ws.recentFiles : ideConfig.recentFiles;
3610 recentFilesMenu.Clear();
3611 for(recent : recentFiles)
3613 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3614 MakeSystemPath(itemPath);
3615 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3616 recentFilesMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentFile }, ide, true);
3623 void updateRecentProjectsMenu()
3626 char * itemPath = new char[MAX_LOCATION];
3627 char * itemName = new char[MAX_LOCATION+4];
3628 recentProjectsMenu.Clear();
3629 for(recent : ideConfig.recentWorkspaces)
3631 strncpy(itemPath, recent, MAX_LOCATION); itemPath[MAX_LOCATION-1] = '\0';
3632 MakeSystemPath(itemPath);
3633 snprintf(itemName, MAX_LOCATION+4, "%d %s", 1 + c, itemPath); itemName[MAX_LOCATION+4-1] = '\0';
3634 recentProjectsMenu.AddDynamic(MenuItem { copyText = true, text = itemName, (Key)k1 + c, id = c, NotifySelect = ide.FileRecentProject }, ide, true);
3645 delete languageItems;
3649 documentor.Puts("Quit\n");
3656 void DestroyDir(char * path)
3658 RecursiveDeleteFolderFSI fsi { };
3663 #if defined(__WIN32__)
3664 define sdkDirName = "Ecere SDK";
3666 define sdkDirName = "ecere";
3669 bool GetInstalledFileOrFolder(const char * subDir, const char * name, char * path, FileAttribs attribs)
3672 char * v = new char[maxPathLen];
3676 strncpy(path, settingsContainer.moduleLocation, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3677 StripLastDirectory(path, path);
3678 PathCat(path, subDir);
3679 if(name) PathCat(path, name);
3680 if(FileExists(path) & attribs) found = true;
3682 #if defined(__WIN32__)
3685 for(s : [ "ECERE_SDK_SRC", "AppData", "ALLUSERSPROFILE", "USERPROFILE", "HOMEPATH", "ProgramData", "ProgramFiles", "ProgramFiles(x86)", "SystemDrive" ])
3687 GetEnvironment(s, v, maxPathLen);
3690 strncpy(path, v, MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3691 if(!strcmp(s, "SystemDrive"))
3692 PathCat(path, "Program Files");
3693 if(strcmp(s, "ECERE_SDK_SRC"))
3694 PathCat(path, sdkDirName);
3695 PathCat(path, subDir);
3696 if(name) PathCat(path, name);
3697 if(FileExists(path) & attribs)
3712 GetEnvironment("XDG_DATA_DIRS", v, maxPathLen);
3713 numTokens = TokenizeWith(v, sizeof(tokens) / sizeof(byte *), tokens, ":", false);
3716 p = new char[MAX_LOCATION];
3718 strcat(p, "/usr/share");
3722 for(c=0; c<numTokens; c++)
3724 strncpy(path, tokens[c], MAX_LOCATION); path[MAX_LOCATION-1] = '\0';
3725 PathCat(path, sdkDirName);
3726 PathCat(path, subDir);
3728 PathCat(path, name);
3729 if(FileExists(path) & attribs)
3742 void FindAndShellOpenInstalledFolder(const char * name)
3744 char path[MAX_LOCATION];
3745 if(GetInstalledFileOrFolder(name, null, path, { isDirectory = true }))
3749 void FindAndShellOpenInstalledFile(const char * subdir, const char * name)
3751 char path[MAX_LOCATION];
3752 if(GetInstalledFileOrFolder(subdir, name, path, { isFile = true }))
3756 class RecursiveDeleteFolderFSI : NormalFileSystemIterator
3758 bool preserveRootFolder;
3760 void OutFolder(const char * folderPath, bool isRoot)
3762 if(!(preserveRootFolder && isRoot))
3763 RemoveDir(folderPath);
3766 bool OnFile(const char * filePath)
3768 DeleteFile(filePath);
3773 class IDEApp : GuiApplication
3775 //driver = "Win32Console";
3776 // driver = "OpenGL";
3780 TempFile includeFile { };
3785 char ext[MAX_EXTENSION];
3786 SetLoggingMode(stdOut, null);
3787 //SetLoggingMode(debug, null);
3789 settingsContainer.Load();
3791 if(ideSettings.language)
3793 const String language = GetLanguageString();
3794 if(ideSettings.language.OnCompare(language))
3796 LanguageRestart(ideSettings.language, app, null, null, null, null, true);
3801 ide.ApplyFont(ideSettings.codeEditorFont, ideSettings.codeEditorFontSize);
3802 ide.ApplyColorScheme(colorScheme);
3804 ideConfig.compilers.read(settingsContainer);
3805 ideConfig.recentFiles.read(settingsContainer);
3806 ideConfig.recentWorkspaces.read(settingsContainer);
3808 // First count files arg to decide whether to maximize
3810 bool passThrough = false, debugWorkDir = false;
3813 for(c = 1; c<app.argc; c++)
3816 else if(debugWorkDir)
3817 debugWorkDir = false;
3818 else if(!strcmp(app.argv[c], "-t"));
3819 else if(!strcmp(app.argv[c], "-no-parsing"));
3820 else if(!strcmp(app.argv[c], "-debug-start"));
3821 else if(!strcmp(app.argv[c], "-debug-work-dir"))
3822 debugWorkDir = true;
3823 else if(!strcmp(app.argv[c], "-@"))
3830 if(app.argFilesCount > 0 && !strcmpi(GetExtension(argv[1], ext), "3ds"))
3832 app.driver = "OpenGL";
3833 ide.driverItems[1].checked = true;
3837 #if defined(__unix__) || defined(__APPLE__)
3838 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "X";
3840 app.driver = (ideSettings.displayDriver && !strcmp(ideSettings.displayDriver, "OpenGL")) ? ideSettings.displayDriver : "GDI";
3842 ide.driverItems[ideSettings.displayDriver && !strcmp(ideSettings.displayDriver,"OpenGL")].checked = true;
3846 char model[MAX_LOCATION];
3847 if(GetInstalledFileOrFolder("samples", "3D/ModelViewer/models/duck/duck.3DS", model, { isFile = true }))
3849 ide.duck.modelFile = model;
3850 ide.duck.parent = ideMainFrame;
3853 if(ide.duck.modelFile && !strcmpi(app.driver, "OpenGL"))
3854 ide.debugRubberDuck.disabled = false;
3858 desktop.caption = titleECEREIDE;
3861 for(c = 1; c<app.argc; c++)
3863 char fullPath[MAX_LOCATION];
3864 GetWorkingDir(fullPath, MAX_LOCATION);
3865 PathCat(fullPath, app.argv[c]);
3866 ide.OpenFile(fullPath, app.argFilesCount > 1, true, null, yes, normal, false);
3870 // Default to language specified by environment if no language selected
3871 if(!ideSettings.language)
3873 ideSettings.language = GetLanguageString();
3874 settingsContainer.Save();
3877 // Default to home directory if no directory yet set up
3878 if(!ideSettings.ideProjectFileDialogLocation[0])
3881 char location[MAX_LOCATION];
3882 char * home = getenv("HOME");
3883 char * homeDrive = getenv("HOMEDRIVE");
3884 char * homePath = getenv("HOMEPATH");
3885 char * userProfile = getenv("USERPROFILE");
3886 char * systemDrive = getenv("SystemDrive");
3887 if(home && FileExists(home).isDirectory)
3889 strcpy(location, home);
3892 if(!found && homeDrive && homePath)
3894 strcpy(location, homeDrive);
3895 PathCat(location, homePath);
3896 if(FileExists(location).isDirectory)
3899 if(!found && FileExists(userProfile).isDirectory)
3901 strcpy(location, userProfile);
3904 if(!found && FileExists(systemDrive).isDirectory)
3906 strcpy(location, systemDrive);
3911 ideSettings.ideProjectFileDialogLocation = location;
3912 if(!ideSettings.ideFileDialogLocation[0])
3913 ideSettings.ideFileDialogLocation = location;
3917 if(!LoadIncludeFile())
3918 PrintLn($"error: unable to load :crossplatform.mk file inside ide binary.");
3920 // Create language menu
3922 String language = ideSettings.language;
3926 ide.languageItems = new MenuItem[languages.count];
3929 ide.languageItems[i] =
3931 ide.languageMenu, l.name;
3932 bitmap = { l.bitmap };
3936 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
3938 if(!LanguageRestart(languages[(int)selection.id].code, app, ideSettings, settingsContainer, ide, ide.projectView, false))
3940 // Re-select previous selected language if aborted
3941 String language = ideSettings.language;
3945 if(((!language || !language[0]) && i == 0) ||
3946 (language && !strcmpi(l.code, language)))
3948 ide.languageItems[i].checked = true;
3960 // Try to find country-specific language first
3966 if(!strcmpi(l.code, language) || (i == 0 && !strcmpi("en", language)))
3968 ide.languageItems[i].checked = true;
3976 // Try generalizing locale
3977 if(!found && language)
3980 char genericLocale[256];
3982 strncpy(genericLocale, language, sizeof(genericLocale));
3983 genericLocale[sizeof(genericLocale)-1] = 0;
3985 under = strchr(genericLocale, '_');
3988 if(!strcmpi(genericLocale, "zh"))
3989 strcpy(genericLocale, "zh_CN");
3990 if(strcmp(genericLocale, language))
3994 if(!strcmpi(l.code, genericLocale) || (i == 0 && !strcmpi("en", genericLocale)))
3996 ide.languageItems[i].checked = true;
4006 ide.languageItems[0].checked = true;
4008 MenuDivider { ide.languageMenu };
4011 ide.languageMenu, "Help Translate";
4013 bool Window::NotifySelect(MenuItem selection, Modifiers mods)
4015 ShellOpen("http://translations.launchpad.net/ecere");
4021 ideMainFrame.Create();
4022 if(app.argFilesCount > 1)
4023 ide.MenuWindowTileVert(null, 0);
4027 bool Cycle(bool idle)
4031 if(ide.documentor.Peek())
4034 ide.documentor.GetLine(line, sizeof(line));
4035 if(!strcmpi(line, "Exited"))
4037 ide.documentor.CloseInput();
4038 ide.documentor.CloseOutput();
4039 ide.documentor.Wait();
4040 delete ide.documentor;
4043 if(ide.documentor && ide.documentor.eof)
4045 ide.documentor.CloseInput();
4046 ide.documentor.CloseOutput();
4047 ide.documentor.Wait();
4048 delete ide.documentor;
4054 bool LoadIncludeFile()
4056 bool result = false;
4057 File include = FileOpen(":crossplatform.mk", read);
4060 File f = includeFile;
4063 for(; !include.Eof(); )
4066 int count = include.Read(buffer, 1, 4096);
4067 f.Write(buffer, 1, count);
4077 IDEMainFrame ideMainFrame { };
4079 define app = ((IDEApp)__thisModule);
4081 define titleECEREIDE = $"Ecere IDE (Debug)";
4083 define titleECEREIDE = $"Ecere IDE";