installer: Fixed Options CheckListBox NotifyChecked()
[sdk] / installer / src / installer.ec
index 8aac572..ca266bb 100644 (file)
@@ -1,7 +1,7 @@
 #ifdef NOMINGW
-static define buildString = $"Ecere SDK v0.44 (Without MinGW) -- built on March 7, 2012 ";
+static define buildString = $"Ecere SDK v0.44.08 (Without MinGW) -- built on August 8, 2013 ";
 #else
-static define buildString = $"Ecere SDK v0.44 -- built on March 7, 2012 ";
+static define buildString = $"Ecere SDK v0.44.08 -- built on August 8, 2013 ";
 #endif
 
 #define WIN32_LEAN_AND_MEAN
@@ -16,156 +16,8 @@ import "ecere"
 #endif
 import "IDESettings"
 import "createLink"
-import "licenseBox"
-
-class CheckListBox : ListBox
-{
-   fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true, 
-   noDragging = true;
-   rowHeight = 18;
-
-   void ToggleCheck(DataRow row)
-   {
-      Button checkBox = (Button)row.tag;
-      DataRow parent;
-      bool checked = !(checkBox.checked) || checkBox.buttonState == down;
-      if(!checkBox.disabled)
-      {
-         SetCheck(row, checked);
-         checkBox.buttonState = up;
-
-         for(parent = row; parent; parent = parent.parent)
-         {
-            for(row = parent.firstRow; row; row = row.next)
-            {
-               checkBox = (Button)row.tag;
-               if(checkBox.checked != checked)
-                  break;
-            }
-            checkBox = (Button)parent.tag;
-            if(row)
-            {
-               checkBox.checked = true;
-               NotifyChecked(master, this, parent);
-               checkBox.buttonState = down;
-               checked = true;
-            }
-            else
-            {
-               checkBox.checked = checked;
-               NotifyChecked(master, this, parent);
-               checkBox.buttonState = up;
-            }
-         }
-      }
-   }
-
-   void SetCheck(DataRow row, bool checked)
-   {
-      Button checkBox = (Button)row.tag;
-      DataRow subRow;
-      if(!checkBox.disabled && (checkBox.checked != checked || checkBox.buttonState == down))
-      {
-         checkBox.checked = checked;
-         for(subRow = row.firstRow; subRow; subRow = subRow.next)
-            SetCheck(subRow, checked);
-         NotifyChecked(master, this, row);
-      }
-   }
-   
-   DataRow AddRow(DataRow parentRow)
-   {      
-      DataRow row = parentRow ? parentRow.AddRow() : ListBox::AddRow();
-      int c;
-      DataRow parent;
-      int indent = 20;
-      for(parent = row.parent; parent; parent = parent.parent)
-         indent += 20;
-      row.tag = (int)Button
-      {
-         this, isCheckbox = true, inactive = true, checked = true,
-         position = { 2 + indent, 1+(row.index + hasHeader) * rowHeight }, size = { 12, 12 }; 
-         id = (int)row;
-
-         bool NotifyPushed(Button button, int x, int y, Modifiers mods)
-         {
-            currentRow = (DataRow)button.id;
-            ToggleCheck(currentRow);
-            return false;
-         }
-
-         bool NotifyReleased(Button button, int x, int y, Modifiers mods)
-         {
-            return false;
-         }
-
-         bool OnMouseOver(int x, int y, Modifiers mods)
-         {
-
-            return true;
-         }
-
-         bool OnMouseLeave(Modifiers mods)
-         {
-
-            return true;
-         }
-      };
-      return row;
-   }      
-
-   bool NotifyKeyDown(CheckListBox listBox, DataRow row, Key key, unichar ch)
-   {
-      if(key == space)
-      {
-         listBox.ToggleCheck(row);
-         return false;
-      }
-      return true;
-   }
-
-   bool OnKeyHit(Key key, unichar ch)
-   {
-      if(key == space)
-         return false;
-      return ListBox::OnKeyHit(key, ch);
-   }
-
-   bool NotifyDoubleClick(CheckListBox listBox, int x, int y, Modifiers mods)
-   {
-      listBox.OnLeftButtonDown(x, y, mods);
-      return false;
-   }
-
-   bool NotifyReclick(CheckListBox listBox, DataRow row, Modifiers mods)
-   {
-      listBox.ToggleCheck(row);
-      return true;
-   }
-
-   bool NotifyCollapse(ListBox listBox, DataRow row, bool collapsed)
-   {
-      DataRow r;
-      for(r = row.firstRow; r && r != row; )
-      {
-         Button checkBox = (Button)r.tag;
-         checkBox.visible = !collapsed;
-         if(r.firstRow && !r.collapsed) 
-            row = r.firstRow;
-         else 
-            for(; r != row; r = r.parent)
-               if(r.next) { r = r.next; break; }
-      }
-      for(r = row.GetNextRow(); r; r = r.GetNextRow())
-      {
-         Button checkBox = (Button)r.tag;
-         checkBox.position.y = 1 + (r.index + listBox.hasHeader) * listBox.rowHeight;
-      }
-      return true;
-   }
-
-   virtual void Window::NotifyChecked(CheckListBox listBox, DataRow row);
-};
+import "licensing"
+import "CheckListBox"
 
 struct CheckItem
 {
@@ -178,7 +30,7 @@ struct CheckItem
 
    void OnDisplay(Surface surface, int x, int y, int width, void * fieldData, Alignment alignment, DataDisplayFlags displayFlags)
    {
-      if(!displayFlags.active) displayFlags.current = false;
+      if(!displayFlags.active) { displayFlags.current = false; displayFlags.selected = false; }
       class::OnDisplay(surface, x + 22, y, width - 22, fieldData, alignment, displayFlags);
    }
 };
@@ -388,9 +240,6 @@ Component coreSDK[CoreSDKID] =
    { "Ecere IDE",       "ecere-sdk/ide",                 "bin",      null, true,  true },
    { "Runtime Library", "ecere-sdk/ecere.dll",           "bin",      null, true,  true },
    { "eC Compiler",     "ecere-sdk/compiler",            "bin",      null, true,  true },
-   { "Data Access",     "ecere-sdk/eda",                 "bin",      null, false, true },
-   { "Ecere Vanilla",   "ecere-sdk/libecereVanilla.a",   "lib",      null, false, true },
-   { "Ecere Extras",    "extras",                        "extras",   null, false, true },
 #ifndef NOMINGW
    { "GNU C Compiler",  "mingw/gcc/core",   "mingw", null, true, true },
    { "GNU Debugger",    "mingw/gdb",        "mingw", null, true, true },
@@ -404,15 +253,18 @@ Component coreSDK[CoreSDKID] =
 #ifndef NOMINGW
 Component additional[] =
 {
-   { "UPX",             "upx/bin",                 "mingw",    null, false, true },
-   { "GNU Regexp",      "mingw/gnurx",             "mingw",    null, false, true },
-   { "Win32 APIs",      "mingw/w32api",            "mingw",    null, false, true },
-   { "pthreads",        "mingw/pthreads",          "mingw",    null, false, true },
-   { "C++ Compiler",    "mingw/gcc/c++",           "mingw",    null, false, true },
-   { "GCC I18n",        "mingw/locale/gcc",        "mingw",    null, false, false },
-   { "GDB I18n",        "mingw/locale/gdb",        "mingw",    null, false, false },
-   { "Make I18n",       "mingw/locale/make",       "mingw",    null, false, false },
-   { "Binutils I18n",   "mingw/locale/binutils",   "mingw",    null, false, false },
+   { "Data Access",     "ecere-sdk/eda",                 "bin",      null, false, true },
+   { "Ecere Vanilla",   "ecere-sdk/libecereVanilla.a",   "lib",      null, false, true },
+   { "Ecere Extras",    "extras",                        "extras",   null, false, true },
+   { "UPX",             "upx/bin",                       "mingw/bin",null, false, true },
+   { "GNU Regexp",      "mingw/gnurx",                   "mingw",    null, false, true },
+   { "pthreads",        "mingw/pthreads",                "mingw",    null, false, true },
+   { "C++ Compiler",    "mingw/gcc/c++",                 "mingw",    null, false, true },
+   { "Win32 APIs",      "mingw/w32api",                  "mingw",    null, false, true },
+   { "GCC I18n",        "mingw/locale/gcc",              "mingw",    null, false, false },
+   { "GDB I18n",        "mingw/locale/gdb",              "mingw",    null, false, false },
+   { "Make I18n",       "mingw/locale/make",             "mingw",    null, false, false },
+   { "Binutils I18n",   "mingw/locale/binutils",         "mingw",    null, false, false },
    { null }
 };
 #endif
@@ -438,7 +290,7 @@ Component documentation[DocumentationID] =
    { "GDB Docs",        "mingw/doc/gdb",        "mingw",          null, false, false },
    { "Make Docs",       "mingw/doc/make",       "mingw",          null, false, false },
    { "Binutils Docs",   "mingw/doc/binutils",   "mingw",          null, false, false },
-   { "MinGW Docs",      "mingw/doc/mingw",      "mingw",          null, false, false },
+   { "MinGW Docs",      "mingw/doc/mingwrt",    "mingw",          null, false, false },
    { "gnurx Docs",      "mingw/doc/gnurx",      "mingw",          null, false, false },
    { "UPX Docs",        "upx/doc",              "mingw/doc/upx",  null, false, false },
 #endif
@@ -539,13 +391,14 @@ char installDir[MAX_LOCATION];
 
 class Installer : Window
 {
-   text = $"Ecere Software Development Kit Setup - v0.44 \"Ryōan-ji\"";
+   text = $"Ecere Software Development Kit Setup - v0.44.08 \"Ryōan-ji\"";
    background = activeBorder;
    borderStyle = fixed;
    hasMinimize = true;
    hasClose = true;
    tabCycle = true;
    clientSize = { 636, 456 };
+   // clientSize = { 796, 576 };
    icon = { ":icon.png" };
 
    Picture back { image = BitmapResource { ":ryoanji.png" }, parent = this, position = { 0, 0 } };
@@ -556,7 +409,7 @@ class Installer : Window
    };
    Button browse
    {
-      master = this, autoCreate = false, inactive = true, /*hotKey = F2,*/ text = "...";
+      master = this, autoCreate = false, inactive = true, text = "...";
       
       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
       {
@@ -578,23 +431,34 @@ class Installer : Window
    CheckListBox componentsBox
    {
       this, size = { 460, 112 }, position = { 160, 160 }, hasHeader = true;
+      fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true, 
+      noDragging = true;
+      rowHeight = 18;
+      selectionColor = { 145, 150, 140 };
+
       alwaysEdit = true;
       opacity = 0;
 
+      bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
+      {
+         if(key == f2 && browse.visible)
+            browse.NotifyClicked(this, browse, 0, 0, 0);
+         return true;
+      }
 
       bool NotifyChanged(ListBox listBox, DataRow row)
       {
          Component * component = ((CheckItem *)listBox.GetData(componentField))->data;
-         char path[MAX_LOCATION], relative[MAX_LOCATION] = "", ** newPath;
+         char path[MAX_LOCATION], relative[MAX_LOCATION] = "", * newPath;
          char fullPath[MAX_LOCATION];
 
          component->parent->GetFullPath(path);
          strcpy(fullPath, path);
 
-         newPath = (char **)row.GetData(locationField);
-         if(newPath && *newPath)
+         newPath = row.GetData(locationField);
+         if(newPath)
          {
-            PathCat(fullPath, *newPath);
+            PathCat(fullPath, newPath);
             MakePathRelative(fullPath, path, relative);
          }
          listBox.SetData(locationField, relative);
@@ -620,10 +484,17 @@ class Installer : Window
 
       bool NotifyEdited(ListBox listBox, DataRow row)
       {
+         Window e;
          browse.parent = listBox;
          browse.position = { componentField.width + locationField.width + 18, (listBox.currentIndex+1) * listBox.rowHeight - 2 };
          browse.size = { 30, listBox.rowHeight + 3 };
-
+         for(e = listBox.firstChild; e; e = e.next)
+         {
+            if(e._class == class(DataBox))
+               break;
+         }
+         if(e)
+            e.Activate();
          browse.Create();
          return true;
       }
@@ -632,8 +503,7 @@ class Installer : Window
       {
          Component * component = ((CheckItem *)row.GetData(componentField))->data;
          int c;
-         Button checkBox = (Button)row.tag;
-         component->selected = checkBox.checked;
+         component->selected = listBox.IsChecked(row);
 
          if(!component->parent) totalSize -= component->requiredSize;
          component->requiredSize = 0;
@@ -672,22 +542,24 @@ class Installer : Window
 
       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
       {
-         LicenseBox { master = this, sourceFile = ":ecere-sdk/doc/LICENSE" }.Modal();
+         // LicenseBox { master = this, sourceFile = ":ecere-sdk/doc/LICENSE" }.Modal();
+         LicensesForm { master = this }.Modal();
          return true;
       }
    };
    CheckListBox optionsBox
    {
       this, size = { 460, 94 }, position = { 160, 284 };
+      fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true, 
+      noDragging = true;
+      rowHeight = 18;
       opacity = 0;
 
       void NotifyChecked(CheckListBox listBox, DataRow row)
       {
          CheckItem * item = row.GetData(optionField);
          InstallOption * option = item->data;
-         int c;
-         Button checkBox = (Button)row.tag;
-         option->selected = checkBox.checked;
+         option->selected = listBox.IsChecked(row);
       }
    };
    Button install
@@ -705,14 +577,17 @@ class Installer : Window
    };
    Button button3 { parent = this, text = $"Cancel", hotKey = altX, size = Size { 75, 23 }, anchor = Anchor { left = 544, top = 416 }, NotifyClicked = ButtonCloseDialog };
    Label label1 { labeledWindow = destBox, tabCycle = true, isGroupBox = true, parent = this, inactive = false, size = Size { 458, 50 }, anchor = Anchor { left = 160, top = 96 } };
-   EditBox destBox
+   PathBox destBox
    {
-      parent = label1, master = this, text = $" Destination Folder", size = Size { 336, 19 }, anchor = Anchor { left = 12, top = 20 };
+      parent = label1, master = this, text = $" Destination Folder", size = Size { 336, 22 }, anchor = Anchor { left = 12, top = 20, right = 12 };
+      typeExpected = directory;
+      browseDialog = fileDialog;
+      opacity = 0;
 
-      bool NotifyModified(EditBox editBox)
+      bool NotifyModified(PathBox pathBox)
       {
          ComponentID c;
-         strcpy(installDir, destBox.contents);
+         strcpy(installDir, destBox.path);
          install.disabled = false;
          for(c = 0; components[c].name; c++)
          {
@@ -721,7 +596,7 @@ class Installer : Window
          return true;
       }
    };
-   Button button1
+   /*Button button1
    {
       label1, this, $"Browse", altB, size = { 83, 24 }, position = { 360, 16 };
 
@@ -738,7 +613,7 @@ class Installer : Window
          }
          return true;
       }
-   };
+   };*/
    EditBox label5
    {
       this, multiLine = true,
@@ -784,7 +659,17 @@ class Installer : Window
          "of the SDK to install, as well as where to install program icons."
    };
    Label label2 { parent = this, text = buildString, position = { 16, 392 }, font = { "Tahoma", 10, true }, disabled = true, opacity = 0, background = activeBorder };
-   Picture picture1 { image = BitmapResource { ":ecere.png", alphaBlend = true }, filter = true, parent = label3, text = "picture1", anchor = Anchor { left = 16, top = 4 } };
+   Picture picture1
+   {
+      image = BitmapResource { ":ecere.png", alphaBlend = true }, filter = true, parent = label3, text = "picture1", anchor = Anchor { left = 16, top = 4 };
+      cursor = ((GuiApplication)__thisModule).GetCursor(hand);
+
+      bool OnLeftButtonDown(int x, int y, Modifiers mods)
+      {
+         ShellOpen("http://www.ecere.com/");
+         return true;
+      }
+   };
    Label label4 { parent = label3, text = $"Choose Components, Locations and Install Options", font = FontResource { "Tahoma", 8.25f, bold = true }, size = Size { 326, 16 }, anchor = Anchor { horz = 91, vert = -12 } };
    DataField componentField { "CheckItem", width = 140, header = $"Component" };
    DataField locationField { "char *", width = 108, header = $"Destination Folder", editable = true };
@@ -836,11 +721,12 @@ class Installer : Window
 
    void AddComponent(Component component, Component parent, char * parentPath)
    {
-      DataRow row = component.row = componentsBox.AddRow((parent != null) ? parent.row : null);
-      Button checkBox = (Button) row.tag;
+      DataRow row = (parent != null) ? parent.row.AddRow() : componentsBox.AddRow();
       FileSize size = 0;
       FileSize64 avSize = 0;
       char path[MAX_LOCATION];
+
+      component.row = row;
       strcpy(path, parentPath);
       if(component.defInstallPath)
          PathCat(path, component.defInstallPath);
@@ -855,8 +741,10 @@ class Installer : Window
          row.SetData(locationField, component.installPath);
       }
 
-      if(component.mandatory) checkBox.disabled = true;
-      if(!component.selected) componentsBox.ToggleCheck(row);
+      if(component.mandatory)
+         componentsBox.SetDisabled(row, true);
+      componentsBox.SetCheck(row, component.selected);
+
       if(component.dataPath)
       {
          char path[MAX_LOCATION];
@@ -891,10 +779,9 @@ class Installer : Window
 
    void AddOption(InstallOption option, InstallOption parent)
    {
-      DataRow row = option.row = optionsBox.AddRow((parent != null) ? parent.row : null);
+      DataRow row = option.row = (parent != null) ? parent.row.AddRow() : optionsBox.AddRow();
       row.SetData(null, CheckItem { option.name, option } );
-      if(!option.selected)
-         optionsBox.ToggleCheck(row);
+      optionsBox.SetCheck(row, option.selected);
       if(option.subOptions)
       {
          int c;
@@ -910,9 +797,9 @@ class Installer : Window
    {
       int c;
       char programFilesDir[MAX_LOCATION];
-      char appData[MAX_LOCATION]; // = getenv("APPDATA");
-      char homeDrive[MAX_LOCATION]; //= getenv("HOMEDRIVE");
-      char winDir[MAX_LOCATION]; //= getenv("windir");
+      char appData[MAX_LOCATION];
+      char homeDrive[MAX_LOCATION];
+      char winDir[MAX_LOCATION];
 
       GetEnvironment("APPDATA", appData, sizeof(appData));
       GetEnvironment("HOMEDRIVE", homeDrive, sizeof(homeDrive));
@@ -956,7 +843,7 @@ class Installer : Window
          coreSDK[extras].defInstallPath = defExtrasPath;
       }
          
-      destBox.contents = installDir;
+      destBox.path = installDir;
 
       {
          ComponentID c;
@@ -1010,7 +897,9 @@ class InstallProgress : Window
    hasMinimize = true;
    hasClose = true;
    tabCycle = true;
-   size = Size { 640, 480 };
+   // size = Size { 640, 480 };
+   clientSize = { 636, 456 };
+   //clientSize = { 796, 576 };
    icon = { ":icon.png" };
 
    Picture back { image = BitmapResource { ":ryoanji-progress.png" }, parent = this, position = { 0, 0 } };
@@ -1039,7 +928,17 @@ class InstallProgress : Window
       contents = $"Please wait while the Ecere Software Development Kit is being installed."
    };
    Label label2 { parent = this, text = buildString, position = { 16, 392 }, font = { "Tahoma", 10, true }, disabled = true, opacity = 0, background = activeBorder };
-   Picture picture1 { image = BitmapResource { ":ecere.png", alphaBlend = true }, filter = true, parent = label3, anchor = Anchor { left = 16, top = 4 } };
+   Picture picture1
+   {
+      image = BitmapResource { ":ecere.png", alphaBlend = true }, filter = true, parent = label3, anchor = Anchor { left = 16, top = 4 };
+      cursor = ((GuiApplication)__thisModule).GetCursor(hand);
+
+      bool OnLeftButtonDown(int x, int y, Modifiers mods)
+      {
+         ShellOpen("http://www.ecere.com/");
+         return true;
+      }
+   };
    Label title { parent = label3, text = $"Installing the ECERE SDK", font = FontResource { "Tahoma", 8.25f, bold = true }, size = Size { 326, 16 }, anchor = Anchor { horz = 91, vert = -12 } };
 
    void OnDrawOverChildren(Surface surface)
@@ -1066,9 +965,9 @@ InstallProgress installProgress { autoCreate = false };
 
 void ModifyPath(char * newPath)
 {
-   char * paths[100];
+   char * paths[200];
    int p, count;
-   char oldPath[4096];
+   char oldPath[8192];
    CoreSDKID c;
 
    strcpy(oldPath, newPath);
@@ -1077,8 +976,10 @@ void ModifyPath(char * newPath)
    for(c = 0; coreSDK[c].name; c++)
    {
       char path[MAX_LOCATION];
+      if(c == extras || c == vanilla) continue;
+
       coreSDK[c].GetFullPath(path);
-      if(c != ide && c != runtime && c != eda && c != ec && c !=extras && c != vanilla)
+      if(c != ide && c != runtime && c != eda && c != ec)
       {
 #ifndef NOMINGW
          if(!pathOptions[PathOptions::AddMinGWPaths].selected)
@@ -1097,7 +998,7 @@ void ModifyPath(char * newPath)
          if(count) 
          {
             strcat(newPath, ";");
-            start = oldPath + strlen(paths[count-1])+1;
+            start = paths[count-1] + strlen(paths[count-1])+1;
          }
          else
             start = oldPath;
@@ -1113,12 +1014,13 @@ void ModifyPath(char * newPath)
    if(pathOptions[PathOptions::AddMinGWPaths].selected)
    {
       int c;
-      for(c = 0; additional[c].name; c++)
+      // Up to before Win32 APIs
+      for(c = 0; c < 4 /*additional[c].name*/; c++)
       {
          char path[MAX_LOCATION];
-         NamedItem item;
          additional[c].GetFullPath(path);
-         PathCat(path, "bin");
+         if(c != 0) // UPX already is in bin
+            PathCat(path, "bin");
          for(p = 0; p<count; p++)
             if(!fstrcmp(paths[p], path))
                break;
@@ -1129,7 +1031,7 @@ void ModifyPath(char * newPath)
             if(count) 
             {
                strcat(newPath, ";");
-               start = oldPath + strlen(paths[count-1])+1;
+               start = paths[count-1] + strlen(paths[count-1])+1;
             }
             else
                start = oldPath;
@@ -1152,16 +1054,16 @@ void AssociateExtension(char * extension, char * description, char *name, char *
    char keyName[1024];
 
    RegCreateKeyEx(HKEY_CLASSES_ROOT, extension, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
-   RegSetValueEx(key, null, 0, REG_SZ, name, strlen(name)+1);
+   RegSetValueEx(key, null, 0, REG_SZ, name, (uint)strlen(name)+1);
    RegCloseKey(key);
 
    RegCreateKeyEx(HKEY_CLASSES_ROOT, name, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
-   RegSetValueEx(key, null, 0, REG_SZ, description, strlen(description)+1);
+   RegSetValueEx(key, null, 0, REG_SZ, description, (uint)strlen(description)+1);
    RegCloseKey(key);
 
    sprintf(keyName, "%s\\shell", extension);
    RegCreateKeyEx(HKEY_CLASSES_ROOT, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
-   RegSetValueEx(key, null, 0, REG_SZ, action, strlen(action)+1);
+   RegSetValueEx(key, null, 0, REG_SZ, action, (uint)strlen(action)+1);
    RegCloseKey(key);
 
    sprintf(keyName, "%s\\shell\\%s", name, action);
@@ -1176,7 +1078,7 @@ void AssociateExtension(char * extension, char * description, char *name, char *
    {
       uint16 wKeyName[2048];
       UTF8toUTF16Buffer(keyName, wKeyName, sizeof(wKeyName) / sizeof(uint16));
-      RegSetValueExW(key, null, 0, REG_SZ, (byte *)wKeyName, (wcslen(wKeyName) + 1)*sizeof(uint16));
+      RegSetValueExW(key, null, 0, REG_SZ, (byte *)wKeyName, (uint)(wcslen(wKeyName) + 1)*sizeof(uint16));
    }
    RegCloseKey(key);
 }
@@ -1209,84 +1111,80 @@ class InstallThread : Thread
          char userProfile[MAX_LOCATION];
 
          // Configure IDE
-         GlobalSettings settings
+         IDESettings settings = null; // Don't instantiate yet so we can pick up old settings
+
+         IDESettingsContainer settingsContainer
          {
-            
+            driver = "JSON";
+            dataOwner = &settings;
+            dataClass = class(IDESettings);
          };
+         CompilerConfig compiler;
          installProgress.installing.text = $"Configuring ECERE IDE...";
          ((GuiApplication)__thisModule).Unlock();
          ((GuiApplication)__thisModule).SignalEvent();
 
-         settings.Load();
-         for(c = 0; coreSDK[c].name; c++)
+         settingsContainer.Load();
+         compiler = settings.GetCompilerConfig(defaultCompilerName);
+         if(compiler)
          {
-            char path[MAX_LOCATION];
-            NamedItem item;
-            coreSDK[c].GetFullPath(path);
-            if(c != ide && c != runtime && c != eda && c != ec)
-               PathCat(path, "bin");
-            if(c == ide)
+            for(c = 0; coreSDK[c].name; c++)
             {
-               coreSDK[c].GetFullPath(idePath);
-               PathCat(idePath, "IDE.exe");
-            }
+               char path[MAX_LOCATION];
+
+               if(c == extras) continue;
+               coreSDK[c].GetFullPath(path);
+               if(c != ide && c != runtime && c != eda && c != ec && c != vanilla)
+                  PathCat(path, "bin");
+               MakeSlashPath(path);
+               if(c == ide)
+               {
+                  coreSDK[c].GetFullPath(idePath);
+                  PathCat(idePath, "IDE.exe");
+               }
 
-            // TODO: Update This!
-            /*
-            for(item = settings.systemDirs[executables].first; item; item = item.next)
-               if(!fstrcmp(item.name, path))
-                  break;
-            if(!item)
-            {
-               settings.systemDirs[executables].Add(NamedItem { name = CopyString(path); });
-            }
+               if(c != vanilla)
+               {
+                  if(!compiler.executableDirs.Find(path))
+                     compiler.executableDirs.Add(CopyString(path));
+               }
 
-            if(c == runtime)
-            {
-               for(item = settings.systemDirs[libraries].first; item; item = item.next)
-                  if(!fstrcmp(item.name, path))
-                     break;
-               if(!item)
+               if(c == runtime || c == vanilla)
                {
-                  settings.systemDirs[libraries].Add(NamedItem { name = CopyString(path); });
+                  if(!compiler.libraryDirs.Find(path))
+                     compiler.libraryDirs.Add(CopyString(path));
                }
             }
-            */
-         }
-#ifndef NOMINGW
-         /*
-         for(c = 0; additional[c].name; c++)
-         {
-            char path[MAX_LOCATION];
-            NamedItem item;
-            additional[c].GetFullPath(path);
-            PathCat(path, "bin");
-            for(item = settings.systemDirs[executables].first; item; item = item.next)
-               if(!fstrcmp(item.name, path))
-                  break;
-            if(!item)
+   #ifndef NOMINGW
+            // Up to before Win32 APIs
+            for(c = 0; c < 4 /*additional[c].name*/; c++)
             {
-               settings.systemDirs[executables].Add(NamedItem { name = CopyString(path); });
+               char path[MAX_LOCATION];
+               additional[c].GetFullPath(path);
+               if(c != 0) // upx
+                  PathCat(path, "bin");
+               MakeSlashPath(path);
+               if(!compiler.executableDirs.Find(path))
+                  compiler.executableDirs.Add(CopyString(path));
+            }
+   #endif
+
+            {
+               char path[MAX_LOCATION] = "";
+               if(components[samples].selected)
+                  components[samples].GetFullPath(path);
+               else
+                  components[coreSDK].GetFullPath(path);
+
+               if(!settings.ideProjectFileDialogLocation)
+                  settings.ideProjectFileDialogLocation = path;
+               if(!settings.ideFileDialogLocation)
+                  settings.ideFileDialogLocation = path;
             }
-         }
-         */
-#endif
-         
-         {
-            char path[MAX_LOCATION] = "";
-            if(components[samples].selected)
-               components[samples].GetFullPath(path);
-            else
-               components[coreSDK].GetFullPath(path);
-            /* TODO: Update This!
-            if(!settings.ideProjectFileDialogLocation)
-               settings.ideProjectFileDialogLocation = path;
-            if(!settings.ideFileDialogLocation)
-               settings.ideFileDialogLocation = path;
-            */
          }
 
-         settings.Save();
+         settingsContainer.Save();
+         delete settingsContainer;
          delete settings;
 
          // Set up Uninstaller
@@ -1307,9 +1205,9 @@ class InstallThread : Thread
 
             RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ECERE SDK", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
 
-            RegSetValueEx(key, "DisplayName", 0, REG_SZ, displayName, strlen(displayName)+1);
-            RegSetValueEx(key, "UninstallString", 0, REG_SZ, uninstaller, strlen(uninstaller)+1);
-            RegSetValueEx(key, "DisplayIcon", 0, REG_SZ, idePath, strlen(idePath)+1);
+            RegSetValueEx(key, "DisplayName", 0, REG_SZ, displayName, (uint)strlen(displayName)+1);
+            RegSetValueEx(key, "UninstallString", 0, REG_SZ, uninstaller, (uint)strlen(uninstaller)+1);
+            RegSetValueEx(key, "DisplayIcon", 0, REG_SZ, idePath, (uint)strlen(idePath)+1);
             //RegSetValueEx(key, "NoModify", 0, REG_DWORD, (byte *)&nomodify, sizeof(nomodify));
             //RegSetValueEx(key, "NoRepair", 0, REG_DWORD, (byte *)&nomodify, sizeof(nomodify));
             RegCloseKey(key);
@@ -1324,8 +1222,8 @@ class InstallThread : Thread
          {
             HKEY key;
             uint status, size;
-            char path[2048] = "";
-            uint16 wPath[2048];
+            char path[4096] = "";
+            uint16 wPath[4096];
 
             ((GuiApplication)__thisModule).Lock();
             installProgress.installing.text = "Registering paths...";
@@ -1344,14 +1242,13 @@ class InstallThread : Thread
             }
             ModifyPath(path);
             UTF8toUTF16Buffer(path, wPath, sizeof(wPath) / sizeof(uint16));
-            RegSetValueExW(key, L"path", 0, REG_EXPAND_SZ, (byte *)wPath, (wcslen(wPath)+1) * 2);
+            RegSetValueExW(key, L"path", 0, REG_EXPAND_SZ, (byte *)wPath, (uint)(wcslen(wPath)+1) * 2);
             RegCloseKey(key);
 
             SendMessageTimeout (HWND_BROADCAST, WM_SETTINGCHANGE, 0, (int)"Environment", SMTO_NORMAL, 1000, NULL);
          }
 
          // Install Program Group Icons
-         // userProfile = getenv("USERPROFILE");
          GetEnvironment("USERPROFILE", userProfile, sizeof(userProfile));
 
          if(options[IconOptions::StartMenuIcon].selected)
@@ -1376,7 +1273,7 @@ class InstallThread : Thread
                UTF16toUTF8Buffer(wStartMenuPath, startMenuPath, sizeof(startMenuPath));
                RegCloseKey(key);
             }
-            if(!startMenuPath[0] && userProfile && userProfile[0])
+            if(!startMenuPath[0] && userProfile[0])
             {
                strcpy(startMenuPath, userProfile);
                PathCat(startMenuPath, "Start Menu\\Programs");
@@ -1406,6 +1303,13 @@ class InstallThread : Thread
                   documentation[ecereBook].GetFullPath(docPath);
                   PathCat(docPath, "Ecere Tao of Programming [work in progress].pdf");
 
+                  {
+                     char tao[MAX_LOCATION] ;
+                     documentation[ecereBook].GetFullPath(tao);
+                     PathCat(tao, "tao.pdf");
+                     RenameFile(tao, docPath);
+                  }
+
                   strcpy(destPath, startMenuPath);
                   PathCat(destPath, "ECERE SDK\\The Ecere Tao of Programming.lnk");
                   CreateLink(docPath, destPath, null);
@@ -1427,7 +1331,7 @@ class InstallThread : Thread
                UTF16toUTF8Buffer(wDesktopPath, desktopPath, sizeof(desktopPath));
                RegCloseKey(key);
             }
-            if(!desktopPath[0] && userProfile && userProfile[0])
+            if(!desktopPath[0] && userProfile[0])
             {
                strcpy(desktopPath, userProfile);
                PathCat(desktopPath, "Desktop");
@@ -1449,10 +1353,10 @@ class InstallThread : Thread
          // Install QuickLaunch Icon
          if(options[IconOptions::QuickLaunchIcon].selected)
          {
-            char appData[MAX_LOCATION]; // = getenv("APPDATA");
+            char appData[MAX_LOCATION];
             GetEnvironment("APPDATA", appData, sizeof(appData));
 
-            if(appData && appData[0])
+            if(appData[0])
             {
                char destPath[MAX_LOCATION];