ide/Global Settings: Initial font selector (Windows support)
[sdk] / ide / src / dialogs / GlobalSettingsDialog.ec
1 import "IDESettings"
2
3 // import "SelectorBar"
4 import "CompilersDetectionDialog"
5 import "ide"
6
7 FileDialog settingsFileDialog { type = selectDir, text = $"Select directory" };
8
9 FileDialog toolchainFileDialog { type = open, text = $"Open"; mayNotExist = true; };
10
11 class GlobalSettingsDialog : Window
12 {
13    autoCreate = false;
14    tabCycle = true;
15    background = formColor;
16    hasClose = true;
17    borderStyle = sizable;
18    text = $"Global Settings";
19    minClientSize = { 560, 542 };
20    nativeDecorations = true;
21
22    String workspaceActiveCompiler;
23
24    TabControl tabControl { this, background = formColor, anchor = { left = 8, top = 8, right = 8, bottom = 40 } };
25
26    EditorTab editorTab { this, tabControl = tabControl };
27    CompilersTab compilersTab { this, tabControl = tabControl };
28    ProjectOptionsTab projectOptionsTab { this, tabControl = tabControl };
29    WorkspaceOptionsTab workspaceOptionsTab { this, tabControl = tabControl };
30
31    property bool settingsModified
32    {
33       get
34       {
35          return editorTab.modifiedDocument || compilersTab.modifiedDocument ||
36                projectOptionsTab.modifiedDocument || workspaceOptionsTab.modifiedDocument;
37       }
38    }
39
40    bool OnClose(bool parentClosing)
41    {
42       if(!settingsModified || MessageBox {
43          type = okCancel, master = ide,
44          text = $"Lose Changes?",
45          contents = $"Are you sure you wish to discard changes?"
46           }.Modal() == ok)
47          return true;
48       return false;
49    }
50
51    Button cancel
52    {
53       parent = this, hotKey = escape, text = $"Cancel", id = DialogResult::cancel;
54       position = { 290, 290 }, size = { 80 };
55       anchor = { right = 8, bottom = 8 };
56       NotifyClicked = ButtonCloseDialog;
57    };
58
59    Button ok
60    {
61       parent = this, isDefault = true, text = $"OK";
62       position = { 200, 290 }, size = { 90 };
63       anchor = { right = 96, bottom = 8 };
64
65       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
66       {
67          if(settingsModified)
68          {
69             bool editorSettingsChanged = false;
70             bool compilerSettingsChanged = false;
71             bool projectOptionsChanged = false;
72             AVLTree<String> cfgsToWrite = null;
73             if(editorTab.modifiedDocument)
74             {
75                if(editorTab.useFreeCaret.checked != ideSettings.useFreeCaret ||
76                      editorTab.showLineNumbers.checked != ideSettings.showLineNumbers ||
77                      editorTab.caretFollowsScrolling.checked != ideSettings.caretFollowsScrolling ||
78                      editorTab.fontPicker.fontSize != ideSettings.codeEditorFontSize ||
79                      editorTab.fontPicker.faceName.OnCompare(ideSettings.codeEditorFont)
80                      )
81                {
82                   ideSettings.useFreeCaret = editorTab.useFreeCaret.checked;
83                   ideSettings.showLineNumbers = editorTab.showLineNumbers.checked;
84                   ideSettings.caretFollowsScrolling = editorTab.caretFollowsScrolling.checked;
85                   ideSettings.codeEditorFont = editorTab.fontPicker.faceName;
86                   ideSettings.codeEditorFontSize = editorTab.fontPicker.fontSize;
87
88                   ide.ApplyFont(ideSettings.codeEditorFont, ideSettings.codeEditorFontSize);
89
90                   editorSettingsChanged = true;
91                }
92             }
93
94             if(compilersTab.modifiedDocument)
95             {
96                if(strcmp(compilersTab.compilerConfigsDir.path, ideSettings.compilerConfigsDir))
97                   ideSettings.compilerConfigsDir = compilersTab.compilerConfigsDir.path;
98                if(compilersTab.compilerConfigs.OnCompare(ideConfig.compilers))
99                {
100                   cfgsToWrite = compilersTab.compilerConfigs.getWriteRequiredList(ideConfig.compilers);
101                   ideConfig.compilers.Free();
102                   for(compiler : compilersTab.compilerConfigs)
103                   {
104                      ideConfig.compilers.Add(compiler.Copy());
105                   }
106                   compilerSettingsChanged = true;
107                }
108             }
109
110             if(projectOptionsTab.modifiedDocument)
111             {
112                if(strcmp(projectOptionsTab.defaultTargetDir.path, ideSettings.projectDefaultTargetDir)
113                      || strcmp(projectOptionsTab.defaultIntermediateObjDir.path, ideSettings.projectDefaultIntermediateObjDir))
114                {
115                   ideSettings.projectDefaultTargetDir = projectOptionsTab.defaultTargetDir.path;
116                   ideSettings.projectDefaultIntermediateObjDir = projectOptionsTab.defaultIntermediateObjDir.path;
117                   projectOptionsChanged = true;
118                }
119             }
120
121             if(workspaceOptionsTab.modifiedDocument)
122             {
123                DataRow row = workspaceOptionsTab.defaultCompilerDropBox.currentRow;
124                if(row && row.string)
125                {
126                   if(!ideSettings.defaultCompiler || strcmp(row.string, ideSettings.defaultCompiler))
127                   {
128                      ideSettings.defaultCompiler = row.string;
129                   }
130                }
131             }
132
133             if(editorSettingsChanged || projectOptionsChanged)
134                settingsContainer.Save();
135
136             if(compilerSettingsChanged)
137             {
138                ideConfig.compilers.write(settingsContainer, cfgsToWrite);
139                OnGlobalSettingChange(GlobalSettingsChange::compilerSettings);
140                cfgsToWrite.Free();
141                delete cfgsToWrite;
142             }
143             if(editorSettingsChanged)
144                OnGlobalSettingChange(GlobalSettingsChange::editorSettings);
145             if(projectOptionsChanged)
146                OnGlobalSettingChange(GlobalSettingsChange::projectOptions);
147
148             editorTab.modifiedDocument = false;
149             compilersTab.modifiedDocument = false;
150             projectOptionsTab.modifiedDocument = false;
151             workspaceOptionsTab.modifiedDocument = false;
152          }
153
154          Destroy(DialogResult::ok);
155          return true;
156       }
157    };
158
159    /*
160    void Temp()
161    {
162       DirTypes c;
163       for(c = 0; c < DirTypes::enumSize; c++)
164       {
165          CompilerDir compilerDir;
166
167          for(systemDir : ideSettings.systemDirs[c])
168          {
169             compilerDir = CompilerDir { type = c; compilerConfig = null; path = CopyString(systemDir) };
170             dirs.Add(compilerDir);
171          }
172
173          row = compilersTab.dirs[c].AddRow();
174          row.SetData(null, "");
175          compilersTab.dirs[c].currentRow = compilersTab.dirs[c].firstRow;
176          compilersTab.dirs[c].modifiedDocument = false;
177       }
178    }
179    */
180
181    bool OnCreate()
182    {
183       CompilerConfig activateCompiler = null;
184       CompilerConfig readonlyCompiler = null;
185
186       // EditorTab
187       editorTab.useFreeCaret.checked = ideSettings.useFreeCaret;
188       editorTab.showLineNumbers.checked = ideSettings.showLineNumbers;
189       editorTab.caretFollowsScrolling.checked = ideSettings.caretFollowsScrolling;
190
191       // CompilersTab
192       if(workspaceActiveCompiler)
193       {
194          for(compiler : ideConfig.compilers)
195          {
196             if(!activateCompiler && !strcmp(workspaceActiveCompiler, compiler.name))
197                activateCompiler = compiler;
198             if(!readonlyCompiler && compiler.readOnly)
199                readonlyCompiler = compiler;
200             if(activateCompiler && readonlyCompiler)
201                break;
202          }
203       }
204       if(!activateCompiler && readonlyCompiler)
205          activateCompiler = readonlyCompiler;
206       if(!activateCompiler && ideConfig.compilers.count)
207          activateCompiler = ideConfig.compilers[0];
208
209       for(compiler : ideConfig.compilers)
210          compilersTab.AddCompiler(compiler.Copy(), compiler == activateCompiler);
211       compilersTab.compilerConfigsDir.path = ideSettings.compilerConfigsDir;
212
213       // ProjectOptionsTab
214       projectOptionsTab.defaultTargetDir.path = ideSettings.projectDefaultTargetDir;
215       projectOptionsTab.defaultIntermediateObjDir.path = ideSettings.projectDefaultIntermediateObjDir;
216
217       return true;
218    }
219
220    void OnDestroy()
221    {
222       editorTab.modifiedDocument = false;
223       compilersTab.modifiedDocument = false;
224       compilersTab.dirsTab.modifiedDocument = false;
225       compilersTab.toolchainTab.modifiedDocument = false;
226       compilersTab.optionsTab.modifiedDocument = false;
227       compilersTab.activeCompiler = null;
228       compilersTab.compilerConfigs.Free();
229       compilersTab.compilerSelector.Clear();
230       projectOptionsTab.modifiedDocument = false;
231       workspaceOptionsTab.modifiedDocument = false;
232    }
233
234    virtual void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange);
235 }
236
237 import "FontPicker"
238
239 class EditorTab : GlobalSettingsSubTab
240 {
241    background = formColor;
242    text = $"Editor";
243
244    Button useFreeCaret
245    {
246       this, text = $"Move code editor caret freely past end of line", position = { 16, 58 }, isCheckbox = true;
247       NotifyClicked = NotifyClickedModifiedDocument;
248    };
249
250    Button caretFollowsScrolling
251    {
252       this, text = $"Keep caret visible (move along) when scrolling", position = { 16, 78 }, isCheckbox = true;
253       NotifyClicked = NotifyClickedModifiedDocument;
254    };
255
256    Button showLineNumbers
257    {
258       this, text = $"Show line numbers in code editor", position = { 16, 98 }, isCheckbox = true;
259       NotifyClicked = NotifyClickedModifiedDocument;
260    };
261
262    bool NotifyClickedModifiedDocument(Button button, int x, int y, Modifiers mods)
263    {
264       modifiedDocument = true;
265       return true;
266    }
267
268    FontPicker fontPicker
269    {
270       this, anchor = { left = 8, right = 8, top = 120, bottom = 8 };
271
272       bool NotifyChanged()
273       {
274          modifiedDocument = true;
275          return true;
276       }
277    };
278 }
279
280 static void DrawStipple(Surface surface, Size clientSize)
281 {
282    int x1 = 0;
283    int y1 = 0;
284    int x2 = clientSize.w - 1;
285    int y2 = clientSize.h - 1;
286    if((x2 - x1) & 1) x2--;
287    if((y2 - y1) & 1) y2--;
288
289    surface.LineStipple(0x5555);
290    surface.Rectangle(x1, y1, x2, y2);
291    surface.LineStipple(0);
292 }
293
294 class CompilersTab : GlobalSettingsSubTab
295 {
296    background = formColor;
297    text = $"Compilers";
298
299    Label compilerConfigsDirLabel { this, position = { 8, 12 }, labeledWindow = compilerConfigsDir, tabCycle = false, inactive = true };
300    PathBox compilerConfigsDir
301    {
302       this, anchor = { left = 230, top = 8, right = 8 };
303       text = $"Compiler Configurations Directory", browseDialog = settingsFileDialog, NotifyModified = NotifyModifiedDocument;
304    };
305
306    SelectorBar compilerSelector
307    {
308       this, text = $"Compiler Configurations:", anchor = { left = 148, top = 38, right = 99 }; size = { 0, 26 };
309       opacity = 0;
310       direction = horizontal;
311       scrollable = true;
312       endButtons = false;
313       hoverScroll = true;
314
315       bool OnKeyDown(Key key, unichar ch)
316       {
317          if(key == insert)
318          {
319             ((CompilersTab)parent).createCompiler.NotifyClicked(parent, ((CompilersTab)parent).createCompiler, 0, 0, 0);
320             return false;
321          }
322          else if(key == del)
323          {
324             ((CompilersTab)parent).deleteCompiler.NotifyClicked(parent, ((CompilersTab)parent).deleteCompiler, 0, 0, 0);
325             return false;
326          }
327          return SelectorBar::OnKeyDown(key, ch);
328       }
329
330       bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
331       {
332          ((CompilersTab)master).labelCompilers.Update(null);
333          return true;
334       }
335
336       bool OnPostCreate()
337       {
338          CompilersTab compilers = (CompilersTab)parent;
339          SelectorBar::OnPostCreate();
340          if(compilers.selectedButton)
341          {
342             Button sb = compilers.selectedButton;
343             sb.Activate();
344             sb.checked = true;
345             // Why was this being set to null? On going back to compilers the 2nd time, the selectedButton was lost and so was not made visible...
346             // compilers.selectedButton = null;
347          }
348          return true;
349       }
350    };
351
352    TabControl tabControl { this, background = formColor, anchor = { left = 8, top = 68, right = 8, bottom = 8 } };
353
354    CompilerDirectoriesTab dirsTab { this, tabControl = tabControl };
355    CompilerToolchainTab toolchainTab { this, tabControl = tabControl };
356    CompilerEnvironmentTab environmentTab { this, tabControl = tabControl };
357    CompilerOptionsTab optionsTab { this, tabControl = tabControl };
358
359    CompilerConfigs compilerConfigs { };
360    CompilerConfig activeCompiler;
361
362    Label labelCompilers
363    {
364       this, anchor = { left = 8, top = 44 }, labeledWindow = compilerSelector;
365
366       void OnRedraw(Surface surface)
367       {
368          Label::OnRedraw(surface);
369          if(labeledWindow.active)
370             DrawStipple(surface, clientSize);
371       }
372    };
373
374    void FindUniqueCompilerName(const char * baseName, CompilerConfig compiler/*, bool startWithNumber*/, char * output)
375    {
376       int num = 0;
377       char tmp[MAX_F_STRING];
378       /*if(startWithNumber)
379          sprintf(tmp, "%s%d", baseName, num);
380       else*/
381          strcpy(tmp, baseName);
382       while(true)
383       {
384          CompilerConfig matchingCompiler = null;
385          for(c : compilerConfigs)
386          {     // TOFIX: Error when omitting these brackets, c not found
387             if((!compiler || c != compiler) && c.name && !strcmp(c.name, tmp))
388             {
389                matchingCompiler = c;
390                break;
391             }
392          }
393          if(matchingCompiler)
394          {
395             num++;
396             sprintf(tmp, "%s%d", baseName, num);
397          }
398          else
399             break;
400       }
401       strcpy(output, tmp);
402    }
403
404    Button createCompiler
405    {
406       parent = this, bevelOver = true, inactive = true;
407       size = { 22, 22 };
408       anchor = { top = 40, right = 77 };
409       hotKey = altC, bitmap = BitmapResource { fileName = ":actions/docNew.png", alphaBlend = true };
410
411       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
412       {
413          char compilerName[MAX_F_STRING];
414          CompilerConfig newCompiler;
415          FindUniqueCompilerName("New Compiler", null, compilerName);
416          newCompiler = MakeDefaultCompiler(compilerName, false);
417          AddCompiler(newCompiler, true);
418          modifiedDocument = true;
419          return true;
420       }
421    };
422    Button detectCompiler
423    {
424       parent = this, bevelOver = true, inactive = true;
425       size = { 22, 22 };
426       anchor = { top = 40, right = 54 };
427       hotKey = altC, bitmap = BitmapResource { fileName = ":actions/attach.png", alphaBlend = true };
428
429       bool NotifyClicked(Button b, int x, int y, Modifiers mods)
430       {
431          CompilersDetectionDialog compilersDetectionDialog
432          {
433             dialog.parent;
434
435          };
436          if(compilersDetectionDialog.Modal())
437          {
438             if(compilersDetectionDialog.selectedCompilerType)
439             {
440                char uniqueName[MAX_F_STRING];
441                CompilerConfig newCompiler = compilersDetectionDialog.compilerConfig;
442                FindUniqueCompilerName(newCompiler.name, null, uniqueName);
443                newCompiler.name = uniqueName;
444                AddCompiler(newCompiler, true);
445                modifiedDocument = true;
446             }
447          }
448          return true;
449       }
450    };
451    Button duplicateCompiler
452    {
453       parent = this, bevelOver = true, inactive = true;
454       size = { 22, 22 };
455       anchor = { top = 40, right = 31 };
456       hotKey = altU, bitmap = BitmapResource { fileName = ":actions/editCopy.png", alphaBlend = true };
457
458       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
459       {
460          char copyName[MAX_F_STRING];
461          CompilerConfig copyCompiler = activeCompiler.Copy();
462          FindUniqueCompilerName(copyCompiler.name, null, copyName);
463          copyCompiler.readOnly = false;
464          copyCompiler.name = copyName;
465          AddCompiler(copyCompiler, true);
466          modifiedDocument = true;
467          return true;
468       }
469    };
470    Button deleteCompiler
471    {
472       parent = this, bevelOver = true, inactive = true;
473       size = { 22, 22 };
474       anchor = { top = 40, right = 8 };
475       hotKey = altD, bitmap = BitmapResource { fileName = ":actions/delete2.png", alphaBlend = true };
476
477       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
478       {
479          if(activeCompiler)
480          {
481             CompilerConfig compilerToDelete = activeCompiler;
482             String title = PrintString($"Delete ", compilerToDelete.name, $" Compiler Configuration");
483             String msg = PrintString($"Are you sure you wish to delete the ", compilerToDelete.name, $" compiler configuration?");
484             if(MessageBox { type = okCancel, text = title, contents = msg }.Modal() == ok)
485             {
486                SelectorButton button = compilerSelector.FindButtonByID((int64)(intptr)compilerToDelete);
487                if(button)
488                   compilerSelector.RemoveButton(button);
489                //DeleteCompiler(compilerToDelete);
490                {
491                   Iterator<CompilerConfig> it { compilerConfigs };
492                   if(it.Find(compilerToDelete))
493                      compilerConfigs.Delete(it.pointer);
494                }
495                modifiedDocument = true;
496             }
497             delete title;
498             delete msg;
499          }
500          return true;
501       }
502    };
503
504    void AddCompiler(CompilerConfig compiler, bool load)
505    {
506       SelectorButton selectButton;
507       if(compiler.readOnly)
508       {
509          SelectorButton button
510          {
511             compilerSelector, master = this, text = compiler.name, id = (int64)(intptr)compiler;
512             NotifyClicked = CompilerClicked;
513          };
514          selectButton = button;
515       }
516       else
517       {
518          EditableSelectorButton button
519          {
520             compilerSelector, master = this, renameable = true, text = compiler.name, id = (int64)(intptr)compiler;
521             NotifyClicked = CompilerClicked;
522
523             bool OnRename(EditableSelectorButton button, char ** oldName, char ** newName)
524             {
525                if(*newName && (*newName)[0])
526                {
527                   char compilerName[MAX_F_STRING];
528                   FindUniqueCompilerName(*newName, activeCompiler, compilerName);
529                   if(strcmp(*newName, compilerName))
530                   {
531                      delete *newName;
532                      *newName = CopyString(compilerName);
533                   }
534                   activeCompiler.name = compilerName;
535                   modifiedDocument = true;
536                   return true;
537                }
538                return false;
539             }
540          };
541          selectButton = (SelectorButton)button;
542       }
543       compilerConfigs.Add(compiler);
544       if(load)
545       {
546          LoadCompiler(compiler);
547          selectedButton = selectButton;
548          compilerSelector.Select(selectedButton);
549       }
550    }
551    SelectorButton selectedButton;
552
553    void LoadCompiler(CompilerConfig compiler)
554    {
555       bool modified = modifiedDocument;
556       activeCompiler = compiler;
557
558       dirsTab.Load();
559       toolchainTab.Load();
560       environmentTab.Load();
561       optionsTab.Load();
562
563       // Restore original modifiedDocument
564       modifiedDocument = modified;
565
566       deleteCompiler.disabled = compiler.readOnly;
567    }
568
569    bool CompilerClicked(Button clickedButton, int x, int y, Modifiers mods)
570    {
571       if(!eClass_IsDerived(clickedButton._class, class(EditableSelectorButton)) || !((EditableSelectorButton)clickedButton).editBox)
572       {
573          LoadCompiler((CompilerConfig)(intptr)clickedButton.id);
574          selectedButton = (SelectorButton)clickedButton;
575       }
576       return true;
577    }
578
579    bool NotifyModifiedDocument(PathBox pathBox)
580    {
581       BasicValidatePathBoxPath(pathBox);
582       modifiedDocument = true;
583       return true;
584    }
585 }
586
587 Array<const String> displayDirectoryNames
588 { [
589    $"Include Files",
590    $"Library Files",
591    $"Executable Files"
592 ] };
593
594 class CompilerDirectoriesTab : CompilersSubTab
595 {
596    background = formColor;
597    text = $"Directories";
598
599    Button dirTypeTglBtn[DirTypes];
600    DirectoriesBox dirs[DirTypes], currentDirs;
601
602    ~CompilerDirectoriesTab()
603    {
604       DirTypes c;
605       for(c = 0; c < DirTypes::enumSize; c++)
606       {
607          delete dirs[c];
608          delete dirTypeTglBtn[c];
609       }
610    }
611    CompilerDirectoriesTab()
612    {
613       DirTypes c;
614       int v = 8;
615       for(c = 0; c < DirTypes::enumSize; c++)
616       {
617          dirs[c] = DirectoriesBox
618          {
619             this;//, alwaysHighLight = true
620             anchor = { left = 8, top = 8, right = 8, bottom = 8 };
621             id = c;
622
623    /*   MAKE SURE THINGS ARE DONE PROPERLY IN THE NEW DIRECTORIES BOX WHEN BROWSING FOR A DIR?
624             settingsFileDialog.filePath = directory;
625          if(settingsFileDialog.Modal())
626             row.SetData(null, (s = CopyUnixPath(settingsFileDialog.filePath)));
627    */
628
629             bool NotifyModified(DirectoriesBox dirsBox)
630             {
631                CompilerConfig compiler = loadedCompiler;
632                if(compiler)
633                {
634                   DirTypes dirType = (DirTypes)dirsBox.id;
635                   if(dirType == includes)
636                      compiler.includeDirs = dirsBox.strings;
637                   else if(dirType == libraries)
638                      compiler.libraryDirs = dirsBox.strings;
639                   else if(dirType == executables)
640                      compiler.executableDirs = dirsBox.strings;
641
642                   compilersTab.modifiedDocument = true;
643                }
644                return true;
645             }
646             bool NotifyPathBoxModified(DirectoriesBox dirsBox, PathBox pathBox)
647             {
648                BasicValidatePathBoxPath(pathBox);
649                return true;
650             }
651          };
652          incref dirs[c];
653
654          if(c)
655             dirs[c].visible = false;
656
657          // (width) Should be 324 for text...
658          //field[c] = { dataType = class(char *), editable = true };
659          //dirs[c].AddField(field[c]);
660
661          dirTypeTglBtn[c] = Button
662          {
663             this, inactive = true, text = displayDirectoryNames[c], bevelOver = true, isRadio = true, bitmap = null;
664             stayOnTop = true;
665             id = c;
666             minClientSize = { 99, 20 };
667             anchor = { left = v, top = 8 }; // ((int)c) * 100 + 8
668
669             bool NotifyClicked(Button button, int x, int y, Modifiers mods)
670             {
671                DirTypes dirType = (DirTypes)button.id;
672                currentDirs.visible = false;
673                dirs[dirType].visible = true;
674                currentDirs = dirs[dirType];
675                return true;
676             }
677          };
678          v += dirTypeTglBtn[c].size.w + 1;
679          incref dirTypeTglBtn[c];
680
681          if(c == includes)
682             dirTypeTglBtn[c].hotKey = altI;
683          else if(c == libraries)
684             dirTypeTglBtn[c].hotKey = altL;
685          else if(c == executables)
686             dirTypeTglBtn[c].hotKey = altE;
687       }
688       currentDirs = dirs[includes];
689       dirTypeTglBtn[includes].checked = true;
690       return true;
691    }
692
693    bool OnLoadGraphics()
694    {
695       DirTypes c;
696       int v = 8;
697       for(c = 0; c < DirTypes::enumSize; c++)
698       {
699          dirTypeTglBtn[c].anchor.left = v;
700          v += dirTypeTglBtn[c].size.w + 1;
701       }
702       return CompilersSubTab::OnLoadGraphics();
703    }
704
705    void Load()
706    {
707       CompilerConfig compiler = loadedCompiler;
708       if(compiler)
709       {
710          dirs[includes].strings = compiler.includeDirs;
711          dirs[libraries].strings = compiler.libraryDirs;
712          dirs[executables].strings = compiler.executableDirs;
713          dirs[includes].list.scroll = { 0, 0 };
714          dirs[libraries].list.scroll = { 0, 0 };
715          dirs[executables].list.scroll = { 0, 0 };
716       }
717    }
718 }
719
720 class CompilerToolchainTab : CompilersSubTab
721 {
722    background = formColor;
723    text = $"Toolchain";
724
725    int margin;
726    margin = 130;
727
728    Label ecpLabel { this, position = { 8, 12 }, labeledWindow = ecp, tabCycle = false, inactive = true };
729    PathBox ecp
730    {
731       this, anchor = { left = margin, top = 8, right = 8 };
732       text = $"eC Precompiler", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
733    };
734    Label eccLabel { this, position = { 8, 38 }, labeledWindow = ecc, tabCycle = false, inactive = true };
735    PathBox ecc
736    {
737       this, anchor = { left = margin, top = 34, right = 8 };
738       text = $"eC Compiler", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
739    };
740    Label ecsLabel { this, position = { 8, 64 }, labeledWindow = ecs, tabCycle = false, inactive = true };
741    PathBox ecs
742    {
743       this, anchor = { left = margin, top = 60, right = 8 };
744       text = $"eC Symbol Loader", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
745    };
746    Label earLabel { this, position = { 8, 90 }, labeledWindow = ear, tabCycle = false, inactive = true };
747    PathBox ear
748    {
749       this, anchor = { left = margin, top = 86, right = 8 };
750       text = $"Ecere Archiver", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
751    };
752    Label cppLabel { this, position = { 8, 116 }, labeledWindow = cpp, tabCycle = false, inactive = true };
753    EditBox cpp
754    {
755       this, anchor = { left = margin, top = 112, right = 8 };
756       //text = $"C Preprocessor", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
757       text = $"C Preprocessor";//, NotifyModified = NotifyModifiedDocument;
758       bool NotifyModified(EditBox editBox)
759       {
760          CompilerConfig compiler = loadedCompiler;
761          if(compiler)
762          {
763             compiler.cppCommand = editBox.contents;
764             modifiedDocument = true;
765             compilersTab.modifiedDocument = true;
766          }
767          return true;
768       }
769    };
770    Label ccLabel { this, position = { 8, 142 }, labeledWindow = cc, tabCycle = false, inactive = true };
771    PathBox cc
772    {
773       this, anchor = { left = margin, top = 138, right = 8 };
774       text = $"C Compiler", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
775    };
776    Label cxxLabel { this, position = { 8, 168 }, labeledWindow = cxx, tabCycle = false, inactive = true };
777    PathBox cxx
778    {
779       this, anchor = { left = margin, top = 164, right = 8 };
780       text = $"C++ Compiler", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
781    };
782    Label arLabel { this, position = { 8, 194 }, labeledWindow = ar, tabCycle = false, inactive = true };
783    PathBox ar
784    {
785       this, anchor = { left = margin, top = 190, right = 8 };
786       text = $"AR", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
787    };
788    Label ldLabel { this, position = { 8, 220 }, labeledWindow = ld, tabCycle = false, inactive = true };
789    PathBox ld
790    {
791       this, anchor = { left = margin, top = 216, right = 8 };
792       text = $"Linker", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
793    };
794    Label makeLabel { this, position = { 8, 246 }, labeledWindow = make, tabCycle = false, inactive = true };
795    PathBox make
796    {
797       this, anchor = { left = margin, top = 242, right = 8 };
798       text = $"GNU Make", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
799    };
800    Label gnuToolchainPrefixLabel { this, position = { 8, 272 }, labeledWindow = gnuToolchainPrefix, tabCycle = false, inactive = true };
801    PathBox gnuToolchainPrefix
802    {
803       this, anchor = { left = margin, top = 268, right = 8 };
804       text = $"GNU Toolchain Prefix", typeExpected = directory, browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
805    };
806    Label sysrootLabel { this, position = { 8, 298 }, labeledWindow = sysroot, tabCycle = false, inactive = true };
807    PathBox sysroot
808    {
809       this, anchor = { left = margin, top = 294, right = 8 };
810       text = $"SYSROOT", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
811    };
812    Label executableLauncherLabel { this, position = { 8, 324 }, labeledWindow = executableLauncher, tabCycle = false, inactive = true };
813    PathBox executableLauncher
814    {
815       this, anchor = { left = margin, top = 320, right = 8 };
816       text = $"Executable Launcher", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
817    };
818
819    bool NotifyModifiedDocument(PathBox pathBox)
820    {
821       CompilerConfig compiler = loadedCompiler;
822       if(compiler)
823       {
824          BasicValidatePathBoxPath(pathBox);
825          if(pathBox == ecp)
826             compiler.ecpCommand = pathBox.slashPath;
827          else if(pathBox == ecc)
828             compiler.eccCommand = pathBox.slashPath;
829          else if(pathBox == ecs)
830             compiler.ecsCommand = pathBox.slashPath;
831          else if(pathBox == ear)
832             compiler.earCommand = pathBox.slashPath;
833          /*else if(pathBox == cpp)
834             compiler.cppCommand = pathBox.slashPath;*/
835          else if(pathBox == cc)
836             compiler.ccCommand = pathBox.slashPath;
837          else if(pathBox == cxx)
838             compiler.cxxCommand = pathBox.slashPath;
839          else if(pathBox == ld)
840             compiler.ldCommand = pathBox.slashPath;
841          else if(pathBox == ar)
842             compiler.arCommand = pathBox.slashPath;
843          else if(pathBox == make)
844             compiler.makeCommand = pathBox.slashPath;
845          else if(pathBox == executableLauncher)
846             compiler.executableLauncher = pathBox.slashPath;
847          else if(pathBox == gnuToolchainPrefix)
848             compiler.gccPrefix = pathBox.slashPath;
849          else if(pathBox == sysroot)
850             compiler.sysroot = pathBox.slashPath;
851          modifiedDocument = true;
852          compilersTab.modifiedDocument = true;
853       }
854       return true;
855    }
856
857    void Load()
858    {
859       CompilerConfig compiler = loadedCompiler;
860       if(compiler)
861       {
862          bool disabled = compiler.readOnly;
863          bool isVC = compiler.type.isVC;
864          ecp.path = compiler.ecpCommand;
865          ecc.path = compiler.eccCommand;
866          ecs.path = compiler.ecsCommand;
867          ear.path = compiler.earCommand;
868          //cpp.path = compiler.cppCommand;
869          cpp.contents = compiler.cppCommand;
870          cc.path = compiler.ccCommand;
871          cxx.path = compiler.cxxCommand;
872          ld.path = compiler.ldCommand;
873          ar.path = compiler.arCommand;
874          make.path = compiler.makeCommand;
875          executableLauncher.path = compiler.executableLauncher;
876          gnuToolchainPrefix.path = compiler.gnuToolchainPrefix;
877          sysroot.path = compiler.sysroot;
878
879          ecpLabel.disabled = ecp.disabled = disabled;
880          eccLabel.disabled = ecc.disabled = disabled;
881          ecsLabel.disabled = ecs.disabled = disabled;
882          earLabel.disabled = ear.disabled = disabled;
883          cppLabel.disabled = cpp.disabled = isVC || disabled;
884          cxxLabel.disabled = cxx.disabled = isVC || disabled;
885          ccLabel.disabled = cc.disabled = isVC || disabled;
886          ldLabel.disabled = ld.disabled = isVC || disabled;
887          arLabel.disabled = ar.disabled = isVC || disabled;
888          makeLabel.disabled = make.disabled = disabled;
889          executableLauncherLabel.disabled = executableLauncher.disabled = disabled;
890          gnuToolchainPrefixLabel.disabled = gnuToolchainPrefix.disabled = disabled;
891          sysrootLabel.disabled = sysroot.disabled = disabled;
892       }
893       modifiedDocument = false;
894    }
895 }
896
897 class CompilerEnvironmentTab : CompilersSubTab
898 {
899    background = formColor;
900    text = $"Environment";
901
902    Label labelEnvVars { envVars, labeledWindow = envVars, position = { 0, 6 }; };
903    NamedStringsBox envVars
904    {
905       this, size = { 290, 22 }, anchor = { left = 8, top = 8, right = 8, bottom = 8 };
906       text = $"Environment Variables", hotKey = altE; //, option = OPTION(postbuildCommands);
907
908       bool NotifyModified(NamedStringsBox stringsBox)
909       {
910          CompilerConfig compiler = loadedCompiler;
911          if(compiler)
912          {
913             compiler.environmentVars = stringsBox.namedStrings;
914             modifiedDocument = true;
915             compilersTab.modifiedDocument = true;
916          }
917          return true;
918       }
919    };
920
921    CompilerEnvironmentTab()
922    {
923    }
924
925    void Load()
926    {
927       CompilerConfig compiler = loadedCompiler;
928       if(compiler)
929       {
930          envVars.namedStrings = compiler.environmentVars;
931
932          modifiedDocument = false;
933       }
934    }
935 }
936
937 class CompilerOptionsTab : CompilersSubTab
938 {
939    background = formColor;
940    text = $"Options";
941
942    Label labelTargetPlatform { this, position = { 8, 12 }, labeledWindow = targetPlatform };   // TOCHECK: nameless instances dissapear when selecting tabs?
943    DropBox targetPlatform
944    {
945       this, position = { 110, 8 }, size = { 160 };
946       text = $"Target Platform", hotKey = altT;
947       bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
948       {
949          CompilerConfig compiler = loadedCompiler;
950          if(compiler && row)
951          {
952             compiler.targetPlatform = (Platform)row.tag;
953             modifiedDocument = true;
954             compilersTab.modifiedDocument = true;
955          }
956          return true;
957       }
958    };
959
960    int numJobs;
961    Label numJobsLabel { this, position = { 8, 40 }, labeledWindow = numJobsBox };
962    DataBox numJobsBox
963    {
964       this, text = $"Number of parallel build jobs", hotKey = altJ, borderStyle = deep;
965       position = { 244, 36 }, size = { 80, 20 }, type = class(int), data = &numJobs;
966
967       bool OnKeyDown(Key key, unichar ch)
968       {
969          if((SmartKey)key == enter)
970          {
971             DataBox::OnKeyDown(key, ch);
972             return true;
973          }
974          else
975             return DataBox::OnKeyDown(key, ch);
976       }
977
978       bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
979       {
980          if(!active)
981          {
982             if(!SaveData())
983                Refresh();
984          }
985          return true;
986       }
987
988       bool NotifyChanged(DataBox dataBox, bool closingDropDown)
989       {
990          CompilerConfig compiler = loadedCompiler;
991          if(compiler)
992          {
993             compiler.numJobs = numJobs;
994             modifiedDocument = true;
995             compilersTab.modifiedDocument = true;
996          }
997          return true;
998       }
999    };
1000
1001    Button ccacheEnabled
1002    {
1003       this, text = $"Use ccache", hotKey = altC, position = { 8, 68 };
1004       isCheckbox = true;
1005
1006       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1007       {
1008          CompilerConfig compiler = loadedCompiler;
1009          if(compiler)
1010          {
1011             compiler.ccacheEnabled = button.checked;
1012             modifiedDocument = true;
1013             compilersTab.modifiedDocument = true;
1014          }
1015          return true;
1016       }
1017    };
1018
1019    Button distccEnabled
1020    {
1021       this, text = $"Use distcc", position = { 158, 68 };
1022       isCheckbox = true;
1023
1024       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1025       {
1026          CompilerConfig compiler = loadedCompiler;
1027          if(compiler)
1028          {
1029             distccHostsLabel.disabled = distccHosts.disabled = !button.checked;
1030             compiler.distccEnabled = button.checked;
1031             modifiedDocument = true;
1032             compilersTab.modifiedDocument = true;
1033          }
1034          return true;
1035       }
1036    };
1037
1038    Label distccHostsLabel { this, position = { 240, 68 }, labeledWindow = distccHosts };
1039    EditBox distccHosts
1040    {
1041       this, text = $"distcc hosts", hotKey = altH;
1042       position = { 320, 64 }, size = { 160, 22 };
1043
1044       bool NotifyModified(EditBox editBox)
1045       {
1046          CompilerConfig compiler = loadedCompiler;
1047          if(compiler)
1048          {
1049             compiler.distccHosts = editBox.contents;
1050             modifiedDocument = true;
1051             compilersTab.modifiedDocument = true;
1052          }
1053          return true;
1054       }
1055    };
1056
1057    Label lblPrepDefs { this, position = { 8, 96 }, labeledWindow = prepDefs };
1058    StringListBox prepDefs
1059    {
1060       this, text = $"Preprocessor directives", hotKey = altP;
1061       position = { 168, 94 }, size = { 280, 22 }, anchor = { left = 168, top = 94, right = 8 };
1062
1063       bool NotifyModified(EditBox editBox)
1064       {
1065          if(loadedCompiler)
1066          {
1067             CompilerConfig compiler = loadedCompiler;
1068             compiler.prepDirectives = ((StringListBox)editBox).strings;
1069             modifiedDocument = true;
1070             compilersTab.modifiedDocument = true;
1071          }
1072          return true;
1073       }
1074    };
1075
1076    Label leCcompilerFlags { this, position = { 8, 126 }, labeledWindow = eCcompilerFlags };
1077    StringListBox eCcompilerFlags
1078    {
1079       this, text = $"Additional eC compiler flags", hotKey = altG;
1080       position = { 168, 124 }, size = { 280, 22 }, anchor = { left = 168, top = 124, right = 8 };
1081
1082       bool NotifyModified(EditBox editBox)
1083       {
1084          if(loadedCompiler)
1085          {
1086             CompilerConfig compiler = loadedCompiler;
1087             compiler.eCcompilerFlags = ((StringListBox)editBox).strings;
1088             modifiedDocument = true;
1089             compilersTab.modifiedDocument = true;
1090          }
1091          return true;
1092       }
1093    };
1094
1095    Label lblCompilerFlags { this, position = { 8, 156 }, labeledWindow = compilerFlags };
1096    StringListBox compilerFlags
1097    {
1098       this, text = $"Additional C compiler flags", hotKey = altR;
1099       position = { 168, 154 }, size = { 280, 22 }, anchor = { left = 168, top = 154, right = 8 };
1100
1101       bool NotifyModified(EditBox editBox)
1102       {
1103          if(loadedCompiler)
1104          {
1105             CompilerConfig compiler = loadedCompiler;
1106             compiler.compilerFlags = ((StringListBox)editBox).strings;
1107             modifiedDocument = true;
1108             compilersTab.modifiedDocument = true;
1109          }
1110          return true;
1111       }
1112    };
1113
1114    Label lblcxxFlags { this, position = { 8, 186 }, labeledWindow = cxxFlags };
1115    StringListBox cxxFlags
1116    {
1117       this, text = $"Additional C++ compiler flags", hotKey = altD;
1118       position = { 168, 184 }, size = { 280, 22 }, anchor = { left = 168, top = 184, right = 8 };
1119
1120       bool NotifyModified(EditBox editBox)
1121       {
1122          if(loadedCompiler)
1123          {
1124             CompilerConfig compiler = loadedCompiler;
1125             compiler.cxxFlags = ((StringListBox)editBox).strings;
1126             modifiedDocument = true;
1127             compilersTab.modifiedDocument = true;
1128          }
1129          return true;
1130       }
1131    };
1132
1133    Label lblLinkerFlags { this, position = { 8, 216 }, labeledWindow = linkerFlags };
1134    StringListBox linkerFlags
1135    {
1136       this, text = $"Additional linker flags", hotKey = altL;
1137       position = { 168, 214 }, size = { 280, 22 }, anchor = { left = 168, top = 214, right = 8 };
1138
1139       bool NotifyModified(EditBox editBox)
1140       {
1141          if(loadedCompiler)
1142          {
1143             CompilerConfig compiler = loadedCompiler;
1144             compiler.linkerFlags = ((StringListBox)editBox).strings;
1145             modifiedDocument = true;
1146             compilersTab.modifiedDocument = true;
1147          }
1148          return true;
1149       }
1150    };
1151
1152    Label lblExcludedLibraries { this, position = { 8, 246 }, labeledWindow = excludedLibraries };
1153    StringListBox excludedLibraries
1154    {
1155       this, text = $"Libraries to exclude", hotKey = altX;
1156       position = { 168, 244 }, size = { 280, 22 }, anchor = { left = 168, top = 244, right = 8 };
1157
1158       bool NotifyModified(EditBox editBox)
1159       {
1160          if(loadedCompiler)
1161          {
1162             CompilerConfig compiler = loadedCompiler;
1163             compiler.excludeLibs = ((StringListBox)editBox).strings;
1164             modifiedDocument = true;
1165             compilersTab.modifiedDocument = true;
1166          }
1167          return true;
1168       }
1169    };
1170
1171    Label objectFileExtLabel { this, position = { 8, 276 }, labeledWindow = objectFileExt };
1172    EditBox objectFileExt
1173    {
1174       this, text = $"Object file extension";//, hotKey = altH;
1175       position = { 168, 274 }, size = { 80, 22 };
1176
1177       bool NotifyModified(EditBox editBox)
1178       {
1179          CompilerConfig compiler = loadedCompiler;
1180          if(compiler)
1181          {
1182             compiler.objectFileExt = editBox.contents;
1183             modifiedDocument = true;
1184             compilersTab.modifiedDocument = true;
1185          }
1186          return true;
1187       }
1188    };
1189
1190    Label staticLibFileExtLabel { this, position = { 8, 306 }, labeledWindow = staticLibFileExt };
1191    EditBox staticLibFileExt
1192    {
1193       this, text = $"Target extensions (a, so, exe)";//, hotKey = altH;
1194       position = { 168, 304 }, size = { 80, 22 };
1195
1196       bool NotifyModified(EditBox editBox)
1197       {
1198          CompilerConfig compiler = loadedCompiler;
1199          if(compiler)
1200          {
1201             compiler.staticLibFileExt = editBox.contents;
1202             modifiedDocument = true;
1203             compilersTab.modifiedDocument = true;
1204          }
1205          return true;
1206       }
1207    };
1208    EditBox sharedLibFileExt
1209    {
1210       this;
1211       position = { 256, 304 }, size = { 80, 22 };
1212
1213       bool NotifyModified(EditBox editBox)
1214       {
1215          CompilerConfig compiler = loadedCompiler;
1216          if(compiler)
1217          {
1218             compiler.sharedLibFileExt = editBox.contents;
1219             modifiedDocument = true;
1220             compilersTab.modifiedDocument = true;
1221          }
1222          return true;
1223       }
1224    };
1225    EditBox executableFileExt
1226    {
1227       this;
1228       position = { 344, 304 }, size = { 80, 22 };
1229
1230       bool NotifyModified(EditBox editBox)
1231       {
1232          CompilerConfig compiler = loadedCompiler;
1233          if(compiler)
1234          {
1235             compiler.executableFileExt = editBox.contents;
1236             modifiedDocument = true;
1237             compilersTab.modifiedDocument = true;
1238          }
1239          return true;
1240       }
1241    };
1242
1243    Button stripTarget
1244    {
1245       this, text = $"Strip target", hotKey = altC, position = { 168, 332 };
1246       isCheckbox = true;
1247
1248       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1249       {
1250          CompilerConfig compiler = loadedCompiler;
1251          if(compiler)
1252          {
1253             compiler.noStripTarget = !button.checked;
1254             modifiedDocument = true;
1255             compilersTab.modifiedDocument = true;
1256          }
1257          return true;
1258       }
1259    };
1260
1261    Button resourcesDotEar
1262    {
1263       this, text = $"Use resources.ear", position = { 308, 332 };
1264       isCheckbox = true;
1265
1266       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1267       {
1268          CompilerConfig compiler = loadedCompiler;
1269          if(compiler)
1270          {
1271             compiler.resourcesDotEar = button.checked;
1272             modifiedDocument = true;
1273             compilersTab.modifiedDocument = true;
1274          }
1275          return true;
1276       }
1277    };
1278
1279    CompilerOptionsTab()
1280    {
1281       Platform p;
1282       DataRow row;
1283       for(p = (Platform)1; p < Platform::enumSize; p++)
1284       {
1285          row = targetPlatform.AddRow();
1286          row.tag = p;
1287          row.string = p;
1288       }
1289    }
1290
1291    void Load()
1292    {
1293       CompilerConfig compiler = loadedCompiler;
1294       if(compiler)
1295       {
1296          bool disabled = compiler.readOnly;
1297          targetPlatform.currentRow = targetPlatform.FindRow(compiler.targetPlatform);
1298          numJobs = compiler.numJobs;
1299          numJobsBox.Refresh();
1300          ccacheEnabled.checked = compiler.ccacheEnabled;
1301          distccEnabled.checked = compiler.distccEnabled;
1302          distccHostsLabel.disabled = distccHosts.disabled = !compiler.distccEnabled;
1303          distccHosts.contents = compiler.distccHosts;
1304          prepDefs.strings = compiler.prepDirectives;
1305          excludedLibraries.strings = compiler.excludeLibs;
1306          eCcompilerFlags.strings = compiler.eCcompilerFlags;
1307          compilerFlags.strings = compiler.compilerFlags;
1308          cxxFlags.strings = compiler.cxxFlags;
1309          linkerFlags.strings = compiler.linkerFlags;
1310          objectFileExt.contents = compiler.objectFileExt;
1311          staticLibFileExt.contents = compiler.staticLibFileExt;
1312          sharedLibFileExt.contents = compiler.sharedLibFileExt;
1313          executableFileExt.contents = compiler.executableFileExt;
1314          stripTarget.checked = !compiler.noStripTarget;
1315          resourcesDotEar.checked = compiler.resourcesDotEar;
1316
1317          labelTargetPlatform.disabled = disabled;
1318          targetPlatform.disabled = disabled;
1319
1320       }
1321       modifiedDocument = false;
1322    }
1323 }
1324
1325 class CompilersSubTab : Tab
1326 {
1327    property CompilersTab compilersTab
1328    {
1329       get
1330       {
1331          CompilersTab tab = (CompilersTab)master;
1332          while(tab && tab._class != class(CompilersTab))
1333             tab = (CompilersTab)tab.master;
1334          return tab;
1335       }
1336    };
1337
1338    property CompilerConfig loadedCompiler
1339    {
1340       get
1341       {
1342          CompilersTab tab = compilersTab;
1343          return tab ? tab.activeCompiler : null;
1344       }
1345    };
1346 }
1347
1348 class ProjectOptionsTab : GlobalSettingsSubTab
1349 {
1350    background = formColor;
1351    text = $"Project";
1352
1353    Label defaultTargetDirLabel { this, position = { 8, 34 }, labeledWindow = defaultTargetDir };
1354    PathBox defaultTargetDir
1355    {
1356       this, size = { 160, 21 }, position = { 8, 52 }, anchor = { left = 8, top = 52, right = 8 };
1357       text = $"Default Target Directory", hotKey = altT;
1358
1359       bool NotifyModified(PathBox pathBox)
1360       {
1361          BasicValidatePathBoxPath(pathBox);
1362          modifiedDocument = true;
1363          return true;
1364       }
1365    };
1366
1367    Label defaultIntermediateObjDirLabel { this, position = { 8, 78 }, labeledWindow = defaultIntermediateObjDir };
1368    PathBox defaultIntermediateObjDir
1369    {
1370       this, size = { 160, 21 }, position = { 8, 96 }, anchor = { left = 8, top = 96, right = 8 };
1371       text = $"Default Intermediate Objects Directory", hotKey = altI;
1372
1373       bool NotifyModified(PathBox pathBox)
1374       {
1375          BasicValidatePathBoxPath(pathBox);
1376          modifiedDocument = true;
1377          return true;
1378       }
1379    };
1380 }
1381
1382 // COMPILER TOFIX: if class GlobalSettingsSubTab is after class WorkspaceOptionsTab the OnPostCreate
1383 //                 of WorkspaceOptionsTab will *not* be called!
1384 class GlobalSettingsSubTab : Tab
1385 {
1386    property GlobalSettingsDialog dialog
1387    {
1388       get
1389       {
1390          GlobalSettingsDialog dialog = (GlobalSettingsDialog)master;
1391          while(dialog && dialog._class != class(GlobalSettingsDialog))
1392             dialog = (GlobalSettingsDialog)dialog.master;
1393          return dialog;
1394       }
1395    };
1396 }
1397
1398 class WorkspaceOptionsTab : GlobalSettingsSubTab
1399 {
1400    background = formColor;
1401    text = $"Workspace";
1402
1403    Label defaultCompilerLabel { this, position = { 8, 14 }, labeledWindow = defaultCompilerDropBox };
1404    DropBox defaultCompilerDropBox
1405    {
1406       this, position = { 140, 8 }, size = { 220 };
1407       text = $"Default Compiler", hotKey = altA;
1408
1409       bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
1410       {
1411          modifiedDocument = true;
1412          return true;
1413       }
1414    };
1415
1416    bool OnCreate()
1417    {
1418       GlobalSettingsDialog dialog = this.dialog;
1419       if(dialog && dialog.compilersTab.compilerConfigs && ideSettings)
1420       {
1421          DataRow row;
1422          for(compiler : ideConfig.compilers)
1423          {
1424             row = defaultCompilerDropBox.AddString(compiler.name);
1425             if(ideSettings.defaultCompiler && ideSettings.defaultCompiler[0] &&
1426                   !strcmp(compiler.name, ideSettings.defaultCompiler))
1427                defaultCompilerDropBox.currentRow = row;
1428          }
1429          if(!defaultCompilerDropBox.currentRow && defaultCompilerDropBox)
1430             defaultCompilerDropBox.currentRow = defaultCompilerDropBox.firstRow;
1431       }
1432       return true;
1433    }
1434
1435    void OnDestroy()
1436    {
1437       // TOFIX: The selection will be lost upon changing tab...
1438       // Should either warn, or leave it modified and put in place
1439       // checks to save/find the compiler by name
1440       defaultCompilerDropBox.Clear();
1441       modifiedDocument = false;
1442    }
1443 }
1444
1445 //static define app = ((GuiApplication)__thisModule);