X-Git-Url: https://ecere.com/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=installer%2Fsrc%2Finstaller.ec;h=5da1a82035be41427ea134ef1567565593ad105d;hb=a5e9fe141ccca04d9c83c20f71d20e0663b62802;hp=8aac572b2d8de7ee6c011d9db2662fe89966eda2;hpb=f2baf5cc4361ceb26b1af5ed45567733c39a8182;p=sdk diff --git a/installer/src/installer.ec b/installer/src/installer.ec index 8aac572..5da1a82 100644 --- a/installer/src/installer.ec +++ b/installer/src/installer.ec @@ -1,8 +1,7 @@ -#ifdef NOMINGW -static define buildString = $"Ecere SDK v0.44 (Without MinGW) -- built on March 7, 2012 "; -#else -static define buildString = $"Ecere SDK v0.44 -- built on March 7, 2012 "; -#endif +static define versionString = "Ecere SDK v0.44.10 (pr2)"; +static define dateString = $"August 7th, 2014"; +static define builtOnString = $"built on "; +static define withoutMinGW = $" (Without MinGW)"; #define WIN32_LEAN_AND_MEAN #define GetFreeSpace _GetFreeSpace @@ -16,169 +15,57 @@ import "ecere" #endif import "IDESettings" import "createLink" -import "licenseBox" +import "licensing" +import "CheckListBox" -class CheckListBox : ListBox +static void SetBuildString(Label label) { - 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; - } - } - } - } + static const String addMinGW = ""; + String s; - 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; - } +#ifdef NOMINGW + addMinGW = withoutMinGW; +#endif - bool NotifyReclick(CheckListBox listBox, DataRow row, Modifiers mods) - { - listBox.ToggleCheck(row); - return true; - } + s = PrintString(versionString, addMinGW, " -- ", builtOnString, dateString); + label.caption = s; + delete s; +} - bool NotifyCollapse(ListBox listBox, DataRow row, bool collapsed) +static bool IsAdministrator() +{ + BOOL b; + SID_IDENTIFIER_AUTHORITY NtAuthority = { SECURITY_NT_AUTHORITY }; + PSID AdministratorsGroup; + b = AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup); + if(b) { - 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; + if(!CheckTokenMembership(NULL, AdministratorsGroup, &b)) + b = FALSE; + FreeSid(AdministratorsGroup); } - - virtual void Window::NotifyChecked(CheckListBox listBox, DataRow row); -}; + return b == TRUE; +} struct CheckItem { - char * name; + const char * name; void * data; - char * OnGetString(char * tempString, void * fieldData, bool * needClass) + bool add32Bit; + const char * OnGetString(char * tempString, void * fieldData, bool * needClass) { + if(add32Bit) + { + strcpy(tempString, name); + strcat(tempString, " (32)"); + return tempString; + } return name; } 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); } }; @@ -187,7 +74,7 @@ struct CheckItem #define BUFFERSIZE 0x1000 bool abortInstall = false; -void ExtractFileFromArchive(ProgressBar progressBar, char * path, char * outputFile) +void ExtractFileFromArchive(ProgressBar progressBar, const char * path, const char * outputFile) { char fileName[MAX_LOCATION]; FileAttribs exists = FileExists(path); @@ -257,11 +144,11 @@ void ExtractFileFromArchive(ProgressBar progressBar, char * path, char * outputF FileGetSize(path, &dataSize); GetLastDirectory(outputFile, fileName); - + ((GuiApplication)__thisModule).SignalEvent(); //((GuiApplication)__thisModule).ProcessInput(); //((GuiApplication)__thisModule).UpdateDisplay(); - + for(c = 0; c c + BUFFERSIZE) ? BUFFERSIZE : (dataSize - c); @@ -291,14 +178,19 @@ void ExtractFileFromArchive(ProgressBar progressBar, char * path, char * outputF FileSetTime(outputFile, stats.created, 0, stats.modified); } +public enum BitArch { none, bits32, bits64 }; + struct Component { - char * name; - char * dataPath; - char * defInstallPath; + const char * name; + const char * dataPath; + const char * defInstallPath; Component * subComponents; bool mandatory; bool selected; + bool available; + BitArch arch; + Component * parent; uint requiredSize; @@ -306,35 +198,43 @@ struct Component char installPath[MAX_LOCATION]; DataRow row; - void GetFullPath(char * path) + void GetFullPath(char * path, bool is32bit) { if(this != null && parent) - parent->GetFullPath(path); + parent->GetFullPath(path, is32bit || (arch == bits32 && osIS64bit)); else - strcpy(path, installDir); + strcpy(path, (this && (is32bit || (arch == bits32 && osIS64bit))) ? installDir32 : installDir); if(this != null) PathCat(path, installPath); } - void Install(char * parentPath) + void Install(char * parentPath, char * parentPath32) { int c; - if(selected) + if(selected && (arch == none || arch == bits32 || osIS64bit)) { - char path[MAX_LOCATION]; - strcpy(path, parentPath); - PathCat(path, installPath); + char path64[MAX_LOCATION]; + char path32[MAX_LOCATION]; + strcpy(path64, parentPath); + PathCat(path64, installPath); + + strcpy(path32, parentPath32); + PathCat(path32, installPath); installProgress.installing.SetText($"Installing %s...", name); ((GuiApplication)__thisModule).UpdateDisplay(); if(dataPath) { + char * path = path64; char source[MAX_LOCATION]; strcpy(source, ":"); strcat(source, dataPath); + if(arch == bits32) + path = path32; + MakeDir(path); if(FileExists(source).isFile) @@ -344,136 +244,138 @@ struct Component PathCat(path, name); } if(requiredSize) - { - uint p = installProgress.progressBar.progress; - ExtractFileFromArchive(installProgress.progressBar, source, path); - } + ExtractFileFromArchive(installProgress.progressBar, source, path); } if(subComponents) { for(c = 0; subComponents[c].name; c++) - subComponents[c].Install(path); + subComponents[c].Install(path64, path32); } } } }; -Component samples[] = -{ - { "Ecere Chess", "samples/chess", "chess", null, false, true }, - { "Ecere Fractals", "samples/fractals", "fractals", null, false, true }, - { "3D", "samples/3D", "3D", null, false, true }, - { "Audio", "samples/audio", "audio", null, false, true }, - { "Database", "samples/db", "db", null, false, true }, - { "eC", "samples/eC", "eC", null, false, true }, - { "Games", "samples/games", "games", null, false, true }, - { "GUI & Graphics", "samples/guiAndGfx", "guiAndGfx", null, false, true }, - { "Miscellaneous", "samples/misc", "misc", null, false, true }, - { "Networking", "samples/net", "net", null, false, true }, - { "WIA Scanning", "samples/scanning", "scanning", null, false, true }, - { "Threading", "samples/threads", "threads", null, false, true } + +#ifndef NOMINGW +define minGWIncluded = true; +#else +define minGWIncluded = false; +#endif + +Array samples +{ [ + { "3D", "samples/3D", "3D", null, false, true, true, none }, + { "Android", "samples/android", "android", null, false, true, true, none }, + { $"Audio", "samples/audio", "audio", null, false, true, true, none }, + { $"Database", "samples/db", "db", null, false, true, true, none }, + { "eC", "samples/eC", "eC", null, false, true, true, none }, + { $"Games", "samples/games", "games", null, false, true, true, none }, + { $"GUI & Graphics", "samples/guiAndGfx", "guiAndGfx", null, false, true, true, none }, + { $"Miscellaneous", "samples/misc", "misc", null, false, true, true, none }, + { $"Networking", "samples/net", "net", null, false, true, true, none }, + { $"WIA Scanning", "samples/scanning", "scanning", null, false, true, true, none }, + { $"Threading", "samples/threads", "threads", null, false, true, true, none }, { null } -}; +] }; public enum CoreSDKID { - ide, runtime, ec, eda, vanilla, extras, -#ifndef NOMINGW + ide, ide32, runtime, runtime32, ec, ec32, gcc, gdb, mingw, binutils, make, -#endif none }; -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 }, - { "MinGW Runtime", "mingw/mingwrt", "mingw", null, true, true }, - { "Binary Utils", "mingw/binutils", "mingw", null, true, true }, - { "GNU Make", "mingw/make", "mingw", null, true, true }, -#endif +Array coreSDK +{ [ + { "Ecere IDE", "ecere-sdk/ide", "bin", null, true, true, true, bits64 }, + { "Ecere IDE", "ecere-sdk32/ide", "bin", null, true, true, true, bits32 }, + { $"Runtime Library", "ecere-sdk/ecere.dll", "bin", null, true, true, true, bits64 }, + { $"Runtime Library", "ecere-sdk32/ecere.dll", "bin", null, true, true, true, bits32 }, + { $"eC Compiler", "ecere-sdk/compiler", "bin", null, true, true, true, bits64 }, + { $"eC Compiler", "ecere-sdk32/compiler", "bin", null, true, true, true, bits32 }, + { $"GNU C Compiler", "tdm/gcc/core", "tdm", null, true, true, minGWIncluded, none }, + { $"GNU Debugger", "tdm/gdb", "tdm", null, true, true, minGWIncluded, none }, + { $"MinGW-w64 Runtime", "tdm/mingwrt", "tdm", null, true, true, minGWIncluded, none }, + { $"Binary Utils", "tdm/binutils", "tdm", null, true, true, minGWIncluded, none }, + { $"GNU Make", "tdm/make", "tdm", null, true, true, minGWIncluded, none }, { null } -}; +] }; -#ifndef NOMINGW -Component additional[] = +public enum AdditionalID { - { "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 }, - { null } + eda, eda32, audio, audio32, vanilla, vanilla32, extras, upx, gnurx, gnurx32, /*pthreads, */cpp, /*w32api, gcci18n, gdbi18n, makei18n, binutilsi18n, */none }; -#endif + +Array additional +{ [ + { $"Data Access", "ecere-sdk/eda", "bin", null, false, true, true, bits64 }, + { $"Data Access", "ecere-sdk32/eda", "bin", null, false, true, true, bits32 }, + { $"Ecere Audio", "ecere-sdk/EcereAudio.dll", "bin", null, false, true, true, bits64 }, + { $"Ecere Audio", "ecere-sdk32/EcereAudio.dll", "bin", null, false, true, true, bits32 }, + { $"Ecere Vanilla", "ecere-sdk/libecereVanilla.a", "lib", null, false, true, true, bits64 }, + { $"Ecere Vanilla", "ecere-sdk32/libecereVanilla.a", "lib", null, false, true, true, bits32 }, + { $"Ecere Extras", "extras", "extras", null, false, true, true, none }, + { "UPX", "upx/bin", "upx/bin", null, false, true, true, none }, + { $"GNU Regexp", "tdm/gnurx", "tdm", null, false, true, true, bits64 }, + { $"GNU Regexp", "tdm/gnurx32", "tdm", null, false, true, true, bits32 }, +// { "pthreads", "tdm/pthreads", "mingw", null, false, true, minGWIncluded, none }, + { $"C++ Compiler", "tdm/gcc/c++", "tdm", null, false, true, minGWIncluded, none }, +// { "Win32 APIs", "mingw/w32api", "mingw", null, false, true, minGWIncluded, none }, +/* { "GCC I18n", "mingw/locale/gcc", "tdm", null, false, false, minGWIncluded, none }, + { "GDB I18n", "mingw/locale/gdb", "tdm", null, false, false, minGWIncluded, none }, + { "Make I18n", "mingw/locale/make", "tdm", null, false, false, minGWIncluded, none }, + { "Binutils I18n", "mingw/locale/binutils", "tdm", null, false, false, minGWIncluded, none }, +*/ + { null } +] }; public enum DocumentationID { - ecereBook, apiRef, tutorials, coursework, -#ifndef NOMINGW + ecereBook, apiRef, coursework, gccDoc, gppDocs, gdbDocs, makeDocs, binDocs, mingwDocs, gnurxDocs, upxDocs, -#endif none }; -Component documentation[DocumentationID] = -{ - { "Ecere Book", "ecere-sdk/book", "doc", null, false, true }, - { "API Reference", "ecere-sdk/doc", "doc", null, false, true }, - { "Ecere Tutorials", "ecere-sdk/tutorials", "doc", null, false, true }, - { "Ecere Coursework", "ecere-sdk/coursework", "doc", null, false, true }, -#ifndef NOMINGW - { "GCC Docs", "mingw/doc/gcc", "mingw", null, false, false }, - { "G++ Docs", "mingw/doc/g++", "mingw", null, false, false }, - { "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 }, - { "gnurx Docs", "mingw/doc/gnurx", "mingw", null, false, false }, - { "UPX Docs", "upx/doc", "mingw/doc/upx", null, false, false }, -#endif +Array documentation +{ [ + { $"Ecere Book", "ecere-sdk/book", "doc", null, false, true, true, none }, + { $"API Reference", "ecere-sdk/doc", "doc", null, false, true, true, none }, + { $"Ecere Coursework", "ecere-sdk/coursework", "doc", null, false, true, true, none }, + { $"GCC Docs", "tdm/doc/gcc", "tdm", null, false, false, minGWIncluded, none }, + { $"G++ Docs", "tdm/doc/g++", "tdm", null, false, false, minGWIncluded, none }, + { $"GDB Docs", "tdm/doc/gdb", "tdm", null, false, false, minGWIncluded, none }, + { $"Make Docs", "tdm/doc/make", "tdm", null, false, false, minGWIncluded, none }, + { $"Binutils Docs", "tdm/doc/binutils", "tdm", null, false, false, minGWIncluded, none }, + { $"gnurx Docs", "tdm/doc/gnurx", "tdm", null, false, false, minGWIncluded, none }, + { $"UPX Docs", "upx/doc", "upx/doc", null, false, false, minGWIncluded, none }, { null } -}; +] }; public enum ComponentID { coreSDK, -#ifndef NOMINGW additional, -#endif documentation, samples, none }; -Component components[ComponentID] = -{ - { "Core SDK Files", null, null, coreSDK, true, true }, -#ifndef NOMINGW - { "Additional Support", null, null, additional, false, true }, -#endif - { "Documentation", null /*"doc"*/, null /*"doc"*/, documentation, false, true }, - { "Samples", null, "samples", samples, false, true }, +Array components +{ [ + { $"Core SDK Files", null, null, coreSDK.array, true, true, true, none }, + { $"Additional Support", null, null, additional.array, false, true, true, none }, + { $"Documentation", null /*"doc"*/, null /*"doc"*/, documentation.array, false, true, true, none }, + { $"Samples", null, "samples", samples.array, false, true, true, none }, { null } -}; +] }; FileSize totalSize; FileSize totalInstalled; struct InstallOption { - char * name; + const char * name; InstallOption * subOptions; bool selected; + bool available; DataRow row; }; @@ -488,82 +390,86 @@ enum AssociateOptions AssociateIMG }; -InstallOption associateOptions[] = -{ - { "Associate with Ecere Project Files (*.epj)", null, true }, - { "Associate with eC Files (*.ec, *.eh)", null, true }, - { "Associate with C files (*.c, *.h)", null, false }, - { "Associate with C++ Files (*.cpp, *.hpp, *.cc, *.hh, *.cxx, *.hxx)", null, false }, - { "Associate with text files (*.txt)", null, false }, - { "Associate with 3D Studio Model Files (*.3ds)", null, true }, - { "Associate with Image Files (*.png, *.jpg, *.pcx, *.bmp, *.gif)", null, false }, +Array associateOptions +{ [ + { $"Associate with Ecere Project Files (*.epj)", null, true }, + { $"Associate with eC Files (*.ec, *.eh)", null, true }, + { $"Associate with C files (*.c, *.h)", null, false }, + { $"Associate with C++ Files (*.cpp, *.hpp, *.cc, *.hh, *.cxx, *.hxx)", null, false }, + { $"Associate with text files (*.txt)", null, false }, + { $"Associate with 3D Studio Model Files (*.3ds)", null, true }, + { $"Associate with Image Files (*.png, *.jpg, *.pcx, *.bmp, *.gif)", null, false }, { null } -}; +] }; enum PathOptions { - AddECEREPaths -#ifndef NOMINGW - , AddMinGWPaths -#endif + AddECEREPaths, AddMinGWPaths }; -InstallOption pathOptions[] = -{ - { "Add Ecere binaries location to the system path", null, true }, - { "Add MinGW to the system path", null, true } +Array pathOptions +{ [ + { $"Add Ecere binaries location to the user environment path", null, true, true }, + { $"Add MinGW to the user environment path", null, true, minGWIncluded }, { null } -}; +] }; enum IconOptions { - StartMenuIcon, - DesktopIcon, - QuickLaunchIcon + StartMenuIcon = 1, + DesktopIcon = 2, + QuickLaunchIcon = 3 }; -InstallOption options[] = -{ - { "Start Menu Group", null, true }, - { "Desktop Icon", null, true }, - { "Quicklaunch Icon", null, true }, - { "Associate the ECERE IDE with Supported File Types", associateOptions, true }, -#ifndef NOMINGW - { "Add binaries location to the system paths", pathOptions, true }, -#endif +Array options +{ [ + { $"Install for All Users", null, true, true }, + { $"Start Menu Group", null, true, true }, + { $"Desktop Icon", null, true, true }, + { $"Quicklaunch Icon", null, true, true }, + { $"Associate the Ecere IDE with Supported File Types", associateOptions.array, true, true }, + { $"Add binaries location to the user environment paths", pathOptions.array, true, minGWIncluded }, { null } -}; +] }; char sourceDir[MAX_LOCATION] = ":"; char installDir[MAX_LOCATION]; +char installDir32[MAX_LOCATION]; +bool osIS64bit; class Installer : Window { - text = $"Ecere Software Development Kit Setup - v0.44 \"Ryōan-ji\""; - background = activeBorder; + background = formColor; borderStyle = fixed; hasMinimize = true; hasClose = true; tabCycle = true; - clientSize = { 636, 456 }; + clientSize = { 636, 476 }; icon = { ":icon.png" }; + caption = $"Ecere Software Development Kit Setup - v0.44.10 \"Ryōan-ji\" 64 Bit Edition"; + + // clientSize = { 796, 576 }; + bool loaded; Picture back { image = BitmapResource { ":ryoanji.png" }, parent = this, position = { 0, 0 } }; FileDialog fileDialog { master = this, type = selectDir, - text = $"Select a new location" + caption = $"Select a new location" }; Button browse { - master = this, autoCreate = false, inactive = true, /*hotKey = F2,*/ text = "..."; - + master = this, autoCreate = false, inactive = true, caption = "..."; + bool NotifyClicked(Button button, int x, int y, Modifiers mods) { DataRow row = componentsBox.currentRow; Component * component = ((CheckItem *)row.GetData(componentField))->data; - component->GetFullPath(fileDialog.filePath); - StripLastDirectory(fileDialog.filePath, fileDialog.currentDirectory); + char filePath[MAX_LOCATION]; + component->GetFullPath(filePath, false); + fileDialog.filePath = filePath; + StripLastDirectory(filePath, filePath); + fileDialog.currentDirectory = filePath; if(fileDialog.Modal() == ok) { @@ -578,24 +484,40 @@ class Installer : Window CheckListBox componentsBox { this, size = { 460, 112 }, position = { 160, 160 }, hasHeader = true; + fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true, + hasHorzScroll = true; + resizable = 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); + component->parent->GetFullPath(path, false); strcpy(fullPath, path); - newPath = (char **)row.GetData(locationField); - if(newPath && *newPath) + newPath = row.GetData(locationField); + if(newPath) { - PathCat(fullPath, *newPath); - MakePathRelative(fullPath, path, relative); + PathCat(fullPath, newPath); + if(IsPathInsideOf(fullPath, path)) + MakePathRelative(fullPath, path, relative); + else + strcpy(relative, fullPath); } listBox.SetData(locationField, relative); strcpy(component->installPath, relative); @@ -620,10 +542,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,14 +561,13 @@ 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; if(component->selected) { - component->requiredSize += component->size; + component->requiredSize += component->size; if(component->subComponents) for(c = 0; component->subComponents[c].name; c++) component->requiredSize += component->subComponents[c].requiredSize; @@ -651,48 +579,105 @@ class Installer : Window } else row.UnsetData(reqField); - if(!component->parent) + if(!component->parent) { totalSize += component->requiredSize; { char sizeString[100]; PrintSize(sizeString, totalSize, 2); - totalSpaceValue.text = sizeString; + totalSpaceValue.caption = sizeString; } } } }; - Label agreementLbl { parent = this, text = $"By installing the Ecere SDK, you agree to the .", font = { "Tahoma", 8.25f }, anchor = Anchor { left = 24, top = 424 } }; + Label agreementLbl { parent = this, caption = $"By installing the Ecere SDK, you agree to the", font = { "Tahoma", 8.25f }, anchor = Anchor { right = 399, top = 448 } }; Button licenseButton { this, inactive = true, offset = false, bevel = false, foreground = blue, font = { "Tahoma", 8.25f, underline = true, bold = true }, - // text = $"terms and conditions", anchor = Anchor { left = 241, top = 421 }; - text = $"terms and conditions", anchor = Anchor { left = 237, top = 421 }; + // caption = $"terms and conditions", anchor = Anchor { left = 241, top = 421 }; + caption = $"terms and conditions", anchor = Anchor { left = 235, top = 445 }; cursor = ((GuiApplication)__thisModule).GetCursor(hand); 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; } }; + Label dotLbl { parent = this, caption = ".", font = { "Tahoma", 8.25f }, anchor = Anchor { left = 372, top = 448 } }; CheckListBox optionsBox { - this, size = { 460, 94 }, position = { 160, 284 }; + this, size = { 460, 114 }, 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); + // Update default samples/extras path whether we're installing for All Users or not + if(option == &options[0]) + { + char appData[MAX_LOCATION]; + + options[5].name = options[0].selected ? $"Add binaries location to the system environment paths" : $"Add binaries location to the user environment paths"; + if(options[5].row) + ((CheckItem *)options[5].row.GetData(optionField))->name = options[5].name; + + pathOptions[PathOptions::AddECEREPaths].name = options[0].selected ? $"Add Ecere binaries location to the system environment path" : $"Add Ecere binaries location to the user environment path"; + if(pathOptions[PathOptions::AddECEREPaths].row) + ((CheckItem *)pathOptions[PathOptions::AddECEREPaths].row.GetData(optionField))->name = pathOptions[PathOptions::AddECEREPaths].name; + + pathOptions[PathOptions::AddMinGWPaths].name = options[0].selected ? $"Add TDM-GCC/MinGW-w64 to the system environment path" : $"Add TDM-GCC/MinGW-w64 to the user environment path"; + if(pathOptions[PathOptions::AddMinGWPaths].row) + ((CheckItem *)pathOptions[PathOptions::AddMinGWPaths].row.GetData(optionField))->name = pathOptions[PathOptions::AddMinGWPaths].name; + + GetEnvironment(options[0].selected ? "ALLUSERSPROFILE" : "APPDATA", appData, sizeof(appData)); + if(appData[0]) + { + char defPath[MAX_LOCATION]; + + strcpy(defPath, installDir); + PathCat(defPath, components[ComponentID::samples].defInstallPath); + ChangeCh(defPath, '/', DIR_SEP); + if(!strcmp(defPath, components[ComponentID::samples].installPath)) + { + static char defSamplesPath[MAX_LOCATION]; + strcpy(defSamplesPath, appData); + PathCat(defSamplesPath, "Ecere SDK\\Samples"); + components[ComponentID::samples].defInstallPath = defSamplesPath; + + strcpy(components[ComponentID::samples].installPath, components[ComponentID::samples].defInstallPath); + ChangeCh(components[ComponentID::samples].installPath, '/', DIR_SEP); + components[ComponentID::samples].row.SetData(locationField, components[ComponentID::samples].installPath); + } + + strcpy(defPath, installDir); + PathCat(defPath, additional[AdditionalID::extras].defInstallPath); + ChangeCh(defPath, '/', DIR_SEP); + if(!strcmp(additional[AdditionalID::extras].installPath, additional[AdditionalID::extras].installPath)) + { + static char defExtrasPath[MAX_LOCATION]; + strcpy(defExtrasPath, appData); + PathCat(defExtrasPath, "Ecere SDK\\extras"); + additional[AdditionalID::extras].defInstallPath = defExtrasPath; + + strcpy(additional[AdditionalID::extras].installPath, additional[AdditionalID::extras].defInstallPath); + ChangeCh(additional[AdditionalID::extras].installPath, '/', DIR_SEP); + additional[AdditionalID::extras].row.SetData(locationField, additional[AdditionalID::extras].installPath); + } + } + listBox.Update(null); + } } }; Button install { - parent = this, text = $"Install", isDefault = true, size = { 75, 23 }, position = { 432, 416 }; + parent = this, caption = $"Install", isDefault = true, size = { 75, 23 }, position = { 432, 440 }; bool NotifyClicked(Button button, int x, int y, Modifiers mods) { @@ -703,16 +688,51 @@ class Installer : Window return true; } }; - Button button3 { parent = this, text = $"Cancel", hotKey = altX, size = Size { 75, 23 }, anchor = Anchor { left = 544, top = 416 }, NotifyClicked = ButtonCloseDialog }; + Button button3 { parent = this, caption = $"Cancel", hotKey = altX, size = Size { 75, 23 }, anchor = Anchor { left = 544, top = 440 }, NotifyClicked = ButtonCloseDialog }; + DropBox languageBox + { + this, position = { 14, 374 }, size = { 142, 0 }, caption = "Language:"; + + bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods) + { + LanguageOption * option = row.GetData(null); + // If the language is already set, we need to override it + { + IDESettings settings = null; + IDESettingsContainer settingsContainer + { + driver = "JSON"; + dataOwner = &settings; + dataClass = class(IDESettings); + allUsers = options[0].selected; + }; + settingsContainer.Load(); + if(settings.language) + { + settings.language = option->code; + settingsContainer.Save(); + } + delete settingsContainer; + delete settings; + } + ((GuiApplication)__thisModule.application).desktop.Destroy(0); + LanguageRestart(option->code, __thisModule.application, null, null, null, null, false); + return true; + } + }; + Label lblLanguageBox { this, position = { 14, 354 }, labeledWindow = languageBox }; 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, caption = $" 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 +741,7 @@ class Installer : Window return true; } }; - Button button1 + /*Button button1 { label1, this, $"Browse", altB, size = { 83, 24 }, position = { 360, 16 }; @@ -738,7 +758,7 @@ class Installer : Window } return true; } - }; + };*/ EditBox label5 { this, multiLine = true, @@ -762,7 +782,7 @@ class Installer : Window }; EditBox label7 { - this, opacity = 0, borderStyle = none, inactive = true, size = { 136, 53 }, position = { 14, 280 }, noSelect = true, + this, opacity = 0, borderStyle = none, inactive = true, size = { 136, 83 }, position = { 14, 280 }, noSelect = true, multiLine = true, contents = $"Select icons to install, file\n" "associations, and system\n" @@ -770,29 +790,39 @@ class Installer : Window }; Label totalSpaceLabel { - this, position = { 18, 352 }, text = $"Space Required: " + this, anchor = { right = 72, top = 404 }, caption = $"Space Required: " }; Label totalSpaceValue { - this, position = { 100, 352 }, text = "0 mb" + this, anchor = { right = 14, top = 404 }, caption = "0 mb" }; EditBox editBox1 { - inactive = true, noSelect = true, - multiLine = true, parent = label3, text = "editBox1", opacity = 0, borderStyle = none, size = Size { 350, 35 }, anchor = Anchor { horz = 111, vert = 13 }, - contents = $"Choose in which folder to install the ECERE SDK, which features\n" + label3, caption = "editBox1", opacity = 0, borderStyle = none, inactive = true, size = { 350, 35 }, position = { 256, 40 }, multiLine = true, noSelect = true, contents = $"Choose in which folder to install the Ecere SDK, which features\n" "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 } }; - 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" }; + Label label2 { parent = this, position = { 16, 422 }, font = { "Tahoma", 10, true }, disabled = true, opacity = 0, background = activeBorder }; + Picture picture1 + { + image = BitmapResource { ":ecere.png", alphaBlend = true }, filter = true, parent = label3, caption = "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 { label3, font = { "Tahoma", 8.25f, bold = true }, /*size = { 326, 16 }, */position = { 248, 24 }, caption = $"Choose Components, Locations and Install Options" }; + DataField componentField { "CheckItem", width = 160, header = $"Component" }; DataField locationField { "char *", width = 108, header = $"Destination Folder", editable = true }; - DataField reqField { "FileSize", width = 80, header = $"Req. Space", alignment = right }; - DataField avField { "FileSize64", width = 80, header = $"Avail. Space", alignment = right }; + DataField reqField { "FileSize", width = 70, header = $"Req. Space", alignment = right }; + DataField avField { "FileSize64", width = 70, header = $"Avail. Space", alignment = right }; DataField optionField { "CheckItem" }; - void SetAvailableSpace(Component component, char * parentPath) + DataField languageField { class(LanguageOption) }; + + void SetAvailableSpace(Component component, const char * parentPath) { char path[MAX_LOCATION]; int c; @@ -814,7 +844,7 @@ class Installer : Window if(!size) install.disabled = true; } - FileSize ComputeSize(char * path) + FileSize ComputeSize(const char * path) { FileSize size = 0; FileAttribs attribs = FileExists(path); @@ -834,19 +864,20 @@ class Installer : Window return size; } - void AddComponent(Component component, Component parent, char * parentPath) + void AddComponent(Component component, Component parent, const 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); component.parent = parent; - - row.SetData(null, CheckItem { component.name, component } ); + + row.SetData(null, CheckItem { component.name, component, (component.arch == bits32 && osIS64bit) } ); if(component.defInstallPath) { @@ -855,8 +886,18 @@ class Installer : Window row.SetData(locationField, component.installPath); } - if(component.mandatory) checkBox.disabled = true; - if(!component.selected) componentsBox.ToggleCheck(row); + if(component.mandatory) + { + if(component.arch != bits32 || !osIS64bit) // || component == &coreSDK[gdb32]) + componentsBox.SetDisabled(row, true); + /*else + component.selected = false;*/ + } + else if(component.arch == bits32 && osIS64bit) + ; //component.selected = false; + + componentsBox.SetCheck(row, component.selected); + if(component.dataPath) { char path[MAX_LOCATION]; @@ -869,8 +910,14 @@ class Installer : Window int c; for(c = 0; component.subComponents[c].name; c++) { - AddComponent(component.subComponents[c], component, path); - size += component.subComponents[c].requiredSize; + Component * sub = &component.subComponents[c]; + if(sub->available && (osIS64bit || sub->arch == bits32 || sub->arch == none)) + { + AddComponent(sub, component, path); + size += sub->requiredSize; + } + else + sub->selected = false; } } @@ -880,7 +927,7 @@ class Installer : Window while(!FileExists(path) && path[0]) StripLastDirectory(path, path); - + if(path[0]) GetFreeSpace(path, &avSize); else @@ -891,10 +938,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,14 +956,53 @@ 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]; + char * x86 = null; + + bool isAdministrator = IsAdministrator(); + + SetBuildString(label2); + + if(!isAdministrator) + { + options[0].available = false; + options[0].selected = false; + } + + // If the SDK is already installed, use currently selected language + { + IDESettings settings = null; + IDESettingsContainer settingsContainer + { + driver = "JSON"; + dataOwner = &settings; + dataClass = class(IDESettings); + allUsers = options[0].selected; + }; + + settingsContainer.Load(); + + if(settings.language) + { + const String language = GetLanguageString(); + if(settings.language.OnCompare(language)) + { + // Relaunch the installer with previously selected language + LanguageRestart(settings.language, __thisModule.application, null, null, null, null, false); + return false; + } + } + delete settingsContainer; + delete settings; + } - GetEnvironment("APPDATA", appData, sizeof(appData)); GetEnvironment("HOMEDRIVE", homeDrive, sizeof(homeDrive)); GetEnvironment("windir", winDir, sizeof(winDir)); - + + GetEnvironment(options[0].selected ? "ALLUSERSPROFILE" : "APPDATA", appData, sizeof(appData)); + componentsBox.AddField(componentField); componentsBox.AddField(locationField); componentsBox.AddField(reqField); @@ -925,38 +1010,68 @@ class Installer : Window optionsBox.AddField(optionField); + languageBox.AddField(languageField); + + programFilesDir[0] = 0; if(GetEnvironment("ProgramFiles", programFilesDir, MAX_LOCATION)) { - strcpy(installDir, programFilesDir); - PathCat(installDir, "ECERE SDK"); + x86 = strstr(programFilesDir, " (x86)"); + if(x86) + osIS64bit = true; } - else if(homeDrive && homeDrive[0]) + + if(isAdministrator && programFilesDir[0]) + { + if(x86) + { + strcpy(installDir32, programFilesDir); + PathCat(installDir32, "Ecere SDK"); + *x86 = 0; + strcpy(installDir, programFilesDir); + PathCat(installDir, "Ecere SDK"); + } + else + { + strcpy(installDir, programFilesDir); + PathCat(installDir, "Ecere SDK"); + strcpy(installDir32, installDir); + } + } + else if(homeDrive[0]) { strcpy(installDir, homeDrive); - PathCat(installDir, "ECERE SDK"); + PathCat(installDir, "Ecere SDK"); + strcpy(installDir32, installDir); + strcat(installDir32, " (32)"); } - else if(winDir && winDir[0]) + else if(winDir[0]) { strcpy(installDir, winDir); - PathCat(installDir, "..\\ECERE SDK"); + PathCat(installDir, "..\\Ecere SDK"); + strcpy(installDir32, installDir); + strcat(installDir32, " (32)"); } else - strcpy(installDir, "C:\\ECERE SDK"); - - if(appData && appData[0]) + { + strcpy(installDir, "C:\\Ecere SDK"); + strcpy(installDir32, installDir); + strcat(installDir32, " (32)"); + } + + if(appData[0]) { static char defSamplesPath[MAX_LOCATION]; static char defExtrasPath[MAX_LOCATION]; strcpy(defSamplesPath, appData); - PathCat(defSamplesPath, "ECERE SDK\\Samples"); - components[samples].defInstallPath = defSamplesPath; + PathCat(defSamplesPath, "Ecere SDK\\Samples"); + components[ComponentID::samples].defInstallPath = defSamplesPath; strcpy(defExtrasPath, appData); - PathCat(defExtrasPath, "ECERE SDK\\extras"); - coreSDK[extras].defInstallPath = defExtrasPath; + PathCat(defExtrasPath, "Ecere SDK\\extras"); + additional[AdditionalID::extras].defInstallPath = defExtrasPath; } - - destBox.contents = installDir; + + destBox.path = installDir; { ComponentID c; @@ -974,14 +1089,90 @@ class Installer : Window { char sizeString[100]; PrintSize(sizeString, totalSize, 2); - totalSpaceValue.text = sizeString; + totalSpaceValue.caption = sizeString; } for(c = 0; options[c].name; c++) - AddOption(options[c], null); + { + if(options[c].available) + AddOption(options[c], null); + } + } + + void OnDestroy() + { + for(l : languages) + delete l.res; + } + + bool OnPostCreate() + { + dotLbl.position.x = licenseButton.position.x + licenseButton.size.w - 4; + return true; } bool OnCreate() { + // Constructor happens before Languages is instantiated... + for(l : languages) + { + l.res = { l.bitmap, window = this }; + incref l.res; + } + + if(!loaded) + { + const String language = GetLanguageString(); + bool found = false; + DataRow row; + + // Try to find country-specific language first + for(l : languages) + { + LanguageOption option = l; + row = languageBox.AddRow(); + row.SetData(null, option); // TOFIX: l used directly here + + if(!found && (!strcmpi(l.code, language) || (!row.GetPrevRow() && !strcmpi("en", language)))) + { + languageBox.currentRow = row; + found = true; + } + } + + // Try generalizing locale + if(!found) + { + char * under; + char genericLocale[256]; + strncpy(genericLocale, language, sizeof(genericLocale)); + genericLocale[sizeof(genericLocale)-1] = 0; + + under = strchr(genericLocale, '_'); + if(under) + *under = 0; + if(!strcmpi(genericLocale, "zh")) + strcpy(genericLocale, "zh_CN"); + if(strcmp(genericLocale, language)) + { + row = languageBox.firstRow; + for(l : languages) + { + if(!strcmpi(l.code, genericLocale) || (!row.GetPrevRow() && !strcmpi("en", genericLocale))) + { + languageBox.currentRow = row; + found = true; + break; + } + row = row.GetNextRow(); + } + } + } + + if(!found) + languageBox.currentRow = languageBox.firstRow; + loaded = true; + } + destBox.Activate(); return true; } @@ -990,12 +1181,11 @@ class Installer : Window { int tw = label2.size.w; surface.SetForeground(Color { 128, 128, 128 }); - surface.HLine(label2.position.x + tw + 6, 620, 400); + surface.HLine(label2.position.x + tw + 6, 620, 430); surface.SetForeground(white); - surface.HLine(label2.position.x + tw + 6, 621, 401); + surface.HLine(label2.position.x + tw + 6, 621, 431); surface.PutPixel(621, 400); } - Label label3 { parent = this, opacity = 0, borderStyle = deep, size = Size { 644, 93 }, anchor = Anchor { left = -8, top = -8 }; @@ -1004,27 +1194,34 @@ class Installer : Window class InstallProgress : Window { - text = $"Ecere Software Development Kit Setup - v0.44 \"Ryōan-ji\""; + caption = $"Ecere Software Development Kit Setup - v0.44.10 \"Ryōan-ji\" 64 Bit Edition"; background = activeBorder; borderStyle = fixed; hasMinimize = true; hasClose = true; tabCycle = true; - size = Size { 640, 480 }; + // size = Size { 640, 480 }; + clientSize = { 636, 476 }; + //clientSize = { 796, 576 }; icon = { ":icon.png" }; + InstallProgress() + { + SetBuildString(label2); + } + Picture back { image = BitmapResource { ":ryoanji-progress.png" }, parent = this, position = { 0, 0 } }; Label installing { this, position = { 32, 160 } }; ProgressBar progressBar { parent = this, size = Size { 588, 24 }, anchor = Anchor { left = 24, top = 184 } }; Button finish { - parent = this, text = $"Install", disabled = true, isDefault = true, size = Size { 75, 23 }, anchor = Anchor { left = 432, top = 416 }; + parent = this, caption = $"Install", disabled = true, isDefault = true, size = Size { 75, 23 }, anchor = Anchor { left = 432, top = 440 }; NotifyClicked = ButtonCloseDialog }; Button cancel { - this, text = $"Cancel", hotKey = altX, size = Size { 75, 23 }, anchor = Anchor { left = 544, top = 416 }; + this, caption = $"Cancel", hotKey = altX, size = Size { 75, 23 }, anchor = Anchor { left = 544, top = 440 }; bool NotifyClicked(Button button, int x, int y, Modifiers mods) { @@ -1038,17 +1235,27 @@ class InstallProgress : Window multiLine = true, parent = label3, opacity = 0, borderStyle = none, size = Size { 350, 35 }, anchor = Anchor { horz = 111, vert = 13 }, 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 } }; - 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 } }; + Label label2 { parent = this, position = { 16, 422 }, 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 }; + cursor = ((GuiApplication)__thisModule).GetCursor(hand); + + bool OnLeftButtonDown(int x, int y, Modifiers mods) + { + ShellOpen("http://www.ecere.com/"); + return true; + } + }; + Label title { parent = label3, caption = $"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) { int tw = label2.size.w; surface.SetForeground(Color { 128, 128, 128 }); - surface.HLine(label2.position.x + tw + 6, 620, 400); + surface.HLine(label2.position.x + tw + 6, 620, 430); surface.SetForeground(white); - surface.HLine(label2.position.x + tw + 6, 621, 401); + surface.HLine(label2.position.x + tw + 6, 621, 431); surface.PutPixel(621, 400); } @@ -1064,119 +1271,127 @@ class InstallProgress : Window Installer installer {}; InstallProgress installProgress { autoCreate = false }; -void ModifyPath(char * newPath) +static void AddPath(char * sysPaths[200], int sysCount, char * paths[200], int * count, char * oldPath, char * userPath, char * path) { - char * paths[100]; - int p, count; - char oldPath[4096]; - CoreSDKID c; - - strcpy(oldPath, newPath); - count = TokenizeWith(oldPath, sizeof(paths) / sizeof(char *), paths, ";", false); - - for(c = 0; coreSDK[c].name; c++) + int p; + bool found = false; + for(p = 0; p