diff --git a/.github/workflows/DevBuild.yml b/.github/workflows/DevBuild.yml index 0561e2635..48c43bb7d 100644 --- a/.github/workflows/DevBuild.yml +++ b/.github/workflows/DevBuild.yml @@ -9,6 +9,10 @@ name: HeliosDev Build & Create MSI Files on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: + +# needed to publish the installers as a GitHub Release +permissions: + contents: write jobs: build: @@ -22,6 +26,26 @@ jobs: fetch-tags: true fetch-depth: 0 + - name: Stage clean source for the download package + # copy every tracked file (including submodules) before the build creates or changes anything + shell: cmd + run: | + git -c core.quotepath=off ls-files --recurse-submodules > "%RUNNER_TEMP%\source-files.txt" + tar -c -f "%RUNNER_TEMP%\source.tar" -T "%RUNNER_TEMP%\source-files.txt" + mkdir "%RUNNER_TEMP%\package\Helios-Developer-Edition" + tar -x -f "%RUNNER_TEMP%\source.tar" -C "%RUNNER_TEMP%\package\Helios-Developer-Edition" + + - name: Choose version number + # every build gets the next number (1.6.1001.0, 1.6.1002.0, ...) so a new installer replaces the previous one; + # it stays in the 1.6.1xxx.x range that the installer scripts treat as a development build + shell: pwsh + run: | + $build = 1000 + ${{ github.run_number }} + if ($build -gt 1999) { throw "Developer Edition version numbers are exhausted; change the numbering in DevBuild.yml." } + $version = "1.6.$build.0" + echo "DEV_VERSION=$version" >> $env:GITHUB_ENV + echo "Building Helios Developer Edition $version" + - name: Setup MSBuild uses: microsoft/setup-msbuild@v2 @@ -53,7 +77,7 @@ jobs: continue-on-error: true shell: cmd run: | - build.cmd test + build.cmd dev %DEV_VERSION% echo "rc=%errorlevel%" >> $env:GITHUB_ENV - name: zip up build logs @@ -82,6 +106,44 @@ jobs: tar -a -c -f "./Assets/HeliosDev32Bit_Installers.zip" -C "Helios Installer/Release32" *.msi tar -a -c -f "./Assets/HeliosDev_StreamDeck_Alpha.zip" -C "bin/x64/Release" Plugins/OpenMacroBoard.SDK.dll Plugins/OpenMacroBoard.VirtualBoard.dll Plugins/StreamDeckSharp.dll Plugins/HeliosMacroBoard.dll + - name: Publish installers as a GitHub Release + # each build becomes a Release on the repository's main page with: + # - the 64-bit and 32-bit Developer Edition installers + # - one zip with the full source and an Installers folder holding both installers + env: + GH_TOKEN: ${{ github.token }} + shell: pwsh + run: | + $msi64 = Get-ChildItem "Helios Installer/Release/Helios.*.msi" | Select-Object -First 1 + $msi32 = Get-ChildItem "Helios Installer/Release32/Helios32bit.*.msi" | Select-Object -First 1 + if (-not $msi64 -or -not $msi32) { throw "Installers were not built, nothing to publish." } + + $out = Join-Path $env:RUNNER_TEMP "release" + New-Item -ItemType Directory -Force -Path $out | Out-Null + Copy-Item $msi64.FullName (Join-Path $out "Helios-Developer-Edition-64bit.msi") + Copy-Item $msi32.FullName (Join-Path $out "Helios-Developer-Edition-32bit.msi") + + $pkg = Join-Path $env:RUNNER_TEMP "package/Helios-Developer-Edition" + $inst = Join-Path $pkg "Installers" + New-Item -ItemType Directory -Force -Path $inst | Out-Null + Copy-Item (Join-Path $out "Helios-Developer-Edition-64bit.msi") $inst + Copy-Item (Join-Path $out "Helios-Developer-Edition-32bit.msi") $inst + tar -a -c -f (Join-Path $out "Helios-Developer-Edition-source-and-installers.zip") -C (Join-Path $env:RUNNER_TEMP "package") "Helios-Developer-Edition" + + $tag = "developer-edition-$env:DEV_VERSION" + $notes = "Helios Developer Edition $env:DEV_VERSION built from commit ${{ github.sha }} on branch ${{ github.ref_name }}.`n`n" + + "- Helios-Developer-Edition-64bit.msi: installer for 64-bit Windows (most PCs)`n" + + "- Helios-Developer-Edition-32bit.msi: installer for 32-bit Windows`n" + + "- Helios-Developer-Edition-source-and-installers.zip: full source code with both installers in its Installers folder`n`n" + + "Installs to Program Files\Helios Development alongside regular Helios and adds a Developer Edition shortcut to the desktop." + gh release create $tag ` + (Join-Path $out "Helios-Developer-Edition-64bit.msi") ` + (Join-Path $out "Helios-Developer-Edition-32bit.msi") ` + (Join-Path $out "Helios-Developer-Edition-source-and-installers.zip") ` + --repo "${{ github.repository }}" --target "${{ github.sha }}" ` + --title "Helios Developer Edition $env:DEV_VERSION" --notes $notes + if ($LASTEXITCODE -ne 0) { throw "Publishing the release failed." } + - name: Upload Helios_Installers 1 uses: actions/upload-artifact@v4 with: diff --git a/BUILD-DEVELOPER-EDITION.txt b/BUILD-DEVELOPER-EDITION.txt new file mode 100644 index 000000000..a87d4d0ac --- /dev/null +++ b/BUILD-DEVELOPER-EDITION.txt @@ -0,0 +1,46 @@ +Helios Developer Edition - how to build the installer +===================================================== + +This folder is the complete source for Helios Developer Edition +(branch helios-developer-edition), including the third-party submodules. + +Ready-made installers + Every GitHub build publishes a Release on https://github.com/mphillippi7804/Helios/releases with: + Helios-Developer-Edition-64bit.msi installer for 64-bit Windows (most PCs) + Helios-Developer-Edition-32bit.msi installer for 32-bit Windows + Helios-Developer-Edition-source-and-installers.zip + this source, with both installers in its Installers folder + If this folder came from that zip, the installers are already in the Installers folder. + +Option A - GitHub (no software needed on your PC) + Your fork mphillippi7804/Helios already has this branch. + 1. On github.com open your fork > Actions > "HeliosDev Build & Create MSI Files". + 2. Click "Run workflow", choose branch helios-developer-edition, Run. + 3. When it finishes, the installers appear as a new Release on your fork's Releases page + (they are also attached to the run page as artifacts for 2 days). + +Option B - build on a Windows PC + Requirements: + - Windows 10/11 + - Visual Studio 2022 or newer with the ".NET desktop development" workload + and the .NET Framework 4.7.2 targeting pack + - Visual Studio extension "Microsoft Visual Studio Installer Projects" + - NuGet command line (nuget.exe) on PATH + Steps, from a "Developer Command Prompt for VS" in this folder: + nuget restore BuildMeFirst.sln + nuget restore "KeyPressReceiver/Keypress Receiver.csproj" + nuget restore Thirdparty/StreamDeckSharp/src/StreamDeckSharp/StreamDeckSharp.csproj + nuget restore Thirdparty/OpenMacroBoard.SDK/src/OpenMacroBoard.SDK/OpenMacroBoard.SDK.csproj + nuget restore Thirdparty/OpenMacroBoard.SDK/src/OpenMacroBoard.VirtualBoard/OpenMacroBoard.VirtualBoard.csproj + nuget restore Helios.sln + build.cmd test + or, to give the build its own version number (needed for a new installer to replace an older one): + build.cmd dev 1.6.1500.0 + (keep the third number between 1000 and 1999 and higher than the version you have installed; + GitHub builds count up automatically: 1.6.1005.0, 1.6.1006.0, ...) + The installers are written to: + Helios Installer\Release\Helios..msi (64-bit) + Helios Installer\Release32\Helios32bit..msi (32-bit) + (The file is named Helios...msi because the build scripts expect that name; + it installs as "Helios Developer Edition" in Program Files\Helios Development, + alongside regular Helios.) diff --git a/Helios Installer/Helios Installer.vdproj b/Helios Installer/Helios Installer.vdproj index d42fd95d1..bf9f3b737 100644 --- a/Helios Installer/Helios Installer.vdproj +++ b/Helios Installer/Helios Installer.vdproj @@ -3924,7 +3924,7 @@ { "{9EF0B969-E518-4E46-987F-47570745A589}:_937487924C53439892F37CF38F2AF25A" { - "Name" = "8:Helios" + "Name" = "8:Helios Developer Edition" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" @@ -3948,7 +3948,7 @@ } "{3C67513D-01DD-4637-8A68-80971EB9504F}:_E384890BFB804E8DBFE6ADCE0EDB8172" { - "DefaultLocation" = "8:[ProgramFiles64Folder][Manufacturer]\\[ProductName]" + "DefaultLocation" = "8:[ProgramFiles64Folder]Helios Development" "Name" = "8:#1925" "AlwaysCreate" = "11:TRUE" "Condition" = "8:" @@ -4116,10 +4116,10 @@ "Product" { "Name" = "8:Microsoft Visual Studio" - "ProductName" = "8:Helios" - "ProductCode" = "8:{421509D7-A828-4190-8C5E-8E1D34BAA66F}" - "PackageCode" = "8:{531526BD-654F-45DC-B26B-0F01475637F3}" - "UpgradeCode" = "8:{589D8667-3ED9-478B-8F67-A56E4FADBC63}" + "ProductName" = "8:Helios Developer Edition" + "ProductCode" = "8:{D9EDC67F-BB34-499C-B559-F16B1A8D9425}" + "PackageCode" = "8:{9F425DB3-5AC3-4E56-8A7D-428CEAED4085}" + "UpgradeCode" = "8:{61ABF5C4-2190-4DF7-8D49-7203DFD55DE0}" "AspNetVersion" = "8:4.0.30319.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:TRUE" @@ -4129,7 +4129,7 @@ "Manufacturer" = "8:Helios Virtual Cockpit" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:https://github.com/HeliosVirtualCockpit/Helios/issues/" - "Title" = "8:Helios" + "Title" = "8:Helios Developer Edition" "Subject" = "8:" "ARPCONTACT" = "8:Helios Contributors" "Keywords" = "8:Helios DCS BMS Cockpit" @@ -4240,7 +4240,7 @@ { "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_04C07E0DE5FE4A0EB4EDFB607E9D253D" { - "Name" = "8:Helios Profile Editor" + "Name" = "8:Developer Edition" "Arguments" = "8:" "Description" = "8:" "ShowCmd" = "3:1" @@ -4268,7 +4268,7 @@ } "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_4959DA6DB3794FBA92F8B9F85C1ACFC9" { - "Name" = "8:Helios Profile Editor" + "Name" = "8:Developer Edition" "Arguments" = "8:" "Description" = "8:" "ShowCmd" = "3:1" @@ -4280,25 +4280,11 @@ "Icon" = "8:_0772EF6D6A1143D284A5C9123C4C6E66" "Feature" = "8:" } - "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_4BAAECF7E41641BDB7D05D98A8B87D5D" - { - "Name" = "8:Helios Control Center" - "Arguments" = "8:" - "Description" = "8:" - "ShowCmd" = "3:1" - "IconIndex" = "3:0" - "Transitive" = "11:FALSE" - "Target" = "8:_60AF79F40A8140E9B89B3252BF8A567C" - "Folder" = "8:_AD59734AD6DF48A39047EBE90EC7C76E" - "WorkingFolder" = "8:_E384890BFB804E8DBFE6ADCE0EDB8172" - "Icon" = "8:_732146C3695F4256A3FBB284936E4563" - "Feature" = "8:" - } "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_53AFDF753B84467AB063EF6F037857AC" { - "Name" = "8:Profile Editor Debug" + "Name" = "8:Developer Edition Debug" "Arguments" = "8:-l Debug" - "Description" = "8:Profile Editor with Loglevel Debug" + "Description" = "8:Developer Edition with Loglevel Debug" "ShowCmd" = "3:1" "IconIndex" = "3:0" "Transitive" = "11:FALSE" @@ -4818,7 +4804,7 @@ } "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_0C23ED5842AB4CD4BE1266E39F55D6D2" { - "SourcePath" = "8:..\\Profile Editor\\obj\\x64\\Release\\Profile Editor.exe" + "SourcePath" = "8:..\\Profile Editor\\obj\\x64\\Release\\Developer Edition.exe" "TargetName" = "8:" "Tag" = "8:" "Folder" = "8:_E384890BFB804E8DBFE6ADCE0EDB8172" diff --git a/Helios Installer/Helios32bit Installer.vdproj b/Helios Installer/Helios32bit Installer.vdproj index f37ea015f..ceb4efa83 100644 --- a/Helios Installer/Helios32bit Installer.vdproj +++ b/Helios Installer/Helios32bit Installer.vdproj @@ -3903,7 +3903,7 @@ { "{9EF0B969-E518-4E46-987F-47570745A589}:_937487924C53439892F37CF38F2AF25A" { - "Name" = "8:Helios" + "Name" = "8:Helios Developer Edition" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" "Transitive" = "11:FALSE" @@ -3927,7 +3927,7 @@ } "{3C67513D-01DD-4637-8A68-80971EB9504F}:_E384890BFB804E8DBFE6ADCE0EDB8172" { - "DefaultLocation" = "8:[ProgramFilesFolder][Manufacturer]\\[ProductName]" + "DefaultLocation" = "8:[ProgramFilesFolder]Helios Development" "Name" = "8:#1925" "AlwaysCreate" = "11:TRUE" "Condition" = "8:" @@ -4095,10 +4095,10 @@ "Product" { "Name" = "8:Microsoft Visual Studio" - "ProductName" = "8:Helios" - "ProductCode" = "8:{421509D7-A828-4190-8C5E-8E1D34BAA66F}" - "PackageCode" = "8:{14E07531-7433-4D31-8378-1E336DD197ED}" - "UpgradeCode" = "8:{589D8667-3ED9-478B-8F67-A56E4FADBC63}" + "ProductName" = "8:Helios Developer Edition" + "ProductCode" = "8:{D9EDC67F-BB34-499C-B559-F16B1A8D9425}" + "PackageCode" = "8:{C9D446CE-A9BA-4AFE-87E7-87F45B0C86F4}" + "UpgradeCode" = "8:{61ABF5C4-2190-4DF7-8D49-7203DFD55DE0}" "AspNetVersion" = "8:4.0.30319.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:TRUE" @@ -4108,7 +4108,7 @@ "Manufacturer" = "8:Helios Virtual Cockpit" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:https://github.com/HeliosVirtualCockpit/Helios/issues/" - "Title" = "8:Helios" + "Title" = "8:Helios Developer Edition" "Subject" = "8:" "ARPCONTACT" = "8:Helios Contributors" "Keywords" = "8:Helios DCS BMS Cockpit" @@ -4219,7 +4219,7 @@ { "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_04C07E0DE5FE4A0EB4EDFB607E9D253D" { - "Name" = "8:Helios Profile Editor" + "Name" = "8:Developer Edition" "Arguments" = "8:" "Description" = "8:" "ShowCmd" = "3:1" @@ -4247,7 +4247,7 @@ } "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_4959DA6DB3794FBA92F8B9F85C1ACFC9" { - "Name" = "8:Helios Profile Editor" + "Name" = "8:Developer Edition" "Arguments" = "8:" "Description" = "8:" "ShowCmd" = "3:1" @@ -4259,25 +4259,11 @@ "Icon" = "8:_0772EF6D6A1143D284A5C9123C4C6E66" "Feature" = "8:" } - "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_4BAAECF7E41641BDB7D05D98A8B87D5D" - { - "Name" = "8:Helios Control Center" - "Arguments" = "8:" - "Description" = "8:" - "ShowCmd" = "3:1" - "IconIndex" = "3:0" - "Transitive" = "11:FALSE" - "Target" = "8:_60AF79F40A8140E9B89B3252BF8A567C" - "Folder" = "8:_AD59734AD6DF48A39047EBE90EC7C76E" - "WorkingFolder" = "8:_E384890BFB804E8DBFE6ADCE0EDB8172" - "Icon" = "8:_732146C3695F4256A3FBB284936E4563" - "Feature" = "8:" - } "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_53AFDF753B84467AB063EF6F037857AC" { - "Name" = "8:Profile Editor Debug" + "Name" = "8:Developer Edition Debug" "Arguments" = "8:-l Debug" - "Description" = "8:Profile Editor with Loglevel Debug" + "Description" = "8:Developer Edition with Loglevel Debug" "ShowCmd" = "3:1" "IconIndex" = "3:0" "Transitive" = "11:FALSE" @@ -4797,7 +4783,7 @@ } "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_0C23ED5842AB4CD4BE1266E39F55D6D2" { - "SourcePath" = "8:..\\Profile Editor\\obj\\AnyCPU32\\Release\\Profile Editor.exe" + "SourcePath" = "8:..\\Profile Editor\\obj\\AnyCPU32\\Release\\Developer Edition.exe" "TargetName" = "8:" "Tag" = "8:" "Folder" = "8:_E384890BFB804E8DBFE6ADCE0EDB8172" diff --git a/Helios Installer/HeliosInstallAdjustments.vbs b/Helios Installer/HeliosInstallAdjustments.vbs index 1c1bb8a07..c284826b9 100644 --- a/Helios Installer/HeliosInstallAdjustments.vbs +++ b/Helios Installer/HeliosInstallAdjustments.vbs @@ -25,6 +25,10 @@ else Dim toolsUpgrade:toolsUpgrade = "{1A6DEA70-100A-4C3B-A9D9-64340BEAC520}" Dim upgradeCode:upgradeCode = heliosUpgrade + ' upgrade code for Helios Developer Edition, which installs alongside regular Helios + ' in Program Files\Helios Development (must match UpgradeCode in the Helios installer projects) + Dim heliosDevEditionUpgrade:heliosDevEditionUpgrade = "{61ABF5C4-2190-4DF7-8D49-7203DFD55DE0}" + ' upgrade code for Helios Development Prototypes Dim heliosDevUpgrade:heliosDevUpgrade = "{BA7FFC56-BDB7-4B02-8A12-089A630CCF96}" @@ -34,7 +38,10 @@ else Dim session : Set session = installer.OpenPackage(database,1) : If Err <> 0 Then Fail "Installer: '" & msiPackage & "' has invalid installer package format" ' check product (this script is shared) - if session.Property("ProductName") = "Helios Keypress Receiver" then + if session.Property("ProductName") = "Helios Developer Edition" then + Wscript.Echo "configuring Helios Developer Edition" + upgradeCode = heliosDevEditionUpgrade + elseif session.Property("ProductName") = "Helios Keypress Receiver" then Wscript.Echo "configuring Helios Keypress Receiver Installer" upgradeCode = keypressUpgrade elseif session.Property("ProductName") = "Helios Developer Tools" then @@ -55,7 +62,7 @@ else ' run custom actions as user instead of system Execute database, "UPDATE CustomAction SET `Type` = 1025 WHERE `Type` = 3073" - if session.Property("ProductName") = "Helios" then + if session.Property("ProductName") = "Helios" or session.Property("ProductName") = "Helios Developer Edition" then if not RemoveProblemComponent( database, "PATCHING.DLL|patching.dll") then ' if lowercase was not found then try mixed case if not RemoveProblemComponent( database, "PATCHING.DLL|Patching.dll") then @@ -70,7 +77,11 @@ else Set devBuild = New RegExp devBuild.Pattern = "[0-9]+\.[0-9]+\.1...\.[0-9]+" if devBuild.Test(version) then - Execute database, "DELETE FROM Shortcut WHERE `Directory_` = 'DesktopFolder' " + ' development builds normally get no desktop shortcuts, but Helios Developer Edition keeps + ' its "Developer Edition" desktop shortcut (it is the only desktop shortcut it installs) + if session.Property("ProductName") <> "Helios Developer Edition" then + Execute database, "DELETE FROM Shortcut WHERE `Directory_` = 'DesktopFolder' " + end if Execute database, "UPDATE Shortcut SET `Name` = 'CONTRO~1|Dev Control Center Debug' WHERE `Name` = 'CONTRO~1|Control Center Debug'" Execute database, "UPDATE Shortcut SET `Name` = 'PROFIL~1|Dev Profile Editor Debug' WHERE `Name` = 'PROFIL~1|Profile Editor Debug'" Execute database, "UPDATE Shortcut SET `Name` = 'HELIOS~2|Dev Helios Profile Editor' WHERE `Name` = 'HELIOS~2|Helios Profile Editor'" diff --git a/Helios/ConfigManager.cs b/Helios/ConfigManager.cs index f3eb2405e..8d6f1f028 100644 --- a/Helios/ConfigManager.cs +++ b/Helios/ConfigManager.cs @@ -109,7 +109,7 @@ private static void ReportFatalWriteFailureAndExit(string path) MessageBox.Show($"Helios could not write to its own data folder at '{path}'. " + "Most likely you have an anti virus or 'application firewall' that is trying to protect your 'Documents' folder.\n\n" + "These types of features are sometimes called 'Ransomware Protection' or 'Controlled Folder Access' (in Windows).\n\n" - + "You will need to give permission to 'Profile Editor.exe', 'HeliosPatching.exe' and 'Control Center.exe' so that\n" + + "You will need to give permission to 'Profile Editor.exe' (or 'Developer Edition.exe'), 'HeliosPatching.exe' and 'Control Center.exe' so that\n" + "Helios can use its own folders.\n\n" + "Helios will now exit.", "Write Access to Helios Folder Denied"); diff --git a/Helios/Controls/ImageDecorationBase.cs b/Helios/Controls/ImageDecorationBase.cs index 562051d38..b85396088 100644 --- a/Helios/Controls/ImageDecorationBase.cs +++ b/Helios/Controls/ImageDecorationBase.cs @@ -143,20 +143,58 @@ public string Image } else { + // when an existing image is replaced in the Profile Editor, keep the control's size and scale the + // new image to fit it; the first image a control receives (new control, profile load, template) + // still sizes the control, and outside the editor (Control Center) behavior is unchanged image = ConfigManager.ImageManager.LoadImage(_imageFile); - if (image != null) + if (image != null && (string.IsNullOrEmpty(oldValue) || !DesignMode)) { Width = image.Width; Height = image.Height; } } - OnPropertyChanged("Image", oldValue, value, true); + NotifyImageChanged(oldValue, value); Refresh(); } } } + /// + /// Report the image change. A centered image is drawn at its own size, so when an existing image is + /// replaced, alignment switches to stretched so the new image scales to the size of the control. + /// Both changes are one undo step. + /// + private void NotifyImageChanged(string oldValue, string newValue) + { + UndoManager undo = ConfigManager.UndoManager; + bool switchAlignment = !string.IsNullOrEmpty(oldValue) + && !string.IsNullOrEmpty(newValue) + && _alignment == ImageAlignment.Centered + && DesignMode + && !(undo?.Working ?? false); + bool ownBatch = switchAlignment && undo != null && !undo.InBatch; + if (ownBatch) + { + undo.StartBatch(); + } + try + { + OnPropertyChanged("Image", oldValue, newValue, true); + if (switchAlignment) + { + Alignment = ImageAlignment.Stretched; + } + } + finally + { + if (ownBatch) + { + undo.CloseBatch(); + } + } + } + public ImageAlignment Alignment { get diff --git a/Helios/Controls/ImageTranslucent.cs b/Helios/Controls/ImageTranslucent.cs index 8bf0fc808..b3598f051 100644 --- a/Helios/Controls/ImageTranslucent.cs +++ b/Helios/Controls/ImageTranslucent.cs @@ -76,8 +76,11 @@ public string Image image = refreshCapableImage.LoadImage(Image, Convert.ToInt32(Width), Convert.ToInt32(Height), LoadImageOptions.ReloadIfChangedExternally); } } - else + else if (string.IsNullOrEmpty(oldValue) || !DesignMode) { + // when an existing image is replaced in the Profile Editor, keep the control's size and scale the + // new image to fit it; the first image a control receives (new control, profile load, template) + // still sizes the control, and outside the editor (Control Center) behavior is unchanged image = ConfigManager.ImageManager.LoadImage(_imageFile); if (image != null) { @@ -90,12 +93,47 @@ public string Image Height = 100d; } } - OnPropertyChanged("Image", oldValue, value, true); + NotifyImageChanged(oldValue, value); Refresh(); } } } + /// + /// Report the image change. A centered image is drawn at its own size, so when an existing image is + /// replaced, alignment switches to stretched so the new image scales to the size of the control. + /// Both changes are one undo step. + /// + private void NotifyImageChanged(string oldValue, string newValue) + { + UndoManager undo = ConfigManager.UndoManager; + bool switchAlignment = !string.IsNullOrEmpty(oldValue) + && !string.IsNullOrEmpty(newValue) + && _alignment == ImageAlignment.Centered + && DesignMode + && !(undo?.Working ?? false); + bool ownBatch = switchAlignment && undo != null && !undo.InBatch; + if (ownBatch) + { + undo.StartBatch(); + } + try + { + OnPropertyChanged("Image", oldValue, newValue, true); + if (switchAlignment) + { + Alignment = ImageAlignment.Stretched; + } + } + finally + { + if (ownBatch) + { + undo.CloseBatch(); + } + } + } + public ImageAlignment Alignment { get diff --git a/Helios/Controls/KneeBoard.cs b/Helios/Controls/KneeBoard.cs index e52ae68f3..c40e37ce3 100644 --- a/Helios/Controls/KneeBoard.cs +++ b/Helios/Controls/KneeBoard.cs @@ -92,7 +92,8 @@ public string Image ImageSource image = ConfigManager.ImageManager.LoadImage(_positions[0].Name); //_imageFile - if (image != null) + // in the Profile Editor, only size to the image the first time; afterwards the image scales to the control + if (image != null && (string.IsNullOrEmpty(oldValue) || !DesignMode)) { Width = image.Width; Height = image.Height; diff --git a/Helios/HeliosVisualContainer.cs b/Helios/HeliosVisualContainer.cs index 9ec7ef8f0..09e26f3d8 100644 --- a/Helios/HeliosVisualContainer.cs +++ b/Helios/HeliosVisualContainer.cs @@ -40,22 +40,23 @@ public override void ScaleChildren(double scaleX, double scaleY) { foreach (HeliosVisual visual in Children) { - if (visual.Left > 0) - { - double locXDif = visual.Left; - visual.Left += (locXDif * scaleX) - locXDif; - } + // position scales with the container, including devices that hang off the left or top edge + visual.Left *= scaleX; + visual.Top *= scaleY; - if (visual.Top > 0) + // a device turned 90 degrees has its own width running along the container's height + double childScaleX = scaleX; + double childScaleY = scaleY; + if (visual.Rotation != HeliosVisualRotation.None && visual.Rotation != HeliosVisualRotation.ROT180) { - double locYDif = visual.Top; - visual.Top += (locYDif * scaleY) - locYDif; + childScaleX = scaleY; + childScaleY = scaleX; } - visual.Width = Math.Max(visual.Width * scaleX, 1d); - visual.Height = Math.Max(visual.Height * scaleY, 1d); + visual.Width = Math.Max(visual.Width * childScaleX, 1d); + visual.Height = Math.Max(visual.Height * childScaleY, 1d); - visual.ScaleChildren(scaleX, scaleY); + visual.ScaleChildren(childScaleX, childScaleY); } } diff --git a/Helios/UndoManager.cs b/Helios/UndoManager.cs index 7991d5dda..a07f54ce9 100644 --- a/Helios/UndoManager.cs +++ b/Helios/UndoManager.cs @@ -62,6 +62,12 @@ public UndoManager() /// public bool CanRedo => _redoEvents.Count > 0 && !Working && _batch == null; + /// + /// Gets a value indicating whether a batch is currently open, so callers that want to group + /// several changes into one undo step know whether they need to open (and close) their own. + /// + public bool InBatch => _batch != null; + /// /// Rollback the last command. /// diff --git a/HeliosInstallAdjustments.vbs b/HeliosInstallAdjustments.vbs index 6e4b72b85..75c300566 100644 --- a/HeliosInstallAdjustments.vbs +++ b/HeliosInstallAdjustments.vbs @@ -26,6 +26,10 @@ else Dim heliosF15EPluginUpgrade:heliosF15EPluginUpgrade = "{CCACC9F3-3F71-4CE5-8A7E-3CCF3746FC46}" Dim upgradeCode:upgradeCode = heliosUpgrade + ' upgrade code for Helios Developer Edition, which installs alongside regular Helios + ' in Program Files\Helios Development (must match UpgradeCode in the Helios installer projects) + Dim heliosDevEditionUpgrade:heliosDevEditionUpgrade = "{61ABF5C4-2190-4DF7-8D49-7203DFD55DE0}" + ' upgrade code for Helios Development Prototypes Dim heliosDevUpgrade:heliosDevUpgrade = "{BA7FFC56-BDB7-4B02-8A12-089A630CCF96}" Dim heliosDevF15EPluginUpgrade:heliosDevF15EPluginUpgrade = "{FF1DE3B4-D0F2-4BC6-AE4C-DCD07C7FFF24}" @@ -36,7 +40,10 @@ else Dim session : Set session = installer.OpenPackage(database,1) : If Err <> 0 Then Fail "Installer: '" & msiPackage & "' has invalid installer package format" ' check product (this script is shared) - if session.Property("ProductName") = "Helios Keypress Receiver" then + if session.Property("ProductName") = "Helios Developer Edition" then + Wscript.Echo "configuring Helios Developer Edition" + upgradeCode = heliosDevEditionUpgrade + elseif session.Property("ProductName") = "Helios Keypress Receiver" then Wscript.Echo "configuring Helios Keypress Receiver Installer" upgradeCode = keypressUpgrade elseif session.Property("ProductName") = "Helios Developer Tools" then diff --git a/Profile Editor/ArchiveInstall/Welcome.xaml b/Profile Editor/ArchiveInstall/Welcome.xaml index acd9a69d2..16b55471a 100644 --- a/Profile Editor/ArchiveInstall/Welcome.xaml +++ b/Profile Editor/ArchiveInstall/Welcome.xaml @@ -26,7 +26,7 @@ Work through the Interface Status until all the interfaces shown there have a green "check mark" status. Use the button on the right to get started. When you are done, return here via the "Installlation Mode" tab shown at the bottom.