ecere/ide: Added DirPath/FilePath support in DataBox (tweaked PathBox), Merged PathBo...
[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 = activeBorder;
16    hasClose = true;
17    borderStyle = sizable;
18    text = "Global Settings";
19    minClientSize = { 560, 420 };
20    nativeDecorations = true;
21
22    IDESettings ideSettings;
23    IDESettingsContainer settingsContainer;
24    String workspaceActiveCompiler;
25    
26    TabControl tabControl { this, background = activeBorder, anchor = { left = 8, top = 8, right = 8, bottom = 40 } };
27    
28    EditorTab editorTab { this, tabControl = tabControl };
29    CompilersTab compilersTab { this, tabControl = tabControl };
30    ProjectOptionsTab projectOptionsTab { this, tabControl = tabControl };
31    WorkspaceOptionsTab workspaceOptionsTab { this, tabControl = tabControl };
32    
33    property bool settingsModified
34    {
35       get
36       {
37          return editorTab.modifiedDocument || compilersTab.modifiedDocument ||
38                projectOptionsTab.modifiedDocument || workspaceOptionsTab.modifiedDocument;
39       }
40    }
41
42    Button cancel
43    {
44       parent = this, hotKey = escape, text = "Cancel", id = DialogResult::cancel;
45       position = { 290, 290 }, size = { 80 };
46       anchor = { right = 8, bottom = 8 };
47
48       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
49       {
50          if(!settingsModified || MessageBox {
51             type = okCancel, master = ide,
52             text = "Lose Changes?",
53             contents = "Are you sure you wish to discard changes?"
54              }.Modal() == ok)
55             Destroy(0);
56          return true;
57       }
58    };
59
60    Button ok
61    {
62       parent = this, isDefault = true, text = "OK";
63       position = { 200, 290 }, size = { 90 };
64       anchor = { right = 96, bottom = 8 };
65
66       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
67       {
68          if(settingsModified)
69          {
70             bool editorSettingsChanged = false;
71             bool compilerSettingsChanged = false;
72             bool projectOptionsChanged = false;
73             bool workspaceOptionsChanged = false;
74             
75             if(editorTab.modifiedDocument)
76             {
77                if(editorTab.useFreeCaret.checked != ideSettings.useFreeCaret ||
78                      editorTab.showLineNumbers.checked != ideSettings.showLineNumbers ||
79                      editorTab.caretFollowsScrolling.checked != ideSettings.caretFollowsScrolling)
80                {
81                   ideSettings.useFreeCaret = editorTab.useFreeCaret.checked;
82                   ideSettings.showLineNumbers = editorTab.showLineNumbers.checked;
83                   ideSettings.caretFollowsScrolling = editorTab.caretFollowsScrolling.checked;
84                   editorSettingsChanged = true;
85                }
86             }
87             
88             if(compilersTab.modifiedDocument)
89             {
90                ideSettings.compilerConfigs.Free();
91                for(compiler : compilersTab.compilerConfigs)
92                   ideSettings.compilerConfigs.Add(compiler.Copy());
93                compilerSettingsChanged = true;
94             }
95
96             if(projectOptionsTab.modifiedDocument)
97             {
98                if(strcmp(projectOptionsTab.defaultTargetDir.path, ideSettings.projectDefaultTargetDir)
99                      || strcmp(projectOptionsTab.defaultIntermediateObjDir.path, ideSettings.projectDefaultIntermediateObjDir))
100                {
101                   ideSettings.projectDefaultTargetDir = projectOptionsTab.defaultTargetDir.path;
102                   ideSettings.projectDefaultIntermediateObjDir = projectOptionsTab.defaultIntermediateObjDir.path;
103                   projectOptionsChanged = true;
104                }
105             }
106
107             if(workspaceOptionsTab.modifiedDocument)
108             {
109                DataRow row = workspaceOptionsTab.defaultCompilerDropBox.currentRow;
110                if(row && row.string)
111                {
112                   if(!ideSettings.defaultCompiler || strcmp(row.string, ideSettings.defaultCompiler))
113                   {
114                      ideSettings.defaultCompiler = row.string;
115                      workspaceOptionsChanged = true;
116                   }
117                }
118             }
119
120             settingsContainer.Save();
121
122             if(compilerSettingsChanged)
123                OnGlobalSettingChange(GlobalSettingsChange::compilerSettings);
124             if(editorSettingsChanged)
125                OnGlobalSettingChange(GlobalSettingsChange::editorSettings);
126             if(projectOptionsChanged)
127                OnGlobalSettingChange(GlobalSettingsChange::projectOptions);
128          }
129          
130          Destroy(DialogResult::ok);
131          return true;
132       }
133    };
134
135    /*
136    void Temp()
137    {
138       DirTypes c;
139       for(c = 0; c < DirTypes::enumSize; c++)
140       {
141          CompilerDir compilerDir;
142
143          for(systemDir : ideSettings.systemDirs[c])
144          {
145             compilerDir = CompilerDir { type = c; compilerConfig = null; path = CopyString(systemDir) };
146             dirs.Add(compilerDir);
147          }
148
149          row = compilersTab.dirs[c].AddRow();
150          row.SetData(null, "");
151          compilersTab.dirs[c].currentRow = compilersTab.dirs[c].firstRow;
152          compilersTab.dirs[c].modifiedDocument = false;
153       }
154    }
155    */
156
157    bool OnCreate()
158    {
159       CompilerConfig activateCompiler = null;
160       CompilerConfig readonlyCompiler = null;
161
162       // EditorTab
163       editorTab.useFreeCaret.checked = ideSettings.useFreeCaret;
164       editorTab.showLineNumbers.checked = ideSettings.showLineNumbers;
165       editorTab.caretFollowsScrolling.checked = ideSettings.caretFollowsScrolling;
166
167       // CompilersTab
168       if(workspaceActiveCompiler)
169       {
170          for(compiler : ideSettings.compilerConfigs)
171          {
172             if(!activateCompiler && !strcmp(workspaceActiveCompiler, compiler.name))
173                activateCompiler = compiler;
174             if(!readonlyCompiler && compiler.readOnly)
175                readonlyCompiler = compiler;
176             if(activateCompiler && readonlyCompiler)
177                break;
178          }
179       }
180       if(!activateCompiler && readonlyCompiler)
181          activateCompiler = readonlyCompiler;
182       if(!activateCompiler && ideSettings.compilerConfigs.count)
183          activateCompiler = ideSettings.compilerConfigs[0];
184       
185       for(compiler : ideSettings.compilerConfigs)
186          compilersTab.AddCompiler(compiler.Copy(), compiler == activateCompiler);
187
188       // ProjectOptionsTab
189       projectOptionsTab.defaultTargetDir.path = ideSettings.projectDefaultTargetDir;
190       projectOptionsTab.defaultIntermediateObjDir.path = ideSettings.projectDefaultIntermediateObjDir;
191       
192       return true;
193    }
194
195    void OnDestroy()
196    {
197       editorTab.modifiedDocument = false;
198       compilersTab.modifiedDocument = false;
199       compilersTab.dirsTab.modifiedDocument = false;
200       compilersTab.toolchainTab.modifiedDocument = false;
201       compilersTab.optionsTab.modifiedDocument = false;
202       compilersTab.activeCompiler = null;
203       compilersTab.compilerConfigs.Free();
204       compilersTab.compilerSelector.Clear();
205       projectOptionsTab.modifiedDocument = false;
206       workspaceOptionsTab.modifiedDocument = false;
207    }
208
209    virtual void OnGlobalSettingChange(GlobalSettingsChange globalSettingsChange);
210 }
211
212 class EditorTab : GlobalSettingsSubTab
213 {
214    background = activeBorder;
215    text = "Editor";
216
217    Button useFreeCaret
218    {
219       this, text = "Move code editor caret freely past end of line", position = { 16, 68 }, isCheckbox = true;
220       NotifyClicked = NotifyClickedModifiedDocument;
221    };
222
223    Button caretFollowsScrolling
224    {
225       this, text = "Keep caret visible (move along) when scrolling", position = { 16, 88 }, isCheckbox = true;
226       NotifyClicked = NotifyClickedModifiedDocument;
227    };
228
229    Button showLineNumbers
230    {
231       this, text = "Show line numbers in code editor", position = { 16, 108 }, isCheckbox = true;
232       NotifyClicked = NotifyClickedModifiedDocument;
233    };
234
235    bool NotifyClickedModifiedDocument(Button button, int x, int y, Modifiers mods)
236    {
237       modifiedDocument = true;
238       return true;
239    }
240 }
241
242 static void DrawStipple(Surface surface, Size clientSize)
243 {
244    int x1 = 0;
245    int y1 = 0;
246    int x2 = clientSize.w - 1;
247    int y2 = clientSize.h - 1;
248    if((x2 - x1) & 1) x2--;
249    if((y2 - y1) & 1) y2--;
250
251    surface.LineStipple(0x5555);
252    surface.Rectangle(x1, y1, x2, y2);
253    surface.LineStipple(0);            
254 }
255
256 class CompilersTab : GlobalSettingsSubTab
257 {
258    background = activeBorder;
259    text = "Compilers";
260
261    SelectorBar compilerSelector
262    {
263       this, text = "Compiler Configurations:", anchor = { left = 148, top = 8, right = 99 }; size = { 0, 26 };
264       opacity = 0;
265       direction = horizontal, scrollable = true;
266
267       bool OnKeyDown(Key key, unichar ch)
268       {
269          if(key == insert)
270          {
271             ((CompilersTab)parent).createCompiler.NotifyClicked(parent, ((CompilersTab)parent).createCompiler, 0, 0, 0);
272             return false;
273          }
274          else if(key == del)
275          {
276             ((CompilersTab)parent).deleteCompiler.NotifyClicked(parent, ((CompilersTab)parent).deleteCompiler, 0, 0, 0);
277             return false;
278          }
279          return SelectorBar::OnKeyDown(key, ch);
280       }
281       
282       bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
283       {
284          ((CompilersTab)master).labelCompilers.Update(null);
285          return true;
286       }
287
288       bool OnPostCreate()
289       {
290          SelectorBar::OnPostCreate();
291          if(((CompilersTab)parent).selectedButton)
292          {
293             ((CompilersTab)parent).selectedButton.Activate();
294             ((CompilersTab)parent).selectedButton.checked = true;
295             ((CompilersTab)parent).selectedButton = null;
296          }
297          return true;
298       }
299    };
300
301    TabControl tabControl { this, background = activeBorder, anchor = { left = 8, top = 38, right = 8, bottom = 8 } };
302    
303    CompilerDirectoriesTab dirsTab { this, tabControl = tabControl };
304    CompilerToolchainTab toolchainTab { this, tabControl = tabControl };
305    CompilerEnvironmentTab environmentTab { this, tabControl = tabControl };
306    CompilerOptionsTab optionsTab { this, tabControl = tabControl };
307
308    List<CompilerConfig> compilerConfigs { };
309    CompilerConfig activeCompiler;
310
311    Label labelCompilers
312    {
313       this, anchor = { left = 8, top = 14 }, labeledWindow = compilerSelector;
314
315       void OnRedraw(Surface surface)
316       {
317          Label::OnRedraw(surface);
318          if(labeledWindow.active)
319             DrawStipple(surface, clientSize);
320       }
321    };
322
323    void FindUniqueCompilerName(char * baseName, CompilerConfig compiler/*, bool startWithNumber*/, char * output)
324    {
325       int num = 0;
326       char tmp[MAX_F_STRING];
327       /*if(startWithNumber)
328          sprintf(tmp, "%s%d", baseName, num);
329       else*/
330          strcpy(tmp, baseName);
331       while(true)
332       {
333          CompilerConfig matchingCompiler = null;
334          for(c : compilerConfigs)
335          {     // TOFIX: Error when omitting these brackets, c not found
336             if((!compiler || c != compiler) && c.name && !strcmp(c.name, tmp))
337             {
338                matchingCompiler = c;
339                break;
340             }
341          }
342          if(matchingCompiler)
343          {
344             num++;
345             sprintf(tmp, "%s%d", baseName, num);
346          }
347          else
348             break;
349       }
350       strcpy(output, tmp);
351    }
352
353    Button createCompiler
354    {
355       parent = this, bevelOver = true, inactive = true;
356       size = { 22, 22 };
357       anchor = { top = 10, right = 77 };
358       hotKey = altC, bitmap = BitmapResource { fileName = ":actions/docNew.png", alphaBlend = true };
359
360       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
361       {
362          char compilerName[MAX_F_STRING];
363          CompilerConfig newCompiler;
364          FindUniqueCompilerName("New Compiler", null, compilerName);
365          newCompiler = MakeDefaultCompiler(compilerName, false);
366          AddCompiler(newCompiler, true);
367          modifiedDocument = true;
368          return true;
369       }
370    };
371    Button detectCompiler
372    {
373       parent = this, bevelOver = true, inactive = true;
374       size = { 22, 22 };
375       anchor = { top = 10, right = 54 };
376       hotKey = altC, bitmap = BitmapResource { fileName = ":actions/attach.png", alphaBlend = true };
377
378       bool NotifyClicked(Button b, int x, int y, Modifiers mods)
379       {
380          CompilersDetectionDialog compilersDetectionDialog
381          {
382             dialog.parent;
383
384          };
385          if(compilersDetectionDialog.Modal())
386          {
387             if(compilersDetectionDialog.selectedCompilerType)
388             {
389                char uniqueName[MAX_F_STRING];
390                CompilerConfig newCompiler = compilersDetectionDialog.compilerConfig;
391                FindUniqueCompilerName(newCompiler.name, null, uniqueName);
392                newCompiler.name = uniqueName;
393                AddCompiler(newCompiler, true);
394                modifiedDocument = true;
395             }
396          }
397          return true;
398       }
399    };
400    Button duplicateCompiler
401    {
402       parent = this, bevelOver = true, inactive = true;
403       size = { 22, 22 };
404       anchor = { top = 10, right = 31 };
405       hotKey = altU, bitmap = BitmapResource { fileName = ":actions/editCopy.png", alphaBlend = true };
406
407       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
408       {
409          char copyName[MAX_F_STRING];
410          CompilerConfig copyCompiler = activeCompiler.Copy();
411          FindUniqueCompilerName(copyCompiler.name, null, copyName);
412          copyCompiler.readOnly = false;
413          copyCompiler.name = copyName;
414          AddCompiler(copyCompiler, true);
415          modifiedDocument = true;
416          return true;
417       }
418    };
419    Button deleteCompiler
420    {
421       parent = this, bevelOver = true, inactive = true;
422       size = { 22, 22 };
423       anchor = { top = 10, right = 8 };
424       hotKey = altD, bitmap = BitmapResource { fileName = ":actions/delete2.png", alphaBlend = true };
425
426       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
427       {
428          if(activeCompiler)
429          {
430             CompilerConfig compilerToDelete = activeCompiler;
431             String title = PrintString("Delete ", compilerToDelete.name, " Compiler Configuration");
432             String msg = PrintString("Are you sure you wish to delete the ", compilerToDelete.name, " compiler configuration?");
433             if(MessageBox { type = okCancel, text = title, contents = msg }.Modal() == ok)
434             {
435                SelectorButton button = compilerSelector.FindButtonByID((int)compilerToDelete);
436                if(button)
437                   compilerSelector.RemoveButton(button);
438                //DeleteCompiler(compilerToDelete);
439                {
440                   Iterator<CompilerConfig> it { compilerConfigs };
441                   if(it.Find(compilerToDelete))
442                      compilerConfigs.Delete(it.pointer);
443                }
444                modifiedDocument = true;
445             }
446             delete title;
447             delete msg;
448          }
449          return true;
450       }
451    };
452
453    void AddCompiler(CompilerConfig compiler, bool load)
454    {
455       SelectorButton selectButton;
456       if(compiler.readOnly)
457       {
458          SelectorButton button
459          {
460             compilerSelector, master = this, text = compiler.name, id = (int)compiler;
461             NotifyClicked = CompilerClicked;
462          };
463          selectButton = button;
464       }
465       else
466       {
467          EditableSelectorButton button
468          {
469             compilerSelector, master = this, renameable = true, text = compiler.name, id = (int)compiler;
470             NotifyClicked = CompilerClicked;
471
472             bool OnRename(EditableSelectorButton button, char ** oldName, char ** newName)
473             {
474                if(*newName && (*newName)[0])
475                {
476                   char compilerName[MAX_F_STRING];
477                   FindUniqueCompilerName(*newName, activeCompiler, compilerName);
478                   if(strcmp(*newName, compilerName))
479                   {
480                      delete *newName;
481                      *newName = CopyString(compilerName);
482                   }
483                   activeCompiler.name = compilerName;
484                   modifiedDocument = true;
485                   return true;
486                }
487                return false;
488             }
489          };
490          selectButton = (SelectorButton)button;
491       }
492       compilerConfigs.Add(compiler);
493       if(load)
494       {
495          LoadCompiler(compiler);
496          selectedButton = selectButton;
497          compilerSelector.Select(selectedButton);
498       }
499    }
500    SelectorButton selectedButton;
501
502    void LoadCompiler(CompilerConfig compiler)
503    {
504       activeCompiler = compiler;
505
506       dirsTab.Load();
507       toolchainTab.Load();
508       environmentTab.Load();
509       optionsTab.Load();
510
511       deleteCompiler.disabled = compiler.readOnly;
512    }
513
514    bool CompilerClicked(Button clickedButton, int x, int y, Modifiers mods)
515    {
516       if(!eClass_IsDerived(clickedButton._class, class(EditableSelectorButton)) || !((EditableSelectorButton)clickedButton).editBox)
517          LoadCompiler((CompilerConfig)clickedButton.id);
518       return true;
519    }
520 }
521
522 class CompilerDirectoriesTab : CompilersSubTab
523 {
524    background = activeBorder;
525    text = "Directories";
526
527    Button dirTypeTglBtn[DirTypes];
528    DirectoriesBox dirs[DirTypes], currentDirs;
529
530    ~CompilerDirectoriesTab()
531    {
532       DirTypes c;
533       for(c = 0; c < DirTypes::enumSize; c++)
534       {
535          delete dirs[c];
536          delete dirTypeTglBtn[c];
537       }
538    }
539    CompilerDirectoriesTab()
540    {
541       DirTypes c;
542       for(c = 0; c < DirTypes::enumSize; c++)
543       {
544          dirs[c] = DirectoriesBox
545          {
546             this;//, alwaysHighLight = true
547             anchor = { left = 8, top = 8, right = 8, bottom = 8 };
548             id = c;
549
550    /*   MAKE SURE THINGS ARE DONE PROPERLY IN THE NEW DIRECTORIES BOX WHEN BROWSING FOR A DIR?
551             settingsFileDialog.filePath = directory;
552          if(settingsFileDialog.Modal())
553             row.SetData(null, (s = CopyUnixPath(settingsFileDialog.filePath)));
554    */
555
556             bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
557             {
558                // DirectoriesBox's NotifyModified isn't working! Or it's not called before this?
559                if(!active && (modifiedDocument || list.modifiedDocument))
560                {
561                   CompilerDirectoriesTab dirsTab = (CompilerDirectoriesTab)parent;
562                   CompilerConfig compiler = dirsTab.loadedCompiler;
563                   if(compiler)
564                   {
565                      DirTypes dirType = (DirTypes)id;
566                      // TODO ? I think not, see DirectoriesBox.ec: CopyUnixPath() must be called when copying these dirs
567
568                      if(dirType == includes)
569                         compiler.includeDirs = strings;
570                      else if(dirType == libraries)
571                         compiler.libraryDirs = strings;
572                      else if(dirType == executables)
573                         compiler.executableDirs = strings;
574
575                      //modifiedDocument = true;
576                      dirsTab.compilersTab.modifiedDocument = true;
577                   }
578                }
579                return true;
580             }
581          };
582          incref dirs[c];
583          
584          if(c)
585             dirs[c].visible = false;
586          
587          // (width) Should be 324 for text...
588          //field[c] = { dataType = class(char *), editable = true };
589          //dirs[c].AddField(field[c]);
590
591          {
592          int v = (int)c * 100 + 8;
593          dirTypeTglBtn[c] = Button
594          {
595             this, inactive = true, text = settingsDirectoryNames[c], bevelOver = true, isRadio = true, bitmap = null;
596             stayOnTop = true;
597             id = c;
598             size = { 99, 20 };
599             anchor = { left = v, top = 8 }; // ((int)c) * 100 + 8
600
601             bool NotifyClicked(Button button, int x, int y, Modifiers mods)
602             {
603                DirTypes dirType = (DirTypes)button.id;
604                currentDirs.visible = false;
605                dirs[dirType].visible = true;
606                currentDirs = dirs[dirType];
607                return true;
608             }
609          };
610          incref dirTypeTglBtn[c];
611
612          if(c == includes)
613             dirTypeTglBtn[c].hotKey = altI;
614          else if(c == libraries)
615             dirTypeTglBtn[c].hotKey = altL;
616          else if(c == executables)
617             dirTypeTglBtn[c].hotKey = altE;
618          }
619       }   
620       currentDirs = dirs[includes];
621       dirTypeTglBtn[includes].checked = true;
622       return true;
623    }
624
625    void Load()
626    {
627       if(loadedCompiler)
628       {
629          CompilerConfig compiler = loadedCompiler;
630          dirs[includes].strings = compiler.includeDirs;
631          dirs[libraries].strings = compiler.libraryDirs;
632          dirs[executables].strings = compiler.executableDirs;
633       }
634    }
635 }
636
637 class CompilerToolchainTab : CompilersSubTab
638 {
639    background = activeBorder;
640    text = "Toolchain";
641
642    Label ecpLabel { this, position = { 8, 12 }, labeledWindow = ecp, tabCycle = false, inactive = true };
643    PathBox ecp
644    {
645       this, anchor = { left = 120, top = 8, right = 8 };
646       text = "eC Precompiler", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
647    };
648    Label eccLabel { this, position = { 8, 38 }, labeledWindow = ecc, tabCycle = false, inactive = true };
649    PathBox ecc
650    {
651       this, anchor = { left = 120, top = 34, right = 8 };
652       text = "eC Compiler", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
653    };
654    Label ecsLabel { this, position = { 8, 64 }, labeledWindow = ecs, tabCycle = false, inactive = true };
655    PathBox ecs
656    {
657       this, anchor = { left = 120, top = 60, right = 8 };
658       text = "eC Symbol Loader", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
659    };
660    Label earLabel { this, position = { 8, 90 }, labeledWindow = ear, tabCycle = false, inactive = true };
661    PathBox ear
662    {
663       this, anchor = { left = 120, top = 86, right = 8 };
664       text = "Ecere Archiver", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
665    };
666    Label cppLabel { this, position = { 8, 116 }, labeledWindow = cpp, tabCycle = false, inactive = true };
667    PathBox cpp
668    {
669       this, anchor = { left = 120, top = 112, right = 8 };
670       text = "C Preprocessor", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
671    };
672    Label ccLabel { this, position = { 8, 142 }, labeledWindow = cc, tabCycle = false, inactive = true };
673    PathBox cc
674    {
675       this, anchor = { left = 120, top = 138, right = 8 };
676       text = "C Compiler", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
677    };
678    Label makeLabel { this, position = { 8, 168 }, labeledWindow = make, tabCycle = false, inactive = true };
679    PathBox make
680    {
681       this, anchor = { left = 120, top = 164, right = 8 };
682       text = "GNU Make", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
683    };
684    Label execPrefixLabel { this, position = { 8, 194 }, labeledWindow = execPrefix, tabCycle = false, inactive = true };
685    PathBox execPrefix
686    {
687       this, anchor = { left = 120, top = 190, right = 8 };
688       text = "Execution Prefix", browseDialog = toolchainFileDialog, NotifyModified = NotifyModifiedDocument;
689    };
690
691    bool NotifyModifiedDocument(PathBox pathBox)
692    {
693       if(loadedCompiler)
694       {
695          CompilerConfig compiler = loadedCompiler;
696          if(pathBox == ecp)
697             compiler.ecpCommand = pathBox.slashPath;
698          else if(pathBox == ecc)
699             compiler.eccCommand = pathBox.slashPath;
700          else if(pathBox == ecs)
701             compiler.ecsCommand = pathBox.slashPath;
702          else if(pathBox == ear)
703             compiler.earCommand = pathBox.slashPath;
704          else if(pathBox == cpp)
705             compiler.cppCommand = pathBox.slashPath;
706          else if(pathBox == cc)
707             compiler.ccCommand = pathBox.slashPath;
708          else if(pathBox == make)
709             compiler.makeCommand = pathBox.slashPath;
710          else if(pathBox == execPrefix)
711             compiler.execPrefixCommand = pathBox.slashPath;
712          modifiedDocument = true;
713          compilersTab.modifiedDocument = true;
714       }
715       return true;
716    }
717
718    void Load()
719    {
720       if(loadedCompiler)
721       {
722          CompilerConfig compiler = loadedCompiler;
723          bool disabled = compiler.readOnly;
724          bool isVC = compiler.type.isVC;
725          ecp.path = compiler.ecpCommand;
726          ecc.path = compiler.eccCommand;
727          ecs.path = compiler.ecsCommand;
728          ear.path = compiler.earCommand;
729          cpp.path = compiler.cppCommand;
730          cc.path = compiler.ccCommand;
731          make.path = compiler.makeCommand;
732          execPrefix.path = compiler.execPrefixCommand;
733
734          ecpLabel.disabled = ecp.disabled = disabled;
735          eccLabel.disabled = ecc.disabled = disabled;
736          ecsLabel.disabled = ecs.disabled = disabled;
737          earLabel.disabled = ear.disabled = disabled;
738          cppLabel.disabled = cpp.disabled = isVC || disabled;
739          ccLabel.disabled = cc.disabled = isVC || disabled;
740          makeLabel.disabled = make.disabled = disabled;
741          execPrefixLabel.disabled = execPrefix.disabled = disabled;
742       }
743       modifiedDocument = false;
744    }
745 }
746
747 class CompilerEnvironmentTab : CompilersSubTab
748 {
749    background = activeBorder;
750    text = "Environment";
751
752    Label labelEnvVars { envVars, labeledWindow = envVars, position = { 0, 6 }; };
753    NamedStringsBox envVars
754    {
755       this, size = { 290, 22 }, anchor = { left = 8, top = 8, right = 8, bottom = 8 };
756       text = "Environment Variables", hotKey = altE; //, option = OPTION(postbuildCommands);
757
758       bool NotifyModified(NamedStringsBox stringsBox)
759       {
760          loadedCompiler.environmentVars = stringsBox.namedStrings;
761          modifiedDocument = true;
762          return true;
763       }
764    };
765
766    CompilerEnvironmentTab()
767    {
768    }
769
770    void Load()
771    {
772       if(loadedCompiler)
773       {
774          CompilerConfig compiler = loadedCompiler;
775          envVars.namedStrings = compiler.environmentVars;
776
777          // Was these meant to be false?
778          modifiedDocument = false;//true;
779          compilersTab.modifiedDocument = false;//true;
780       }
781    }
782 }
783
784 class CompilerOptionsTab : CompilersSubTab
785 {
786    background = activeBorder;
787    text = "Options";
788
789    Label labelTargetPlatform { this, position = { 8, 12 }, labeledWindow = targetPlatform };   // TOCHECK: nameless instances dissapear when selecting tabs?
790    DropBox targetPlatform
791    {
792       this, position = { 110, 8 }, size = { 160 };
793       text = "Target Platform", hotKey = altT;
794       bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
795       {
796          CompilerConfig compiler = loadedCompiler;
797          if(compiler && row)
798          {
799             compiler.targetPlatform = (Platform)row.tag;
800             modifiedDocument = true;
801             compilersTab.modifiedDocument = true;
802          }
803          return true;
804       }
805    };
806
807    int numJobs;
808    Label numJobsLabel { this, position = { 8, 40 }, labeledWindow = numJobsBox };
809    DataBox numJobsBox
810    {
811       this, text = "Number of parallel build jobs", hotKey = altJ, borderStyle = deep;
812       position = { 184, 36 }, size = { 80, 20 }, type = class(int), data = &numJobs;
813
814       bool OnKeyDown(Key key, unichar ch)
815       {
816          if((SmartKey)key == enter)
817          {  
818             DataBox::OnKeyDown(key, ch);
819             return true;
820          }
821          else
822             return DataBox::OnKeyDown(key, ch);
823       }
824       
825       bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
826       {
827          if(!active)
828          {
829             if(!SaveData())
830                Refresh();
831          }
832          return true;
833       }
834
835       bool NotifyChanged(bool closingDropDown)
836       {
837          CompilerConfig compiler = loadedCompiler;
838          if(compiler)
839          {
840             compiler.numJobs = numJobs;
841             modifiedDocument = true;
842             compilersTab.modifiedDocument = true;
843          }
844          return true;
845       }
846    };
847
848    Button ccacheEnabled
849    {
850       this, text = "Use ccache", hotKey = altC, position = { 8, 68 };
851       isCheckbox = true;
852
853       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
854       {
855          CompilerConfig compiler = loadedCompiler;
856          if(compiler)
857          {
858             compiler.ccacheEnabled = button.checked;
859             modifiedDocument = true;
860             compilersTab.modifiedDocument = true;
861          }
862          return true;
863       }
864    };
865
866    Button distccEnabled
867    {
868       this, text = "Use distcc", hotKey = altD, position = { 8, 96 };
869       isCheckbox = true;
870
871       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
872       {
873          CompilerConfig compiler = loadedCompiler;
874          if(compiler)
875          {
876             distccHosts.disabled = !button.checked;
877             compiler.distccEnabled = button.checked;
878             modifiedDocument = true;
879             compilersTab.modifiedDocument = true;
880          }
881          return true;
882       }
883    };
884
885    Label distccHostsLabel { this, position = { 8, 124 }, labeledWindow = distccHosts };
886    EditBox distccHosts
887    {
888       this, text = "distcc hosts", hotKey = altH;
889       position = { 88, 120 }, size = { 300 };
890
891       bool NotifyModified(EditBox editBox)
892       {
893          if(loadedCompiler)
894          {
895             CompilerConfig compiler = loadedCompiler;
896             compiler.distccHosts = editBox.contents;
897             modifiedDocument = true;
898             compilersTab.modifiedDocument = true;
899          }
900          return true;
901       }
902    }
903
904    CompilerOptionsTab()
905    {
906       Platform p;
907       DataRow row;
908       for(p = (Platform)1; p < Platform::enumSize; p++)
909       {
910          row = targetPlatform.AddRow();
911          row.tag = p;
912          row.string = p;
913       }
914    }
915
916    void Load()
917    {
918       if(loadedCompiler)
919       {
920          CompilerConfig compiler = loadedCompiler;
921          bool disabled = compiler.readOnly;
922          targetPlatform.currentRow = targetPlatform.FindRow(compiler.targetPlatform);
923          numJobs = compiler.numJobs;
924          numJobsBox.Refresh();
925          ccacheEnabled.checked = compiler.ccacheEnabled;
926          distccEnabled.checked = compiler.distccEnabled;
927          distccHosts.disabled = !compiler.distccEnabled;
928          distccHosts.contents = compiler.distccHosts;
929          
930          labelTargetPlatform.disabled = disabled;
931          targetPlatform.disabled = disabled;
932
933       }
934       modifiedDocument = false;
935    }
936 }
937
938 class CompilersSubTab : Tab
939 {
940    property CompilersTab compilersTab
941    {
942       get
943       {
944          CompilersTab tab = (CompilersTab)master;
945          while(tab && tab._class != class(CompilersTab))
946             tab = (CompilersTab)tab.master;
947          return tab;
948       }
949    };
950
951    property CompilerConfig loadedCompiler
952    {
953       get
954       {
955          CompilersTab tab = compilersTab;
956          return tab ? tab.activeCompiler : null;
957       }
958    };
959 }
960
961 class ProjectOptionsTab : GlobalSettingsSubTab
962 {
963    background = activeBorder;
964    text = "Project";
965
966    Label defaultTargetDirLabel { this, position = { 8, 34 }, labeledWindow = defaultTargetDir };
967    PathBox defaultTargetDir
968    {
969       this, size = { 160, 21 }, position = { 8, 52 }, anchor = { left = 8, top = 52, right = 8 };
970       text = "Default Target Directory", hotKey = altT;
971
972       bool NotifyModified(PathBox editBox)
973       {
974          modifiedDocument = true;
975          return true;
976       }
977    };
978
979    Label defaultIntermediateObjDirLabel { this, position = { 8, 78 }, labeledWindow = defaultIntermediateObjDir };
980    PathBox defaultIntermediateObjDir
981    {
982       this, size = { 160, 21 }, position = { 8, 96 }, anchor = { left = 8, top = 96, right = 8 };
983       text = "Default Intermediate Objects Directory", hotKey = altI;
984
985       bool NotifyModified(PathBox editBox)
986       {
987          modifiedDocument = true;
988          return true;
989       }
990    };
991 }
992
993 // COMPILER TOFIX: if class GlobalSettingsSubTab is after class WorkspaceOptionsTab the OnPostCreate 
994 //                 of WorkspaceOptionsTab will *not* be called!
995 class GlobalSettingsSubTab : Tab
996 {
997    property GlobalSettingsDialog dialog
998    {
999       get
1000       {
1001          GlobalSettingsDialog dialog = (GlobalSettingsDialog)master;
1002          while(dialog && dialog._class != class(GlobalSettingsDialog))
1003             dialog = (GlobalSettingsDialog)dialog.master;
1004          return dialog;
1005       }
1006    };
1007 }
1008
1009 class WorkspaceOptionsTab : GlobalSettingsSubTab
1010 {
1011    background = activeBorder;
1012    text = "Workspace";
1013
1014    Label defaultCompilerLabel { this, position = { 8, 14 }, labeledWindow = defaultCompilerDropBox };
1015    DropBox defaultCompilerDropBox
1016    {
1017       this, position = { 140, 8 }, size = { 220 };
1018       text = "Default Compiler", hotKey = altA;
1019
1020       bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
1021       {
1022          modifiedDocument = true;
1023          return true;
1024       }
1025    };
1026
1027    bool OnCreate()
1028    {
1029       GlobalSettingsDialog dialog = this.dialog;
1030       if(dialog && dialog.compilersTab.compilerConfigs && dialog.ideSettings)
1031       {
1032          DataRow row;
1033          for(compiler : dialog.ideSettings.compilerConfigs)
1034          {
1035             row = defaultCompilerDropBox.AddString(compiler.name);
1036             if(dialog.ideSettings.defaultCompiler && dialog.ideSettings.defaultCompiler[0] && 
1037                   !strcmp(compiler.name, dialog.ideSettings.defaultCompiler))
1038                defaultCompilerDropBox.currentRow = row;
1039          }
1040          if(!defaultCompilerDropBox.currentRow && defaultCompilerDropBox)
1041             defaultCompilerDropBox.currentRow = defaultCompilerDropBox.firstRow;
1042       }
1043       return true;
1044    }
1045
1046    void OnDestroy()
1047    {
1048       defaultCompilerDropBox.Clear();
1049       modifiedDocument = false;
1050    }
1051 }
1052
1053 //static define app = ((GuiApplication)__thisModule);