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