├── .github └── FUNDING.yml ├── .gitignore ├── .vs └── ToolbarControl │ └── v15 │ ├── Server │ └── sqlite3 │ │ ├── db.lock │ │ └── storage.ide │ └── sqlite3 │ ├── db.lock │ └── storage.ide ├── BUGS.txt ├── ChangeLog.txt ├── GameData └── 001_ToolbarControl │ ├── LICENSE.md │ ├── PluginData │ ├── Intro.txt │ └── Textures │ │ ├── toolbar_24.png │ │ ├── toolbar_38.png │ │ └── window.png │ ├── README.md │ └── ToolbarControl.version ├── LICENSE.md ├── README.md ├── ToolbarControl.sln ├── ToolbarControl.version ├── ToolbarControl.version.1-12-3 ├── ToolbarControl ├── AssemblyVersion.cs ├── AssemblyVersion.tt ├── BlizzyOptions.cs ├── ConfigInfo.cs ├── InstallChecker.cs ├── IntroWindow.cs ├── Log.cs ├── Properties │ └── AssemblyInfo.cs ├── RegisterToolbar.cs ├── RegisterUsage.cs ├── Resources │ ├── btnBackground.png │ ├── btnClose.png │ ├── btnDelete.png │ ├── btnExpand.png │ ├── btnLock.png │ ├── btnOpen.png │ ├── btnRename.png │ ├── btnSave.png │ ├── btnUnlock.png │ ├── flask-38.png │ ├── flask.png │ ├── sheet-38.png │ └── sheet.png ├── Settings.cs ├── ToolbarControl.cs ├── ToolbarControl.csproj ├── ToolbarControl.csproj.173 ├── ToolbarControl.csproj.orig └── ToolbarWrapper.cs ├── buildRelease.bat ├── deploy.bat └── jenkins.txt /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: linuxgurugamer 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | custom: # Replace with a single custom sponsorship URL 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # MSTest test Results 20 | [Tt]est[Rr]esult*/ 21 | [Bb]uild[Ll]og.* 22 | 23 | #NUNIT 24 | *.VisualState.xml 25 | TestResult.xml 26 | 27 | # Build Results of an ATL Project 28 | [Dd]ebugPS/ 29 | [Rr]eleasePS/ 30 | dlldata.c 31 | 32 | *_i.c 33 | *_p.c 34 | *_i.h 35 | *.ilk 36 | *.meta 37 | *.obj 38 | *.pch 39 | *.pdb 40 | *.pgc 41 | *.pgd 42 | *.rsp 43 | *.sbr 44 | *.tlb 45 | *.tli 46 | *.tlh 47 | *.tmp 48 | *.tmp_proj 49 | *.log 50 | *.vspscc 51 | *.vssscc 52 | .builds 53 | *.pidb 54 | *.svclog 55 | *.scc 56 | 57 | # Chutzpah Test files 58 | _Chutzpah* 59 | 60 | # Visual C++ cache files 61 | ipch/ 62 | *.aps 63 | *.ncb 64 | *.opensdf 65 | *.sdf 66 | *.cachefile 67 | 68 | # Visual Studio profiler 69 | *.psess 70 | *.vsp 71 | *.vspx 72 | 73 | # TFS 2012 Local Workspace 74 | $tf/ 75 | 76 | # Guidance Automation Toolkit 77 | *.gpState 78 | 79 | # ReSharper is a .NET coding add-in 80 | _ReSharper*/ 81 | *.[Rr]e[Ss]harper 82 | *.DotSettings.user 83 | 84 | # JustCode is a .NET coding addin-in 85 | .JustCode 86 | 87 | # TeamCity is a build add-in 88 | _TeamCity* 89 | 90 | # DotCover is a Code Coverage Tool 91 | *.dotCover 92 | 93 | # NCrunch 94 | *.ncrunch* 95 | _NCrunch_* 96 | .*crunch*.local.xml 97 | 98 | # MightyMoose 99 | *.mm.* 100 | AutoTest.Net/ 101 | 102 | # Web workbench (sass) 103 | .sass-cache/ 104 | 105 | # Installshield output folder 106 | [Ee]xpress/ 107 | 108 | # DocProject is a documentation generator add-in 109 | DocProject/buildhelp/ 110 | DocProject/Help/*.HxT 111 | DocProject/Help/*.HxC 112 | DocProject/Help/*.hhc 113 | DocProject/Help/*.hhk 114 | DocProject/Help/*.hhp 115 | DocProject/Help/Html2 116 | DocProject/Help/html 117 | 118 | # Click-Once directory 119 | publish/ 120 | 121 | # Publish Web Output 122 | *.[Pp]ublish.xml 123 | *.azurePubxml 124 | 125 | # NuGet Packages Directory 126 | packages/ 127 | ## TODO: If the tool you use requires repositories.config uncomment the next line 128 | #!packages/repositories.config 129 | 130 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 131 | # This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) 132 | !packages/build/ 133 | 134 | # Windows Azure Build Output 135 | csx/ 136 | *.build.csdef 137 | 138 | # Windows Store app package directory 139 | AppPackages/ 140 | 141 | # Others 142 | sql/ 143 | *.Cache 144 | ClientBin/ 145 | [Ss]tyle[Cc]op.* 146 | ~$* 147 | *~ 148 | *.dbmdl 149 | *.dbproj.schemaview 150 | *.pfx 151 | *.publishsettings 152 | node_modules/ 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | *.mdf 166 | *.ldf 167 | 168 | # Business Intelligence projects 169 | *.rdl.data 170 | *.bim.layout 171 | *.bim_*.settings 172 | 173 | # Microsoft Fakes 174 | FakesAssemblies/ 175 | 176 | # ========================= 177 | # Operating System Files 178 | # ========================= 179 | 180 | # OSX 181 | # ========================= 182 | 183 | .DS_Store 184 | .AppleDouble 185 | .LSOverride 186 | 187 | # Icon must ends with two \r. 188 | Icon 189 | 190 | # Thumbnails 191 | ._* 192 | 193 | # Files that might appear on external disk 194 | .Spotlight-V100 195 | .Trashes 196 | 197 | # Directories potentially created on remote AFP share 198 | .AppleDB 199 | .AppleDesktop 200 | Network Trash Folder 201 | Temporary Items 202 | .apdisk 203 | 204 | 205 | 206 | # Windows 207 | # ========================= 208 | 209 | # Windows image file caches 210 | Thumbs.db 211 | ehthumbs.db 212 | 213 | # Folder config file 214 | Desktop.ini 215 | 216 | # Recycle Bin used on file shares 217 | $RECYCLE.BIN/ 218 | 219 | # Windows Installer files 220 | *.cab 221 | *.msi 222 | *.msm 223 | *.msp 224 | 225 | # Windows shortcuts 226 | *.lnk 227 | 228 | # 229 | # Vim files 230 | # 231 | *~ 232 | *.swp 233 | *.dll 234 | *.pdb 235 | .vs/* 236 | 237 | -------------------------------------------------------------------------------- /.vs/ToolbarControl/v15/Server/sqlite3/db.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/.vs/ToolbarControl/v15/Server/sqlite3/db.lock -------------------------------------------------------------------------------- /.vs/ToolbarControl/v15/Server/sqlite3/storage.ide: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/.vs/ToolbarControl/v15/Server/sqlite3/storage.ide -------------------------------------------------------------------------------- /.vs/ToolbarControl/v15/sqlite3/db.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/.vs/ToolbarControl/v15/sqlite3/db.lock -------------------------------------------------------------------------------- /.vs/ToolbarControl/v15/sqlite3/storage.ide: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/.vs/ToolbarControl/v15/sqlite3/storage.ide -------------------------------------------------------------------------------- /BUGS.txt: -------------------------------------------------------------------------------- 1 | Can't have multiple buttons in a single namespace due to only using the Namespace as the only key in registeredMods 2 | See the RegisterMod() in RegisterUsage.cs, line 137 -------------------------------------------------------------------------------- /ChangeLog.txt: -------------------------------------------------------------------------------- 1 | ChangeLog 2 | 3 | 0.1.9.14 4 | Thanks to github user @averageksp for this: 5 | Fix Spelling Error (Blizzy toobar is now Blizzy toolbar) 6 | 7 | 0.1.9.13 8 | Fixed wrong URL in version file 9 | 10 | 0.1.9.12 11 | Fixed bug where memory was continually used when icons were being updated every frame on the Blizzy toolbar, even if no change had been made 12 | Updated version file to use github for version info 13 | fixed version info in changelog 14 | 15 | 0.1.9.11 16 | Updated internal assembly number, needed for new mod 17 | 18 | 0.1.9.10 19 | Added check for null image var when loading from file, if null, allocates a small texture first 20 | 21 | 0.1.9.9 22 | Release to get AssemblyFileVersion set properly, no functional change 23 | 24 | 0.1.9.8 25 | Reverted disabling the KSPAssembly number (had to modify build server to support this) 26 | 27 | 0.1.9.7 28 | Added ability to hide button even when Blizzy toolbar is not installed 29 | 30 | 0.1.9.6 31 | Reverted DLL name change, too many mods were using the original name 32 | 33 | 0.1.9.5 34 | Renamed DLL for CKAN compatibility 35 | Added AssemblyFileVersion 36 | Updated version file for 1.12 37 | 38 | 0.1.9.4 39 | Really did the MiniAVC update 40 | 41 | 0.1.9.3 42 | Updated MiniAVC.dll to 1.4.0.2 to fix a nasty CTD 43 | Some optimization work on related to the stock toolbar code, reduces the number of calls 44 | Unity makes every frame 45 | 46 | 0.1.9.2 47 | Removed some log spam 48 | 49 | 0.1.9.1 50 | Updated MiniAVC to 1.4.0 51 | 52 | 0.1.9 53 | Updated for 1.8 54 | Added Startup class 55 | 56 | 0.1.8.2 57 | Removed all UnBlur references 58 | 59 | 0.1.8.1 60 | Updated to add large icon to the toolbar.BigTexturePath (new in toolbar 1.7.20) 61 | Added InstallChecker 62 | Updated AssemblyVersion.tt 63 | Changed the message about: WARNING: RegisterMod to only show when debugmode is true 64 | Removed the unBlur mod as a hard dependency. It will use UnBlur if it's there, otherwise will fall back to reading the file 65 | Removed dependency check for unBlur 66 | 67 | 0.1.7 68 | Added dependency unBlur 69 | Added dependency checks for unblur, clickthroughblocker 70 | 71 | Replaced code which needless read the disk often with the unBlur clode to both fix blurring 72 | and needless reading of the disk 73 | Moved Textures directory out of the PluginData 74 | 75 | 0.1.6.20 76 | Removed KSP_VERSION_MAX 77 | 78 | 0.1.6.19 79 | Fixed URL in .version file 80 | Corrected text in intro 81 | 82 | 0.1.6.18 83 | Version bump to fix .version file 84 | 85 | 0.1.6.17 86 | Version bump for 1.5 rebuild 87 | 88 | 0.1.6.16 89 | Fixed harmless nullref which was occuring in a very few mods at initialization 90 | 91 | 0.1.6.15 92 | Thanks to github user @piezpiedpy and @mwerle for this fix to a very subtle problem: 93 | Intro window can be blank and the log spammed with errors, doesn't heppen often, mainly in a debug mode 94 | 95 | 0.1.6.14 96 | Fixed timing issue on toolbar registration 97 | Added log warning in case RegisterToolbar is called too late 98 | 99 | 0.1.6.13 100 | Reimplemented the Log.Debug, using a local file to store the debug value 101 | 102 | 0.1.6.12 103 | Commented out all Log.Debug lines because they were using the settings class which isn't instantiated in the beginning. Was causing nullrefs 104 | 105 | 0.1.6.11 106 | Added a debugMode setting 107 | Changed most Log.info to Log.Debug to reduce log spam 108 | 109 | 0.1.6.10 110 | Fixed Nullref when Blizzy toolbar not installed and buttons were selected to be on the Blizzy button 111 | 112 | 0.1.6.9 113 | Updated .version file for all 1.4 114 | 115 | 0.1.6.8 116 | Added code to load button textures from game database instead of the disk for the stock toolbar 117 | 118 | 0.1.6.7 119 | Fixed repaint issues causing NullRefs 120 | Now only shows mods which have regeristed in the current game, it still remembers all of them 121 | 122 | 0.1.6.6 123 | Added IsHovering 124 | Added StockPosition 125 | Added BlizzyPosition ( placeholder for now) 126 | Changed startup for registeration from MainMenu to instantly 127 | Added sorted list by mod id 128 | Reduced size of ToolbarController window 129 | Added two new methods: 130 | bool IsStockButtonManaged(ApplicationLauncherButton button, out string nameSpace, out string id, out string toolTip) 131 | bool IsBlizzyButtonManaged(IButton blizzyButton, out string nameSpace, out string id, out string toolTip) 132 | 133 | 0.1.6.5 134 | Fixed issue when both buttons are shown, if the mod was updating the textures, the stock texture wasn't being updated while the Blizzy texture was 135 | 136 | 0.1.6.4 137 | Added two methods, currently only working on the stock button: 138 | public void DisableMutuallyExclusive() 139 | public void EnableMutuallyExclusive() 140 | 141 | Fixed hovering over button in Blizzy toolbar not working 142 | 143 | 0.1.6.3 144 | Fixed nullrefs when blizzy toolbar not installed 145 | Added code to always show buttons on stock if lbizzy not installed 146 | 147 | 0.1.6.2 148 | Fixed nullref when setting textures and no stock button set 149 | 150 | 0.1.6.1 151 | Added KSPAssembly to AssemblyInfo.cs, will help with load order of DLLs 152 | 153 | 0.1.6 154 | Added code for mods to register with the toolbar Controller 155 | Added functions for mods to set and get the setting for the Blizzy toolbar 156 | Added window to allow users to change setting without having to go into the mod 157 | Added following methods, see the README for details: 158 | 159 | toolbarControl.UseButtons(string NameSpace); 160 | public static bool RegisterMod(string NameSpace, string DisplayName = "", bool useBlizzy = false, bool useStock = true, bool NoneAllowed = true) 161 | public static bool BlizzyActive(string NameSpace, bool? useBlizzy = null) 162 | public static bool StockActive(string NameSpace, bool? useStock = null) 163 | public static void ButtonsActive(string NameSpace, bool? useStock, bool? useBlizzy) 164 | public void UseStock(bool useStock) 165 | 166 | Cleaned up old commented-out code 167 | 168 | 0.1.5.9 169 | Fixed issue when doing a SetTrue or SetFalse before the button has actually been created 170 | 171 | 0.1.5.8 172 | Updated version file for 1.4.1-1.4.99 173 | 174 | 0.1.5.7 175 | fixed the LoadImageFromFile, the "public" was deleted somehow 176 | 177 | 0.1.5.6 178 | Added DDS to the possible image formats, only DXT1 and DXT5 are supported 179 | 180 | 0.1.5.5 181 | Added GIF to the possible image formats 182 | 183 | 0.1.5.4 184 | Fix for fuzzy buttons, looks for png and jpg files 185 | 186 | 0.1.5.3 187 | Fixed nullref when onTrue was called before button was created 188 | 189 | 0.1.5.2 190 | Fixed AddLeftRightClickCallbacks call 191 | 192 | 0.1.5.1 193 | Filled nullref when first called 194 | Fixed bug when a mod called SetTrue or SetFalse, the button would be set true/false, but the texture wasn't being changed 195 | 196 | 0.1.5.0 197 | Recompiled for 1.4.1 198 | 199 | 0.1.4.8 200 | Fixed issue with manually set textures not showing up when toolbar changed 201 | Fixed SetTexture so that by setting both large & small to empty strings, control of the icon will revert to the mod 202 | 203 | 0.1.4.7 204 | Fixed bug with not being able to have a button on the Blizzy toolbar only in the flight scene and not in the map view 205 | Added void SetTexture(string large, string small) to allow mod to change the button textures directly 206 | 207 | 0.1.4.6 208 | Added code to not try to use tooltips if not in a scene which supports it 209 | 210 | 0.1.4.5 211 | Fixed typo in the UseBlizzy method which was causing the blizzy toolbar to be always selected if it was called before the initial button creation 212 | 213 | 0.1.4.4 214 | Improved the UseBlizzy method to now allow setting it BEFORe creating the toolbar, this 215 | makes it possible to not have to use the UseBlizzy in an OnGUI if not desired 216 | Added methods: SetTrue() and SetFalse() 217 | 218 | 0.1.4.3 219 | Added method/function to allow mods to check to see if a toolbarbutton is controlled by this mod 220 | Renamed License.md and README.md 221 | 222 | 0.1.4.2 223 | Fixed mouse position for Blizzy toolbar 224 | Inverted the y value for the mouse position 225 | 226 | 0.1.4.1 227 | Fixed harmless nullrefs which were happening after clicking toolbar button 228 | Added checks to all callbacks for nulls 229 | 230 | 0.1.4 231 | Added left/right button callbacks 232 | Updated documentation 233 | 234 | 0.1.3.5 235 | More fixes re. stock buttons not being deleted 236 | 237 | 0.1.3.4 238 | Fixed issue where stock buttons weren't always being deleted 239 | 240 | 0.1.3.3 241 | Fixed download link in .version file 242 | 243 | 0.1.3.2 244 | Fixed bug where calling the SetFalse() wasn't properly doing the callbacks 245 | 246 | 0.1.3.1 247 | Moved mod into it's own folder 248 | 249 | 0.1.3 250 | Fixed nullref during game startup 251 | 252 | 0.1.2 253 | Fixed issue with stock toolbar not changing textures 254 | Replaced Debug.Log with logging class to reduce log spam 255 | 256 | 0.1.1 257 | Moved mod into the 000_Toolbar directory 258 | Added method to return location of mouse at last buttonclick 259 | Added Enable method to enable/disable the button 260 | Added tooltip for stock buttons 261 | Added settings page 262 | Show tooltips 263 | Stock tooltip timeout 264 | 265 | 0.1.0 266 | Initial release 267 | 268 | 269 | 270 | TODO 271 | Add tooltip options to Blizzy 272 | -------------------------------------------------------------------------------- /GameData/001_ToolbarControl/LICENSE.md: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /GameData/001_ToolbarControl/PluginData/Intro.txt: -------------------------------------------------------------------------------- 1 | The Toolbar Controller is a new mod which provides an easy way for the user to select which toolbar to use for mods which have toolbar button. 2 | 3 | KSP has a stock toolbar, located either along the bottom or side of the screen, depending on which scene you are in. 4 | 5 | There is another toolbar available as a mod, commonly referred to as the Blizzy Toolbar; called this because the original author was known as blizzy78. 6 | 7 | The button for the Toolbar Controller will be available in all scenes. The button looks like this, and can appear in either toolbar: 8 | 9 | 10 | 11 | Clicking the button for this mod will bring up a simple window which will look similar to the following image: 12 | 13 | 14 | 15 | For each mod that has registered itself with the Toolbar Controller, there will be a line with two radio buttons and the name of the mod. The buttons are exclusive, meaning that if you click one, the other will be unset. In most cases, the change is instantaneous. The Toolbar Controller itself uses this, so you can immediately see the results. 16 | 17 | If the Blizzy toolbar is NOT installed, then all buttons will be shown on the stock toolbar 18 | 19 | This intro window will be displayed every time you start the game until you click the button labeled "Hide this window" at the bottom, after which it will not be shown again 20 | 21 | -------------------------------------------------------------------------------- /GameData/001_ToolbarControl/PluginData/Textures/toolbar_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/GameData/001_ToolbarControl/PluginData/Textures/toolbar_24.png -------------------------------------------------------------------------------- /GameData/001_ToolbarControl/PluginData/Textures/toolbar_38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/GameData/001_ToolbarControl/PluginData/Textures/toolbar_38.png -------------------------------------------------------------------------------- /GameData/001_ToolbarControl/PluginData/Textures/window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/GameData/001_ToolbarControl/PluginData/Textures/window.png -------------------------------------------------------------------------------- /GameData/001_ToolbarControl/README.md: -------------------------------------------------------------------------------- 1 | # ToolbarControl 2 | 3 | An interface to control both the Blizzy Toolbar and the stock Toolbar without having to code for each one. 4 | 5 | Most important 6 | All mods using this should add the following line to the AssemblyInfo.cs file: 7 | 8 | [assembly: KSPAssemblyDependency("ToolbarController", 1, 0)] 9 | 10 | This will guarantee the load order. One benefit is that KSP will output a warning and won't load an assembly if it's dependencies aren't met (which may be better than puking out a bunch of exceptions). The only other real problem with the forced to the top of the sort list method is that technically there's a couple characters before zero ('~', '!', '@', etc.) and dlls directly in GameData come first too. Of course someone pretty much has to be trying to break things if you have to worry about this particular case. 11 | 12 | 13 | // If true, activates Blizzy toolbar, if available. Otherwise, use the stock toolbar 14 | public void UseBlizzy(bool useBlizzy) 15 | 16 | 17 | // The TC_ClickHander is a delegate used to pass in a method reference in the AddToAllToolbars methods below 18 | public delegate void TC_ClickHandler(); 19 | 20 | The method AddToAllToolbars has several definitions. All parameters are the same, the only difference is that 21 | the shorter ones don't pass in unneeded parameters 22 | 23 | // The position of the mouse the last time the button was clicked 24 | Vector2 buttonClickedMousePos 25 | 26 | // Whether this button is currently enabled (clickable) or not. 27 | // If setting, sets enabled (clickable) or not. 28 | public bool Enabled 29 | 30 | // The button's tool tip text. Set to null if no tool tip is desired. 31 | public string ToolTip 32 | 33 | Definitions 34 | =========== 35 | The onTrue parameter is unique in that it applies both to the stock toolbar and the Blizzy toolbar. 36 | onTrue Corresponds to the onTrue parameter in the AddModApplication function. This also corresponds to the 37 | blizzyButton.OnClick setting 38 | 39 | The following corresponds to the same parameter in the AddModApplication() method 40 | onFalse 41 | onHover 42 | onHoverOut 43 | onenable 44 | onDisable 45 | 46 | visibleInScenes The values are the same as stock ApplicationLauncher.AppScenes. The mod will use this to build the appropriate 47 | values for the Blizzy toolbar 48 | 49 | Icons 50 | largeToolbarIcon used for the stock toolbar 51 | smallToolbarIcon Used for the Blizzy toolbar 52 | 53 | If used, the following will be used to change the icon depending on whether it is active or not 54 | largeToolbarIconActive large is used for the stock toolbar 55 | largeToolbarIconInactive 56 | 57 | smallToolbarIconActive small is used for Blizzy toolbar 58 | smallToolbarIconInactive 59 | 60 | The following are used by the Blizzy toolbar only 61 | nameSpace Namespace of the mod 62 | toolbarId unique id for the toolbar 63 | tooltip tooltip which is shown when hovering the mouse over the button 64 | 65 | 66 | The following methods are available, more can be added if requested 67 | 68 | 69 | public void AddToAllToolbars(TC_ClickHandler onTrue, TC_ClickHandler onFalse, 70 | ApplicationLauncher.AppScenes visibleInScenes, 71 | string nameSpace, string toolbarId, 72 | string largeToolbarIcon, string smallToolbarIcon, 73 | string toolTip = "") 74 | 75 | public void AddToAllToolbars(TC_ClickHandler onTrue, TC_ClickHandler onFalse, 76 | ApplicationLauncher.AppScenes visibleInScenes, 77 | string nameSpace, string toolbarId, 78 | string largeToolbarIconActive, 79 | string largeToolbarIconInactive, 80 | string smallToolbarIconActive, 81 | string smallToolbarIconInactive, 82 | string toolTip = "") 83 | 84 | public void AddToAllToolbars(TC_ClickHandler onTrue, TC_ClickHandler onFalse, TC_ClickHandler onHover, TC_ClickHandler onHoverOut, TC_ClickHandler onEnable, TC_ClickHandler onDisable, 85 | ApplicationLauncher.AppScenes visibleInScenes, 86 | string nameSpace, string toolbarId, 87 | string largeToolbarIcon, string smallToolbarIcon, 88 | string toolTip = "") 89 | 90 | public void AddToAllToolbars(TC_ClickHandler onTrue, TC_ClickHandler onFalse, TC_ClickHandler onHover, TC_ClickHandler onHoverOut, TC_ClickHandler onEnable, TC_ClickHandler onDisable, 91 | ApplicationLauncher.AppScenes visibleInScenes, 92 | string nameSpace, string toolbarId, 93 | string largeToolbarIconActive, string largeToolbarIconInactive, string smallToolbarIconActive, string smallToolbarIconInactive, 94 | string toolTip = "") 95 | 96 | If you need to use Left and Right clicks (seperate from the onTrue and onFalse), the following is available. Not that if you have an onTrue/onFalse specified along with an onLeftClick, 97 | both will be called: 98 | 99 | public void AddLeftRightClickCallbacks(TC_ClickHandler onLeftClick, TC_ClickHandler onRightClick) 100 | 101 | If you have the toolbar selectable in a settings page, you an ensure that any time the user changes the setting 102 | the toolbar will change immediately by adding the following (example from FlightPlanner): 103 | 104 | private void OnGUI() 105 | { 106 | if (toolbarControl != null) 107 | toolbarControl.UseBlizzy(HighLogic.CurrentGame.Parameters.CustomParams().useBlizzy); 108 | } 109 | 110 | You can also add, if you like, various callbacks to monitor the settings. This is a very lightweight call, if 111 | there isn't any change, it returns immediately 112 | 113 | If you wish to manually change the button setting, you can use the following methods. If makeCall is true, then the appropriate 114 | call will be done, if there is a defined function for it 115 | 116 | public void SetTrue(bool makeCall = false) 117 | public void SetFalse(bool makeCall = false) 118 | 119 | 120 | ========================================================================================== 121 | New Features 122 | 123 | Buttons can now be displayed on both toolbars simultaneously. 124 | Button settings can now be stored by the ToolbarController itself, eliminating the need to save it in the mod settings. This is done by registering the button before or when the MainMenu is reached, see the example code below. 125 | 126 | If using registration, then no need to have any call in the OnGUI method 127 | If you do change the blizzy/stock options, then a single call to the following method will suffice: 128 | toolbarControl.UseButtons(string NameSpace); 129 | 130 | Following used to register and set which button(s) are active 131 | 132 | NameSpace Same namespace as for the AddToAllToolbars() 133 | DisplayName Name of mod in display format, used on the ToolbarControl page 134 | 135 | Method available to register the button: 136 | public static bool RegisterMod(string NameSpace, string DisplayName = "", bool useBlizzy = false, bool useStock = true, bool NoneAllowed = true) 137 | 138 | Methods to either get or set the BlizzyActive and StockActive settings: 139 | public static bool BlizzyActive(string NameSpace, bool? useBlizzy = null) 140 | public static bool StockActive(string NameSpace, bool? useStock = null) 141 | 142 | Method to set status of both buttons: 143 | public static void ButtonsActive(string NameSpace, bool? useStock, bool? useBlizzy) 144 | 145 | 146 | New method to compliment the UseBlizzy method: 147 | public void UseStock(bool useStock) 148 | 149 | 150 | The following example is from the Slingshotter mod: 151 | 152 | 153 | Sample Code 154 | 155 | Use code like the following to register the mod before or at the MainMenu: 156 | 157 | using UnityEngine; 158 | using ToolbarControl_NS; 159 | 160 | namespace KerbalSlingshotter 161 | { 162 | [KSPAddon(KSPAddon.Startup.MainMenu, true)] 163 | public class RegisterToolbar : MonoBehaviour 164 | { 165 | void Start() 166 | { 167 | ToolbarControl.RegisterMod(SlingshotCore.MODID, SlingshotCore.MODNAME); 168 | } 169 | } 170 | } 171 | 172 | And in the file where the button is added to the ToolbarController: 173 | 174 | using System; 175 | using System.Linq; 176 | using UnityEngine; 177 | using KSP.UI.Screens; 178 | 179 | using ClickThroughFix; 180 | using ToolbarControl_NS; 181 | 182 | namespace KerbalSlingshotter 183 | { 184 | [KSPAddon(KSPAddon.Startup.Flight,false)] 185 | public class SlingshotCore 186 | { 187 | internal const string MODID = "Slingshotter_NS"; 188 | internal const string MODNAME = "SlingShotter"; 189 | } 190 | 191 | private void CreateButtonIcon() 192 | { 193 | toolbarControl = gameObject.AddComponent(); 194 | toolbarControl.AddToAllToolbars(ToggleOn, ToggleOff, 195 | ApplicationLauncher.AppScenes.FLIGHT | ApplicationLauncher.AppScenes.MAPVIEW | ApplicationLauncher.AppScenes.TRACKSTATION, 196 | MODID, 197 | "slingShotterButton", 198 | "SlingShotter/PluginData/Textures/icon_38", 199 | "SlingShotter/PluginData/Textures/icon_24", 200 | MODNAME 201 | ); 202 | } 203 | } 204 | } -------------------------------------------------------------------------------- /GameData/001_ToolbarControl/ToolbarControl.version: -------------------------------------------------------------------------------- 1 | { 2 | "NAME": "ToolbarControl", 3 | "URL": "https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/refs/heads/master/ToolbarControl.version", 4 | "DOWNLOAD": "https://github.com/linuxgurugamer/ToolbarControl/releases", 5 | "GITHUB": { 6 | "USERNAME": "linuxgurugamer", 7 | "REPOSITORY": "ToolbarControl" 8 | }, 9 | "VERSION": { 10 | "MAJOR": 0, 11 | "MINOR": 1, 12 | "PATCH": 9, 13 | "BUILD": 14 14 | }, 15 | "KSP_VERSION": { 16 | "MAJOR": 1, 17 | "MINOR": 12, 18 | "PATCH": 3 19 | }, 20 | "KSP_VERSION_MIN": { 21 | "MAJOR": 1, 22 | "MINOR": 9, 23 | "PATCH": 0 24 | }, 25 | "KSP_VERSION_MAX": { 26 | "MAJOR": 1, 27 | "MINOR": 12, 28 | "PATCH": 99 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ToolbarControl 2 | 3 | An interface to control both the Blizzy Toolbar and the stock Toolbar without having to code for each one. 4 | 5 | Most important 6 | All mods using this should add the following line to the AssemblyInfo.cs file: 7 | 8 | [assembly: KSPAssemblyDependency("ToolbarController", 1, 0)] 9 | 10 | This will guarantee the load order. One benefit is that KSP will output a warning and won't load an assembly if it's dependencies aren't met (which may be better than puking out a bunch of exceptions). The only other real problem with the forced to the top of the sort list method is that technically there's a couple characters before zero ('~', '!', '@', etc.) and dlls directly in GameData come first too. Of course someone pretty much has to be trying to break things if you have to worry about this particular case. 11 | 12 | 13 | // If true, activates Blizzy toolbar, if available. Otherwise, use the stock toolbar 14 | public void UseBlizzy(bool useBlizzy) 15 | 16 | 17 | // The TC_ClickHander is a delegate used to pass in a method reference in the AddToAllToolbars methods below 18 | public delegate void TC_ClickHandler(); 19 | 20 | The method AddToAllToolbars has several definitions. All parameters are the same, the only difference is that 21 | the shorter ones don't pass in unneeded parameters 22 | 23 | // The position of the mouse the last time the button was clicked 24 | Vector2 buttonClickedMousePos 25 | 26 | // Whether this button is currently enabled (clickable) or not. 27 | // If setting, sets enabled (clickable) or not. 28 | public bool Enabled 29 | 30 | // The button's tool tip text. Set to null if no tool tip is desired. 31 | public string ToolTip 32 | 33 | Definitions 34 | =========== 35 | The onTrue parameter is unique in that it applies both to the stock toolbar and the Blizzy toolbar. 36 | onTrue Corresponds to the onTrue parameter in the AddModApplication function. This also corresponds to the 37 | blizzyButton.OnClick setting 38 | 39 | The following corresponds to the same parameter in the AddModApplication() method 40 | onFalse 41 | onHover 42 | onHoverOut 43 | onenable 44 | onDisable 45 | 46 | visibleInScenes The values are the same as stock ApplicationLauncher.AppScenes. The mod will use this to build the appropriate 47 | values for the Blizzy toolbar 48 | 49 | Icons 50 | largeToolbarIcon used for the stock toolbar 51 | smallToolbarIcon Used for the Blizzy toolbar 52 | 53 | If used, the following will be used to change the icon depending on whether it is active or not 54 | largeToolbarIconActive large is used for the stock toolbar 55 | largeToolbarIconInactive 56 | 57 | smallToolbarIconActive small is used for Blizzy toolbar 58 | smallToolbarIconInactive 59 | 60 | The following are used by the Blizzy toolbar only 61 | nameSpace Namespace of the mod 62 | toolbarId unique id for the toolbar 63 | tooltip tooltip which is shown when hovering the mouse over the button 64 | 65 | 66 | The following methods are available, more can be added if requested 67 | 68 | 69 | public void AddToAllToolbars(TC_ClickHandler onTrue, TC_ClickHandler onFalse, 70 | ApplicationLauncher.AppScenes visibleInScenes, 71 | string nameSpace, string toolbarId, 72 | string largeToolbarIcon, string smallToolbarIcon, 73 | string toolTip = "") 74 | 75 | public void AddToAllToolbars(TC_ClickHandler onTrue, TC_ClickHandler onFalse, 76 | ApplicationLauncher.AppScenes visibleInScenes, 77 | string nameSpace, string toolbarId, 78 | string largeToolbarIconActive, 79 | string largeToolbarIconInactive, 80 | string smallToolbarIconActive, 81 | string smallToolbarIconInactive, 82 | string toolTip = "") 83 | 84 | public void AddToAllToolbars(TC_ClickHandler onTrue, TC_ClickHandler onFalse, TC_ClickHandler onHover, TC_ClickHandler onHoverOut, TC_ClickHandler onEnable, TC_ClickHandler onDisable, 85 | ApplicationLauncher.AppScenes visibleInScenes, 86 | string nameSpace, string toolbarId, 87 | string largeToolbarIcon, string smallToolbarIcon, 88 | string toolTip = "") 89 | 90 | public void AddToAllToolbars(TC_ClickHandler onTrue, TC_ClickHandler onFalse, TC_ClickHandler onHover, TC_ClickHandler onHoverOut, TC_ClickHandler onEnable, TC_ClickHandler onDisable, 91 | ApplicationLauncher.AppScenes visibleInScenes, 92 | string nameSpace, string toolbarId, 93 | string largeToolbarIconActive, string largeToolbarIconInactive, string smallToolbarIconActive, string smallToolbarIconInactive, 94 | string toolTip = "") 95 | 96 | If you need to use Left and Right clicks (seperate from the onTrue and onFalse), the following is available. Not that if you have an onTrue/onFalse specified along with an onLeftClick, 97 | both will be called: 98 | 99 | public void AddLeftRightClickCallbacks(TC_ClickHandler onLeftClick, TC_ClickHandler onRightClick) 100 | 101 | If you have the toolbar selectable in a settings page, you an ensure that any time the user changes the setting 102 | the toolbar will change immediately by adding the following (example from FlightPlanner): 103 | 104 | private void OnGUI() 105 | { 106 | if (toolbarControl != null) 107 | toolbarControl.UseBlizzy(HighLogic.CurrentGame.Parameters.CustomParams().useBlizzy); 108 | } 109 | 110 | You can also add, if you like, various callbacks to monitor the settings. This is a very lightweight call, if 111 | there isn't any change, it returns immediately 112 | 113 | If you wish to manually change the button setting, you can use the following methods. If makeCall is true, then the appropriate 114 | call will be done, if there is a defined function for it 115 | 116 | public void SetTrue(bool makeCall = false) 117 | public void SetFalse(bool makeCall = false) 118 | 119 | 120 | ========================================================================================== 121 | New Features 122 | 123 | Buttons can now be displayed on both toolbars simultaneously. 124 | Button settings can now be stored by the ToolbarController itself, eliminating the need to save it in the mod settings. This is done by registering the button before or when the MainMenu is reached, see the example code below. 125 | 126 | If using registration, then no need to have any call in the OnGUI method 127 | If you do change the blizzy/stock options, then a single call to the following method will suffice: 128 | toolbarControl.UseButtons(string NameSpace); 129 | 130 | Following used to register and set which button(s) are active 131 | 132 | NameSpace Same namespace as for the AddToAllToolbars() 133 | DisplayName Name of mod in display format, used on the ToolbarControl page 134 | 135 | Method available to register the button: 136 | public static bool RegisterMod(string NameSpace, string DisplayName = "", bool useBlizzy = false, bool useStock = true, bool NoneAllowed = true) 137 | 138 | Methods to either get or set the BlizzyActive and StockActive settings: 139 | public static bool BlizzyActive(string NameSpace, bool? useBlizzy = null) 140 | public static bool StockActive(string NameSpace, bool? useStock = null) 141 | 142 | Method to set status of both buttons: 143 | public static void ButtonsActive(string NameSpace, bool? useStock, bool? useBlizzy) 144 | 145 | 146 | New method to compliment the UseBlizzy method: 147 | public void UseStock(bool useStock) 148 | 149 | 150 | The following example is from the Slingshotter mod: 151 | 152 | 153 | Sample Code 154 | 155 | Use code like the following to register the mod before or at the MainMenu: 156 | 157 | using UnityEngine; 158 | using ToolbarControl_NS; 159 | 160 | namespace KerbalSlingshotter 161 | { 162 | [KSPAddon(KSPAddon.Startup.MainMenu, true)] 163 | public class RegisterToolbar : MonoBehaviour 164 | { 165 | void Start() 166 | { 167 | ToolbarControl.RegisterMod(SlingshotCore.MODID, SlingshotCore.MODNAME); 168 | } 169 | } 170 | } 171 | 172 | And in the file where the button is added to the ToolbarController: 173 | 174 | using System; 175 | using System.Linq; 176 | using UnityEngine; 177 | using KSP.UI.Screens; 178 | 179 | using ClickThroughFix; 180 | using ToolbarControl_NS; 181 | 182 | namespace KerbalSlingshotter 183 | { 184 | [KSPAddon(KSPAddon.Startup.Flight,false)] 185 | public class SlingshotCore 186 | { 187 | internal const string MODID = "Slingshotter_NS"; 188 | internal const string MODNAME = "SlingShotter"; 189 | } 190 | 191 | private void CreateButtonIcon() 192 | { 193 | toolbarControl = gameObject.AddComponent(); 194 | toolbarControl.AddToAllToolbars(ToggleOn, ToggleOff, 195 | ApplicationLauncher.AppScenes.FLIGHT | ApplicationLauncher.AppScenes.MAPVIEW | ApplicationLauncher.AppScenes.TRACKSTATION, 196 | MODID, 197 | "slingShotterButton", 198 | "SlingShotter/PluginData/Textures/icon_38", 199 | "SlingShotter/PluginData/Textures/icon_24", 200 | MODNAME 201 | ); 202 | } 203 | } 204 | } -------------------------------------------------------------------------------- /ToolbarControl.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30517.126 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ToolbarControl", "ToolbarControl\ToolbarControl.csproj", "{B146B9F2-61CB-4E43-BF7C-8737448116AE}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F7F33464-5170-431E-A77F-91E05FB3FE23}" 9 | ProjectSection(SolutionItems) = preProject 10 | BUGS.txt = BUGS.txt 11 | buildRelease.bat = buildRelease.bat 12 | ChangeLog.txt = ChangeLog.txt 13 | deploy.bat = deploy.bat 14 | jenkins.txt = jenkins.txt 15 | LICENSE.md = LICENSE.md 16 | README.md = README.md 17 | ToolbarControl.version = ToolbarControl.version 18 | EndProjectSection 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Release|Any CPU = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {B146B9F2-61CB-4E43-BF7C-8737448116AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {B146B9F2-61CB-4E43-BF7C-8737448116AE}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {B146B9F2-61CB-4E43-BF7C-8737448116AE}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {B146B9F2-61CB-4E43-BF7C-8737448116AE}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {86BBEC6E-5881-49BC-ADE4-99C0FEBCA0D0} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /ToolbarControl.version: -------------------------------------------------------------------------------- 1 | { 2 | "NAME": "ToolbarControl", 3 | "URL": "https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/refs/heads/master/ToolbarControl.version", 4 | "DOWNLOAD": "https://github.com/linuxgurugamer/ToolbarControl/releases", 5 | "GITHUB": { 6 | "USERNAME": "linuxgurugamer", 7 | "REPOSITORY": "ToolbarControl" 8 | }, 9 | "VERSION": { 10 | "MAJOR": 0, 11 | "MINOR": 1, 12 | "PATCH": 9, 13 | "BUILD": 14 14 | }, 15 | "KSP_VERSION": { 16 | "MAJOR": 1, 17 | "MINOR": 12, 18 | "PATCH": 3 19 | }, 20 | "KSP_VERSION_MIN": { 21 | "MAJOR": 1, 22 | "MINOR": 9, 23 | "PATCH": 0 24 | }, 25 | "KSP_VERSION_MAX": { 26 | "MAJOR": 1, 27 | "MINOR": 12, 28 | "PATCH": 99 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ToolbarControl.version.1-12-3: -------------------------------------------------------------------------------- 1 | { 2 | "NAME": "ToolbarControl", 3 | "URL": "http://ksp.spacetux.net/avc/ToolbarControl", 4 | "DOWNLOAD": "https://github.com/linuxgurugamer/ToolbarControl/releases", 5 | "GITHUB": { 6 | "USERNAME": "linuxgurugamer", 7 | "REPOSITORY": "ToolbarControl" 8 | }, 9 | "VERSION": { 10 | "MAJOR": 0, 11 | "MINOR": 1, 12 | "PATCH": 9, 13 | "BUILD": 8 14 | }, 15 | "KSP_VERSION": { 16 | "MAJOR": 1, 17 | "MINOR": 12, 18 | "PATCH": 3 19 | }, 20 | "KSP_VERSION_MIN": { 21 | "MAJOR": 1, 22 | "MINOR": 9, 23 | "PATCH": 0 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ToolbarControl/AssemblyVersion.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | // This code was generated by a tool. Any changes made manually will be lost 8 | // the next time this code is regenerated. 9 | // 10 | 11 | using System.Reflection; 12 | 13 | [assembly: AssemblyVersion("0.1.9.14")] 14 | [assembly: AssemblyFileVersion("0.1.9.14")] 15 | -------------------------------------------------------------------------------- /ToolbarControl/AssemblyVersion.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="true" language="C#" #> 2 | <#@ import namespace="System.IO" #> 3 | <#@ output extension=".cs" #> 4 | 5 | <#@ assembly name="EnvDTE" #><# /* This assembly provides access to Visual Studio project properties. */ #> 6 | <# 7 | 8 | // Instructions 9 | // 1. Add a new Text Template to the project 10 | // 2. Copy this file into the new template 11 | // 3. Update the string: versionfile with the complete path to the .version file 12 | // 4. Remove the following line from the file AssemblyInfo.cs (usually located in the "Property" folder inside your C# project): 13 | // [assembly: AssemblyVersion("1.0.0.0")] 14 | // 5. Add the following to the PreBuild steps: 15 | // 16 | // set textTemplatingPath="%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\IDE\texttransform.exe" 17 | // %textTemplatingPath% "$(ProjectDir)AssemblyVersion.tt" 18 | 19 | 20 | int major = 0; 21 | int minor = 0; 22 | int build = 0; 23 | int patch = 0; 24 | bool versionSection = false; 25 | 26 | int i = 0; 27 | int i2 = 0; 28 | string s; 29 | 30 | // For Visual Studio / MSBuild Build-Time Template Resolution 31 | string RootDirectory = System.IO.Path.GetDirectoryName(Host.TemplateFile) + @"\..\"; 32 | 33 | // 34 | // Update the following with the name of the .version file which is in the root directory 35 | // 36 | string versionfile = RootDirectory + "ToolbarControl.version"; 37 | 38 | if (!File.Exists(versionfile)) 39 | { 40 | Write("File: " + versionfile + " missing\n"); 41 | } 42 | 43 | try 44 | { 45 | foreach (var line in File.ReadAllLines(versionfile)) 46 | { 47 | if (line != null) 48 | { 49 | if (!versionSection) 50 | { 51 | if (line.Contains("\"VERSION\"")) 52 | versionSection = true; 53 | } 54 | else 55 | { 56 | if (line.Contains("}")) 57 | versionSection = false; 58 | i = line.IndexOf(":"); 59 | i2 = line.IndexOf(","); 60 | if (i2 == -1) 61 | i2 = line.Length; 62 | if (i >= 0 && i2 >= 0) 63 | { 64 | s = line.Substring(i + 1, i2 - i - 1); 65 | 66 | if (line.Contains("MAJOR")) 67 | Int32.TryParse(s, out major); 68 | 69 | if (line.Contains("MINOR")) 70 | Int32.TryParse(s, out minor); 71 | 72 | if (line.Contains("PATCH")) 73 | Int32.TryParse(s, out patch); 74 | 75 | if (line.Contains("BUILD")) 76 | Int32.TryParse(s, out build); 77 | } 78 | } 79 | } 80 | } 81 | 82 | } 83 | catch 84 | { 85 | major = 1; 86 | minor = 0; 87 | patch = 0; 88 | build = 0; 89 | } 90 | //Write("File done"); 91 | 92 | #> 93 | // This code was generated by a tool. Any changes made manually will be lost 94 | // the next time this code is regenerated. 95 | // 96 | 97 | using System.Reflection; 98 | 99 | [assembly: AssemblyVersion("<#= major #>.<#= minor #>.<#= patch #>.<#= build #>")] 100 | [assembly: AssemblyFileVersion("<#= major #>.<#= minor #>.<#= patch #>.<#= build #>")] 101 | -------------------------------------------------------------------------------- /ToolbarControl/BlizzyOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using KSP.UI.Screens; 4 | using ClickThroughFix; 5 | using System.Linq; 6 | 7 | namespace ToolbarControl_NS 8 | { 9 | [KSPAddon(KSPAddon.Startup.MainMenu, true)] 10 | public class BlizzyOptions : MonoBehaviour 11 | { 12 | internal const string MODID = "ToolbarController_NS"; 13 | internal const string MODNAME = "Toolbar Controller"; 14 | 15 | GUIStyle scrollbar_style = new GUIStyle(HighLogic.Skin.scrollView); 16 | ToolbarControl toolbarControl; 17 | bool GUIEnabled = false; 18 | Rect WindowRect; 19 | int scrollBarHeight = Math.Min(500, Screen.height - 200); 20 | Vector2 scrollVector; 21 | internal static bool startupCompleted = false; 22 | bool initted = false; 23 | 24 | void Start() 25 | { 26 | startupCompleted = true; 27 | #if false 28 | if (ToolbarControl.registeredMods.Count == 1) 29 | Destroy(this); 30 | #endif 31 | scrollbar_style.padding = new RectOffset(3, 3, 3, 3); 32 | scrollbar_style.border = new RectOffset(3, 3, 3, 3); 33 | scrollbar_style.margin = new RectOffset(1, 1, 1, 1); 34 | scrollbar_style.overflow = new RectOffset(1, 1, 1, 1); 35 | 36 | AddToolbarButton(); 37 | 38 | DontDestroyOnLoad(this); 39 | } 40 | 41 | void AddToolbarButton() 42 | { 43 | 44 | toolbarControl = gameObject.AddComponent(); 45 | toolbarControl.AddToAllToolbars(ToggleGUI, ToggleGUI, 46 | ApplicationLauncher.AppScenes.SPACECENTER | ApplicationLauncher.AppScenes.FLIGHT | 47 | ApplicationLauncher.AppScenes.MAPVIEW | ApplicationLauncher.AppScenes.SPH | ApplicationLauncher.AppScenes.VAB | 48 | ApplicationLauncher.AppScenes.TRACKSTATION, 49 | MODID, 50 | "toolbarControllerButton", 51 | "001_ToolbarControl/PluginData/Textures/toolbar_38", 52 | "001_ToolbarControl/PluginData/Textures/toolbar_24", 53 | MODNAME 54 | ); 55 | } 56 | 57 | void ToggleGUI() 58 | { 59 | GUIEnabled = !GUIEnabled; 60 | } 61 | 62 | void InitGUIStuff() 63 | { 64 | // Calculate height of scrollbox 65 | GUIContent content = new GUIContent("a"); 66 | Vector2 size = GUI.skin.toggle.CalcSize(content); 67 | 68 | scrollBarHeight = Math.Min(Screen.height /4 * 3 - 150, ToolbarControl.registeredMods.Count * (9 + (int)size.y) + 150); 69 | 70 | // and calculate the window dimensions 71 | double WindowX = (Screen.width - 400) / 2; 72 | double WindowY = (Screen.height - (scrollBarHeight + 150)) / 2; 73 | 74 | WindowRect = new Rect((float)WindowX, (float)WindowY, 400, scrollBarHeight + 150); 75 | 76 | initted = true; 77 | } 78 | internal static GUIStyle windowStyle = null; 79 | void OnGUI() 80 | { 81 | if (!GUIEnabled) 82 | return; 83 | if (!initted) 84 | InitGUIStuff(); 85 | if (windowStyle == null) 86 | { 87 | GUI.color = Color.grey; 88 | windowStyle = new GUIStyle(HighLogic.Skin.window); 89 | windowStyle.active.background = windowStyle.normal.background; 90 | Texture2D tex = windowStyle.normal.background; 91 | var pixels = tex.GetPixels32(); 92 | 93 | for (int i = 0; i < pixels.Length; ++i) 94 | pixels[i].a = 255; 95 | 96 | tex.SetPixels32(pixels); tex.Apply(); 97 | windowStyle.active.background = 98 | windowStyle.focused.background = 99 | windowStyle.normal.background = tex; 100 | } 101 | WindowRect = ClickThruBlocker.GUILayoutWindow(4946386, WindowRect, DoWindow, "Toolbar Controller", windowStyle); 102 | } 103 | 104 | void OnDestroy() 105 | { 106 | toolbarControl.OnDestroy(); 107 | Destroy(toolbarControl); 108 | } 109 | 110 | void DoWindow(int id) 111 | { 112 | 113 | GUILayout.BeginHorizontal(); 114 | GUILayout.Label("For each mod, select which toolbar to put it's button on."); 115 | GUILayout.EndHorizontal(); 116 | GUILayout.BeginHorizontal(); 117 | GUILayout.Label("If the Blizzy toolbar is not installed, all buttons will be put on the stock toolbar, regardless of the setting"); 118 | GUILayout.EndHorizontal(); 119 | 120 | GUILayout.Space(10); 121 | 122 | GUILayout.BeginHorizontal(); 123 | GUILayout.Label("Stock", GUILayout.Width(50)); 124 | GUILayout.Label("Blizzy", GUILayout.Width(50)); 125 | GUILayout.Label("Both", GUILayout.Width(50)); 126 | GUILayout.Label("None", GUILayout.Width(50)); 127 | GUILayout.EndHorizontal(); 128 | GUILayout.BeginHorizontal(); 129 | 130 | //ToolbarControl.sortedModList = ToolbarControl.sortedModList.OrderBy(x => x.displayName).ToList(); 131 | 132 | 133 | scrollVector = GUILayout.BeginScrollView(scrollVector, scrollbar_style, GUILayout.Height(scrollBarHeight)); 134 | 135 | foreach (var mod in ToolbarControl.sortedModList) 136 | { 137 | bool doUseButtons = false; 138 | GUILayout.BeginHorizontal(); 139 | bool stock = GUILayout.Toggle(mod.useStock, "", GUILayout.Width(60)); 140 | if (stock != mod.useStock) 141 | { 142 | if (ToolbarControl.registeredMods[mod.modId].useStock == ToolbarControl.registeredMods[mod.modId].useBlizzy && 143 | ToolbarControl.registeredMods[mod.modId].useStock) 144 | { 145 | ToolbarControl.registeredMods[mod.modId].useBlizzy = false; 146 | } 147 | else 148 | { 149 | ToolbarControl.registeredMods[mod.modId].useStock = stock; 150 | ToolbarControl.registeredMods[mod.modId].useBlizzy = !stock; 151 | } 152 | 153 | doUseButtons = true; 154 | } 155 | 156 | bool blizzy = GUILayout.Toggle(mod.useBlizzy, "", GUILayout.Width(50)); 157 | 158 | if (blizzy != ToolbarControl.registeredMods[mod.modId].useBlizzy) 159 | { 160 | if (ToolbarControl.registeredMods[mod.modId].useStock == ToolbarControl.registeredMods[mod.modId].useBlizzy && 161 | ToolbarControl.registeredMods[mod.modId].useBlizzy) 162 | { 163 | ToolbarControl.registeredMods[mod.modId].useStock = false; 164 | } 165 | else 166 | { 167 | ToolbarControl.registeredMods[mod.modId].useBlizzy = blizzy; 168 | ToolbarControl.registeredMods[mod.modId].useStock = !blizzy; 169 | } 170 | 171 | doUseButtons = true; 172 | } 173 | 174 | bool both = (stock & blizzy); 175 | bool newboth = GUILayout.Toggle(both, "", GUILayout.Width(50)); 176 | if (newboth != both) 177 | { 178 | ToolbarControl.registeredMods[mod.modId].useBlizzy = true; 179 | ToolbarControl.registeredMods[mod.modId].useStock = true; 180 | 181 | doUseButtons = true; 182 | } 183 | if (!ToolbarControl.registeredMods[mod.modId].noneAllowed) 184 | GUI.enabled = false; 185 | bool none = (!stock & !blizzy); 186 | bool newnone = GUILayout.Toggle(none, "", GUILayout.Width(25)); 187 | if (newnone != none) 188 | { 189 | 190 | ToolbarControl.registeredMods[mod.modId].useBlizzy = false; 191 | ToolbarControl.registeredMods[mod.modId].useStock = false; 192 | 193 | doUseButtons = true; 194 | } 195 | 196 | if (doUseButtons) 197 | { 198 | ToolbarControl.SaveData(); 199 | if (ToolbarControl.registeredMods[mod.modId].modToolbarControl != null) 200 | ToolbarControl.registeredMods[mod.modId].modToolbarControl.UseButtons(mod.modId); 201 | else 202 | Log.Debug(ConfigInfo.debugMode, "mod.Key: " + mod.modId + " modToolbarControl is null"); 203 | } 204 | GUI.enabled = true; 205 | GUILayout.Label(" " + mod.displayName); 206 | GUILayout.FlexibleSpace(); 207 | GUILayout.EndHorizontal(); 208 | } 209 | GUILayout.EndScrollView(); 210 | 211 | GUILayout.EndHorizontal(); 212 | 213 | GUILayout.BeginHorizontal(); 214 | GUILayout.FlexibleSpace(); 215 | if (GUILayout.Button("Close")) 216 | { 217 | GUIEnabled = false; 218 | } 219 | GUILayout.FlexibleSpace(); 220 | if (GUILayout.Button("?")) 221 | { 222 | IntroWindowClass.showHelp = true; 223 | IntroWindowClass.automoved = 0; 224 | } 225 | GUILayout.FlexibleSpace(); 226 | GUILayout.EndHorizontal(); 227 | 228 | GUI.DragWindow(); 229 | } 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /ToolbarControl/ConfigInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using UnityEngine; 6 | using KSP.UI.Screens; 7 | using KSP.IO; 8 | 9 | namespace ToolbarControl_NS 10 | { 11 | [KSPAddon(KSPAddon.Startup.Instantly, true)] 12 | public class ConfigInfo : MonoBehaviour 13 | { 14 | public static ConfigInfo Instance; 15 | const string SETTINGSNAME = "ToolbarController"; 16 | static string PLUGINDATA; 17 | 18 | static public bool debugMode = false; 19 | 20 | private void Awake() 21 | { 22 | Instance = this; 23 | PLUGINDATA = KSPUtil.ApplicationRootPath + "GameData/001_ToolbarControl/PluginData/Debug.cfg"; 24 | DontDestroyOnLoad(this); 25 | } 26 | 27 | private void Start() 28 | { 29 | LoadData(); 30 | } 31 | 32 | public void SaveData() 33 | { 34 | ConfigNode settingsFile = new ConfigNode(); 35 | ConfigNode settings = new ConfigNode(); 36 | 37 | settingsFile.SetNode(SETTINGSNAME, settings, true); 38 | settings.AddValue("debugMode", HighLogic.CurrentGame.Parameters.CustomParams().debugMode); 39 | settingsFile.Save(PLUGINDATA); 40 | } 41 | 42 | public void LoadData() 43 | { 44 | ConfigNode settingsFile = ConfigNode.Load(PLUGINDATA); 45 | ConfigNode node = null; 46 | if (settingsFile != null) 47 | { 48 | node = settingsFile.GetNode(SETTINGSNAME); 49 | if (node != null) 50 | { 51 | if (node.HasValue("debugMode")) 52 | { 53 | debugMode = bool.Parse(node.GetValue("debugMode")); 54 | } 55 | } 56 | } 57 | 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ToolbarControl/InstallChecker.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Based on the InstallChecker from the Kethane mod for Kerbal Space Program. 3 | * https://github.com/Majiir/Kethane/blob/b93b1171ec42b4be6c44b257ad31c7efd7ea1702/Plugin/InstallChecker.cs 4 | * 5 | * Original is (C) Copyright Majiir. 6 | * CC0 Public Domain (http://creativecommons.org/publicdomain/zero/1.0/) 7 | * http://forum.kerbalspaceprogram.com/threads/65395-CompatibilityChecker-Discussion-Thread?p=899895&viewfull=1#post899895 8 | * 9 | * This file has been modified extensively and is released under the same license. 10 | */ 11 | using System; 12 | using System.IO; 13 | using System.Linq; 14 | using System.Reflection; 15 | using UnityEngine; 16 | 17 | namespace ToolbarControl_NS 18 | { 19 | [KSPAddon(KSPAddon.Startup.Instantly, true)] 20 | internal class Startup : MonoBehaviour 21 | { 22 | private void Start() 23 | { 24 | string v = "n/a"; 25 | AssemblyTitleAttribute attributes = (AssemblyTitleAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyTitleAttribute), false); 26 | string title = attributes?.Title; 27 | if (title == null) 28 | { 29 | title = "TitleNotAvailable"; 30 | } 31 | v = Assembly.GetExecutingAssembly().FullName; 32 | if (v == null) 33 | { 34 | v = "VersionNotAvailable"; 35 | } 36 | Debug.Log("[" + title + "] Version " + v); 37 | } 38 | } 39 | 40 | [KSPAddon(KSPAddon.Startup.MainMenu, true)] 41 | internal class InstallChecker : MonoBehaviour 42 | { 43 | internal const string MODNAME = "Toolbar Controller"; 44 | internal const string FOLDERNAME = "001_ToolbarControl"; 45 | internal const string EXPECTEDPATH = FOLDERNAME + "/Plugins"; 46 | 47 | protected void Start() 48 | { 49 | // Search for this mod's DLL existing in the wrong location. This will also detect duplicate copies because only one can be in the right place. 50 | var assemblies = AssemblyLoader.loadedAssemblies.Where(a => a.assembly.GetName().Name == Assembly.GetExecutingAssembly().GetName().Name).Where(a => a.url != EXPECTEDPATH); 51 | if (assemblies.Any()) 52 | { 53 | var badPaths = assemblies.Select(a => a.path).Select(p => Uri.UnescapeDataString(new Uri(Path.GetFullPath(KSPUtil.ApplicationRootPath)).MakeRelativeUri(new Uri(p)).ToString().Replace('/', Path.DirectorySeparatorChar))); 54 | PopupDialog.SpawnPopupDialog 55 | ( 56 | new Vector2(0.5f, 0.5f), 57 | new Vector2(0.5f, 0.5f), 58 | "test", 59 | "Incorrect " + MODNAME + " Installation", 60 | MODNAME + " has been installed incorrectly and will not function properly. All files should be located in KSP/GameData/" + FOLDERNAME + ". Do not move any files from inside that folder.\n\nIncorrect path(s):\n" + String.Join("\n", badPaths.ToArray()), 61 | "OK", 62 | false, 63 | HighLogic.UISkin 64 | ); 65 | Debug.Log("Incorrect " + MODNAME + " Installation: " + MODNAME + " has been installed incorrectly and will not function properly. All files should be located in KSP/GameData/" + EXPECTEDPATH + ". Do not move any files from inside that folder.\n\nIncorrect path(s):\n" + String.Join("\n", badPaths.ToArray()) 66 | 67 | ); 68 | 69 | } 70 | 71 | //// Check for Module Manager 72 | //if (!AssemblyLoader.loadedAssemblies.Any(a => a.assembly.GetName().Name.StartsWith("ModuleManager") && a.url == "")) 73 | //{ 74 | // PopupDialog.SpawnPopupDialog("Missing Module Manager", 75 | // modName + " requires the Module Manager mod in order to function properly.\n\nPlease download from http://forum.kerbalspaceprogram.com/threads/55219 and copy to the KSP/GameData/ directory.", 76 | // "OK", false, HighLogic.Skin); 77 | //} 78 | 79 | CleanupOldVersions(); 80 | } 81 | 82 | /* 83 | * Tries to fix the install if it was installed over the top of a previous version 84 | */ 85 | void CleanupOldVersions() 86 | { 87 | try 88 | { 89 | } 90 | catch (Exception ex) 91 | { 92 | Debug.LogError("-ERROR- " + this.GetType().FullName + "[" + this.GetInstanceID().ToString("X") + "][" + Time.time.ToString("0.00") + "]: " + 93 | "Exception caught while cleaning up old files.\n" + ex.Message + "\n" + ex.StackTrace); 94 | 95 | } 96 | } 97 | } 98 | } 99 | 100 | -------------------------------------------------------------------------------- /ToolbarControl/IntroWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using System.Collections.Generic; 5 | using UnityEngine; 6 | using ClickThroughFix; 7 | 8 | namespace ToolbarControl_NS 9 | { 10 | [KSPAddon(KSPAddon.Startup.SpaceCentre, true)] 11 | public class IntroWindowClass : MonoBehaviour 12 | { 13 | internal static bool showHelp = false; 14 | internal static bool showIntroAtStartup = true; 15 | internal static GUIStyle windowStyle = null; 16 | 17 | Rect introWindow; 18 | int introWindowId; 19 | int MAIN_WIDTH = Screen.height * 3 / 4; 20 | int MAIN_HEIGHT = 400; 21 | internal static int automoved = 0; 22 | 23 | GUIStyle areaStyle; 24 | 25 | private void Awake() 26 | { 27 | introWindowId = GUIUtility.GetControlID(FocusType.Passive); 28 | DontDestroyOnLoad(this); 29 | } 30 | 31 | private void Start() 32 | { 33 | #if false 34 | if (ToolbarControl.registeredMods.Count == 1) 35 | Destroy(this); 36 | #endif 37 | 38 | MAIN_WIDTH = Screen.width / 2; 39 | MAIN_HEIGHT = Screen.height * 3 / 4; 40 | 41 | introWindow = new Rect((Screen.width - MAIN_WIDTH) / 2, (Screen.height - MAIN_HEIGHT) / 2, MAIN_WIDTH, MAIN_HEIGHT); 42 | areaStyle = new GUIStyle(HighLogic.Skin.textArea); 43 | areaStyle.richText = true; 44 | ToolbarControl.LoadData(); 45 | showHelp = showIntroAtStartup; 46 | } 47 | 48 | public void OnGUI() 49 | { 50 | if (windowStyle == null) 51 | { 52 | GUI.color = Color.grey; 53 | windowStyle = new GUIStyle(HighLogic.Skin.window); 54 | windowStyle.active.background = windowStyle.normal.background; 55 | Texture2D tex = windowStyle.normal.background; 56 | var pixels = tex.GetPixels32(); 57 | 58 | for (int i = 0; i < pixels.Length; ++i) 59 | pixels[i].a = 255; 60 | 61 | tex.SetPixels32(pixels); tex.Apply(); 62 | windowStyle.active.background = 63 | windowStyle.focused.background = 64 | windowStyle.normal.background = tex; 65 | } 66 | 67 | if (!showHelp) 68 | return; 69 | introWindow = ClickThruBlocker.GUILayoutWindow(introWindowId, introWindow, IntroWindow, "Toolbar Controller Intro", windowStyle); 70 | if (automoved < 2) 71 | { 72 | introWindow.x = (Screen.width - introWindow.width) / 2; 73 | introWindow.y = (Screen.height - introWindow.height) / 2; 74 | 75 | automoved++; 76 | } 77 | } 78 | 79 | const string IntroPath = "001_ToolbarControl/PluginData/Intro.txt"; 80 | 81 | 82 | private bool Load(string fileName) 83 | { 84 | Log.Debug(ConfigInfo.debugMode, "Load, fileName: " + fileName); 85 | // Handle any problems that might arise when reading the text 86 | try 87 | { 88 | string line; 89 | // Create a new StreamReader, tell it which file to read and what encoding the file 90 | // was saved as 91 | StreamReader theReader = new StreamReader(fileName, Encoding.Default); 92 | // Immediately clean up the reader after this block of code is done. 93 | // You generally use the "using" statement for potentially memory-intensive objects 94 | // instead of relying on garbage collection. 95 | // (Do not confuse this with the using directive for namespace at the 96 | // beginning of a class!) 97 | using (theReader) 98 | { 99 | line = theReader.ReadLine(); 100 | if (line != null) 101 | { 102 | // While there's lines left in the text file, do this: 103 | do 104 | { 105 | ProcessLine(line); 106 | line = theReader.ReadLine(); 107 | } 108 | while (line != null); 109 | } 110 | // Done reading, close the reader and return true to broadcast success 111 | theReader.Close(); 112 | return true; 113 | } 114 | 115 | } 116 | // If anything broke in the try block, we throw an exception with information 117 | // on what didn't work 118 | catch (Exception e) 119 | { 120 | Log.Error("Load error: " + e.Message); 121 | return false; 122 | } 123 | } 124 | 125 | 126 | List lines = new List(); 127 | List images = new List(); 128 | bool loaded = false; 129 | void ProcessLine(string line) 130 | { 131 | if (line.Length >= 7 && line.Substring(0, 7) == "= 7 && line.Substring(0, 7) == " 0) 164 | { 165 | GUILayout.BeginHorizontal(); 166 | GUILayout.Label(l); 167 | GUILayout.EndHorizontal(); 168 | l = ""; 169 | } 170 | if (imgcnt <= images.Count) 171 | { 172 | GUILayout.BeginHorizontal(); 173 | GUILayout.FlexibleSpace(); 174 | GUILayout.Box(images[imgcnt], GUILayout.Width(images[imgcnt].width + 10), GUILayout.Height(images[imgcnt].height + 10)); 175 | GUILayout.FlexibleSpace(); 176 | imgcnt++; 177 | GUILayout.EndHorizontal(); 178 | } 179 | } 180 | else 181 | { 182 | if (l == "") 183 | l = line; 184 | else 185 | l += "\n" + line; 186 | } 187 | } 188 | if (l.Length > 0) 189 | { 190 | GUILayout.BeginHorizontal(); 191 | GUILayout.Label(l); 192 | GUILayout.EndHorizontal(); 193 | l = ""; 194 | } 195 | } 196 | 197 | void IntroWindow(int id) 198 | { 199 | LoadAndDisplay(KSPUtil.ApplicationRootPath + "GameData/" + IntroPath); 200 | 201 | 202 | GUILayout.FlexibleSpace(); 203 | GUILayout.BeginHorizontal(); 204 | GUILayout.FlexibleSpace(); 205 | if (GUILayout.Button("OK", GUILayout.Width(120))) 206 | { 207 | showHelp = false; 208 | } 209 | GUILayout.FlexibleSpace(); 210 | if (GUILayout.Button("Hide this window at startup")) 211 | { 212 | showHelp = false; 213 | showIntroAtStartup = false; 214 | ToolbarControl.SaveData(); 215 | } 216 | GUILayout.EndHorizontal(); 217 | GUI.DragWindow(); 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /ToolbarControl/Log.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Diagnostics; 4 | 5 | namespace ToolbarControl_NS 6 | { 7 | internal static class Log 8 | { 9 | public enum LEVEL 10 | { 11 | OFF = 0, 12 | ERROR = 1, 13 | WARNING = 2, 14 | INFO = 3, 15 | DETAIL = 4, 16 | TRACE = 5 17 | }; 18 | 19 | public static LEVEL level = LEVEL.INFO; 20 | 21 | private static readonly String PREFIX = "ToolbarControl" + ": "; 22 | 23 | public static LEVEL GetLevel() 24 | { 25 | return level; 26 | } 27 | 28 | public static void SetLevel(LEVEL level) 29 | { 30 | UnityEngine.Debug.Log("log level " + level); 31 | Log.level = level; 32 | } 33 | 34 | public static LEVEL GetLogLevel() 35 | { 36 | return level; 37 | } 38 | 39 | private static bool IsLevel(LEVEL level) 40 | { 41 | return level == Log.level; 42 | } 43 | 44 | public static bool IsLogable(LEVEL level) 45 | { 46 | return level <= Log.level; 47 | } 48 | 49 | public static void Trace(String msg) 50 | { 51 | if (IsLogable(LEVEL.TRACE)) 52 | { 53 | UnityEngine.Debug.Log(PREFIX + msg); 54 | } 55 | } 56 | 57 | public static void Detail(String msg) 58 | { 59 | if (IsLogable(LEVEL.DETAIL)) 60 | { 61 | UnityEngine.Debug.Log(PREFIX + msg); 62 | } 63 | } 64 | 65 | [ConditionalAttribute("DEBUG")] 66 | public static void Info(String msg) 67 | { 68 | if (IsLogable(LEVEL.INFO)) 69 | { 70 | UnityEngine.Debug.Log(PREFIX + msg); 71 | } 72 | } 73 | 74 | [ConditionalAttribute("DEBUG")] 75 | public static void Test(String msg) 76 | { 77 | //if (IsLogable(LEVEL.INFO)) 78 | { 79 | UnityEngine.Debug.LogWarning(PREFIX + "TEST:" + msg); 80 | } 81 | } 82 | 83 | public static void Warning(String msg) 84 | { 85 | if (IsLogable(LEVEL.WARNING)) 86 | { 87 | UnityEngine.Debug.LogWarning(PREFIX + msg); 88 | } 89 | } 90 | 91 | public static void Error(String msg) 92 | { 93 | if (IsLogable(LEVEL.ERROR)) 94 | { 95 | UnityEngine.Debug.LogError(PREFIX + msg); 96 | } 97 | } 98 | 99 | public static void Debug(bool debugMode, String msg) 100 | { 101 | if (debugMode) 102 | { 103 | UnityEngine.Debug.LogError(PREFIX + msg); 104 | } 105 | else 106 | Log.Info(msg); 107 | } 108 | 109 | public static void Exception(Exception e) 110 | { 111 | Log.Error("exception caught: " + e.GetType() + ": " + e.Message); 112 | } 113 | 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /ToolbarControl/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ToolbarControl")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ToolbarControl")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b146b9f2-61cb-4e43-bf7c-8737448116ae")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | //[assembly: AssemblyVersion("1.0.0.0")] 36 | //[assembly: AssemblyFileVersion("1.0.0.0")] 37 | 38 | [assembly: KSPAssembly("ToolbarController", 1, 0, 1)] 39 | [assembly: KSPAssemblyDependency("ClickThroughBlocker", 1, 0)] 40 | -------------------------------------------------------------------------------- /ToolbarControl/RegisterToolbar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using KSP.UI.Screens; 4 | using ClickThroughFix; 5 | using System.Linq; 6 | 7 | namespace ToolbarControl_NS 8 | { 9 | [KSPAddon(KSPAddon.Startup.Instantly, true)] 10 | public class RegisterToolbarBlizzyOptions : MonoBehaviour 11 | { 12 | 13 | void Start() 14 | { 15 | ToolbarControl.RegisterMod(BlizzyOptions.MODID, BlizzyOptions.MODNAME, false, true, false); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /ToolbarControl/RegisterUsage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.IO; 6 | using KSP.UI.Screens; 7 | 8 | namespace ToolbarControl_NS 9 | { 10 | public partial class ToolbarControl 11 | { 12 | internal class Mod 13 | { 14 | public string modId; 15 | public string displayName; 16 | public bool useBlizzy; 17 | public bool useStock; 18 | public bool noneAllowed = true; 19 | public ToolbarControl modToolbarControl; 20 | public bool registered = false; 21 | 22 | public Mod(string ModId, string DisplayName, bool UseBlizzy, bool UseStock, bool NoneAllowed = true) 23 | { 24 | modId = ModId; 25 | displayName = DisplayName; 26 | useBlizzy = UseBlizzy; 27 | useStock = UseStock; 28 | 29 | noneAllowed = NoneAllowed; 30 | } 31 | } 32 | 33 | //internal static SortedDictionary registeredMods = new SortedDictionary(); 34 | 35 | internal static Dictionary registeredMods = new Dictionary(); 36 | internal static List sortedModList = new List(); 37 | 38 | //internal static List registeredMods = new List(); 39 | 40 | static string ConfigFile; 41 | const string TOOLBARCONTROL = "ToolbarControl"; 42 | const string TOOLBARCONTROLDATA = "ToolbarControlData"; 43 | const string DATA = "DATA"; 44 | 45 | static bool initted = false; 46 | 47 | private void Awake() 48 | { 49 | SetConfigFilePath(); 50 | } 51 | 52 | private static void SetConfigFilePath() 53 | { 54 | ConfigFile = KSPUtil.ApplicationRootPath + "GameData/001_ToolbarControl/PluginData/ToolbarControl.cfg"; 55 | } 56 | 57 | internal static void SaveData() 58 | { 59 | if (ConfigFile == null) 60 | SetConfigFilePath(); 61 | 62 | ConfigNode node = new ConfigNode(TOOLBARCONTROL); 63 | ConfigNode data = new ConfigNode(TOOLBARCONTROLDATA); 64 | data.AddValue("showWindowAtStartup", IntroWindowClass.showIntroAtStartup); 65 | foreach (var s in registeredMods) 66 | { 67 | ConfigNode nodeData = new ConfigNode(); 68 | nodeData.AddValue("name", s.Key); 69 | nodeData.AddValue("displayName", s.Value.displayName); 70 | nodeData.AddValue("useBlizzy", s.Value.useBlizzy); 71 | nodeData.AddValue("useStock", s.Value.useStock); 72 | nodeData.AddValue("noneAllowed", s.Value.noneAllowed); 73 | data.AddNode(DATA, nodeData); 74 | } 75 | node.AddNode(data); 76 | node.Save(ConfigFile); 77 | } 78 | 79 | static bool ToBool(string aText) 80 | { 81 | if (aText == null) 82 | return false; 83 | return aText.ToLower() == "true" || aText.ToLower() == "on" || aText.ToLower() == "yes"; 84 | } 85 | 86 | internal static void LoadData() 87 | { 88 | if (initted) 89 | return; 90 | 91 | if (ConfigFile == null) 92 | SetConfigFilePath(); 93 | 94 | if (File.Exists(ConfigFile)) 95 | { 96 | ConfigNode tempNode = ConfigNode.Load(ConfigFile); 97 | ConfigNode data = tempNode.GetNode(TOOLBARCONTROLDATA); 98 | initted = true; 99 | 100 | registeredMods.Clear(); 101 | if (data.HasValue("showWindowAtStartup")) 102 | { 103 | IntroWindowClass.showIntroAtStartup = ToBool(data.GetValue("showWindowAtStartup")); 104 | } 105 | 106 | foreach (var node in data.GetNodes()) 107 | { 108 | if (node.HasValue("name") && node.HasValue("useBlizzy")) 109 | { 110 | string modName = node.GetValue("name"); 111 | string displayName = modName; 112 | try 113 | { 114 | displayName = node.GetValue("displayName"); 115 | if (displayName == "") 116 | displayName = modName; 117 | } 118 | catch { } 119 | bool useBlizzy = ToBool(node.GetValue("useBlizzy")); 120 | bool useStock = true; 121 | if (node.HasValue("useStock")) 122 | useStock = ToBool(node.GetValue("useStock")); 123 | 124 | bool noneAllowed = true; 125 | if (node.HasValue("noneAllowed")) 126 | noneAllowed = ToBool(node.GetValue("noneAllowed")); 127 | 128 | Mod mod = new Mod(modName, displayName, useBlizzy, useStock, noneAllowed); 129 | registeredMods.Add(modName, mod); 130 | // sortedModList.Add(mod); 131 | } 132 | //sortedModList.Sort((x, y) => x.displayName.CompareTo(y.displayName)); 133 | } 134 | } 135 | } 136 | 137 | public static bool RegisterMod(string NameSpace, string DisplayName = "", bool useBlizzy = false, bool useStock = true, bool NoneAllowed = true) 138 | { 139 | if (BlizzyOptions.startupCompleted && ConfigInfo.debugMode) 140 | { 141 | Log.Error("WARNING: RegisterMod, LoadedScene: " + HighLogic.LoadedScene + ", called too late for: " + NameSpace + ", " + DisplayName + ", button may not be registered properly"); 142 | } 143 | LoadData(); 144 | Mod mod = null; 145 | //Log.Info("RegisterMod, NameSpace: " + NameSpace + ", DisplayName: " + DisplayName); 146 | if (registeredMods.ContainsKey(NameSpace)) 147 | { 148 | //Log.Info("RegisterMod, found, NameSpace: " + NameSpace + ", DisplayName: " + DisplayName); 149 | if (DisplayName != "") 150 | registeredMods[NameSpace].displayName = DisplayName; 151 | 152 | registeredMods[NameSpace].noneAllowed = NoneAllowed; 153 | registeredMods[NameSpace].registered = true; 154 | mod = registeredMods[NameSpace]; 155 | SaveData(); 156 | 157 | } 158 | else 159 | try 160 | { 161 | if (DisplayName == "") 162 | DisplayName = NameSpace; 163 | //Log.Info("RegisterMod, NameSpace: " + NameSpace + ", DisplayName: " + DisplayName); 164 | mod = new Mod(NameSpace, DisplayName, useBlizzy, useStock, NoneAllowed); 165 | registeredMods.Add(NameSpace, mod); 166 | 167 | SaveData(); 168 | 169 | } 170 | catch { return false; } 171 | if (mod != null) 172 | { 173 | sortedModList.Add(mod); 174 | 175 | sortedModList.Sort((x, y) => x.displayName.CompareTo(y.displayName)); 176 | 177 | return true; 178 | } 179 | // Should never get here 180 | Log.Error("Impossible Error"); 181 | return false; 182 | } 183 | 184 | 185 | public static bool BlizzyActive(string NameSpace, bool? useBlizzy = null) 186 | { 187 | LoadData(); 188 | 189 | if (useBlizzy == null) 190 | { 191 | 192 | if (registeredMods.ContainsKey(NameSpace)) 193 | { 194 | return registeredMods[NameSpace].useBlizzy; 195 | } 196 | else return false; 197 | } 198 | 199 | registeredMods[NameSpace].useBlizzy = (bool)useBlizzy; 200 | SaveData(); 201 | return (bool)useBlizzy; 202 | } 203 | 204 | public static bool StockActive(string NameSpace, bool? useStock = null) 205 | { 206 | LoadData(); 207 | if (useStock == null) 208 | { 209 | if (registeredMods.ContainsKey(NameSpace)) 210 | { 211 | return registeredMods[NameSpace].useStock; 212 | } 213 | else return false; 214 | } 215 | 216 | registeredMods[NameSpace].useStock = (bool)useStock; 217 | SaveData(); 218 | return (bool)useStock; 219 | } 220 | 221 | public static void ButtonsActive(string NameSpace, bool? useStock, bool? useBlizzy) 222 | { 223 | LoadData(); 224 | 225 | registeredMods[NameSpace].useStock = (bool)useStock; 226 | registeredMods[NameSpace].useBlizzy = (bool)useBlizzy; 227 | SaveData(); 228 | } 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /ToolbarControl/Resources/btnBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/ToolbarControl/Resources/btnBackground.png -------------------------------------------------------------------------------- /ToolbarControl/Resources/btnClose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/ToolbarControl/Resources/btnClose.png -------------------------------------------------------------------------------- /ToolbarControl/Resources/btnDelete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/ToolbarControl/Resources/btnDelete.png -------------------------------------------------------------------------------- /ToolbarControl/Resources/btnExpand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/ToolbarControl/Resources/btnExpand.png -------------------------------------------------------------------------------- /ToolbarControl/Resources/btnLock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/ToolbarControl/Resources/btnLock.png -------------------------------------------------------------------------------- /ToolbarControl/Resources/btnOpen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/ToolbarControl/Resources/btnOpen.png -------------------------------------------------------------------------------- /ToolbarControl/Resources/btnRename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/ToolbarControl/Resources/btnRename.png -------------------------------------------------------------------------------- /ToolbarControl/Resources/btnSave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/ToolbarControl/Resources/btnSave.png -------------------------------------------------------------------------------- /ToolbarControl/Resources/btnUnlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/ToolbarControl/Resources/btnUnlock.png -------------------------------------------------------------------------------- /ToolbarControl/Resources/flask-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/ToolbarControl/Resources/flask-38.png -------------------------------------------------------------------------------- /ToolbarControl/Resources/flask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/ToolbarControl/Resources/flask.png -------------------------------------------------------------------------------- /ToolbarControl/Resources/sheet-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/ToolbarControl/Resources/sheet-38.png -------------------------------------------------------------------------------- /ToolbarControl/Resources/sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ToolbarControl/5a7e5d4b3fea19ae9060c9f6e195ed5670165ffb/ToolbarControl/Resources/sheet.png -------------------------------------------------------------------------------- /ToolbarControl/Settings.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | using System.IO; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Text; 9 | using UnityEngine; 10 | 11 | 12 | namespace ToolbarControl_NS 13 | { 14 | public class TC : GameParameters.CustomParameterNode 15 | { 16 | public override string Title { get { return ""; } } 17 | public override GameParameters.GameMode GameMode { get { return GameParameters.GameMode.ANY; } } 18 | public override string Section { get { return "Toolbar Control"; } } 19 | public override string DisplaySection { get { return "Toolbar Control"; } } 20 | public override int SectionOrder { get { return 1; } } 21 | public override bool HasPresets { get { return false; } } 22 | 23 | 24 | [GameParameters.CustomParameterUI("Show tooltips for stock & Blizzy toolbar", 25 | toolTip ="Blzzy tooltip setting may need to restart SKP")] 26 | public bool showStockTooltips = true; 27 | 28 | [GameParameters.CustomFloatParameterUI("Tooltip timeout", minValue = 0.5f, maxValue = 5.0f, asPercentage = false, displayFormat = "0.0", 29 | toolTip = "Time tooltip stays around")] 30 | public float hoverTimeout = 0.5f; 31 | 32 | [GameParameters.CustomParameterUI("Allow the Toolbar Control button to be hidden", 33 | toolTip = "When hidden, you can't change anything")] 34 | public bool allowAllToolbarButtonsHidden = false; 35 | 36 | 37 | [GameParameters.CustomParameterUI("Debug mode", 38 | toolTip = "Writes extra data to the log file")] 39 | public bool debugMode = false; 40 | 41 | public bool oldDebugMode = false; 42 | bool loaded = false; 43 | 44 | 45 | public override void SetDifficultyPreset(GameParameters.Preset preset) 46 | { 47 | } 48 | 49 | public override bool Enabled(MemberInfo member, GameParameters parameters) 50 | { 51 | if (oldDebugMode != debugMode) 52 | { 53 | ConfigInfo.Instance.SaveData(); 54 | oldDebugMode = debugMode; 55 | } 56 | return true; 57 | } 58 | 59 | public override bool Interactible(MemberInfo member, GameParameters parameters) 60 | { 61 | if (!loaded) 62 | { 63 | ConfigInfo.Instance.LoadData(); 64 | debugMode = ConfigInfo.debugMode; 65 | oldDebugMode = debugMode; 66 | loaded = true; 67 | } 68 | return true; 69 | } 70 | 71 | public override IList ValidValues(MemberInfo member) 72 | { 73 | return null; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ToolbarControl/ToolbarControl.cs: -------------------------------------------------------------------------------- 1 | using DDSHeaders; 2 | using KSP.UI; 3 | using KSP.UI.Screens; 4 | using System; 5 | using System.Collections.Generic; 6 | using UnityEngine; 7 | 8 | namespace ToolbarControl_NS 9 | { 10 | /// 11 | /// Determines visibility of a button in relation to the currently running game scene. 12 | /// 13 | /// 14 | /// 15 | /// IButton button = ... 16 | /// button.Visibility = new GameScenesVisibility(GameScenes.EDITOR, GameScenes.FLIGHT); 17 | /// 18 | /// 19 | /// 20 | public class TC_GameScenesVisibility : IVisibility 21 | { 22 | public bool Visible 23 | { 24 | get 25 | { 26 | return (HighLogic.LoadedScene == GameScenes.FLIGHT && !MapView.MapIsEnabled && 27 | (visibleInScenes & ApplicationLauncher.AppScenes.FLIGHT) != ApplicationLauncher.AppScenes.NEVER) || 28 | 29 | (HighLogic.LoadedScene == GameScenes.FLIGHT && MapView.MapIsEnabled && 30 | (visibleInScenes & ApplicationLauncher.AppScenes.MAPVIEW) != ApplicationLauncher.AppScenes.NEVER) || 31 | 32 | (HighLogic.LoadedScene == GameScenes.SPACECENTER && 33 | (visibleInScenes & ApplicationLauncher.AppScenes.SPACECENTER) != ApplicationLauncher.AppScenes.NEVER) || 34 | 35 | (HighLogic.LoadedScene == GameScenes.EDITOR && 36 | (visibleInScenes & (ApplicationLauncher.AppScenes.VAB | ApplicationLauncher.AppScenes.SPH)) != ApplicationLauncher.AppScenes.NEVER) || 37 | 38 | (HighLogic.LoadedScene == GameScenes.TRACKSTATION && (visibleInScenes & ApplicationLauncher.AppScenes.TRACKSTATION) != ApplicationLauncher.AppScenes.NEVER) || 39 | (HighLogic.LoadedScene == GameScenes.MAINMENU && (visibleInScenes & ApplicationLauncher.AppScenes.MAINMENU) != ApplicationLauncher.AppScenes.NEVER); 40 | } 41 | } 42 | 43 | ApplicationLauncher.AppScenes visibleInScenes; 44 | 45 | public TC_GameScenesVisibility(ApplicationLauncher.AppScenes visibleInScenes) 46 | { 47 | this.visibleInScenes = visibleInScenes; 48 | } 49 | } 50 | 51 | public partial class ToolbarControl : MonoBehaviour 52 | { 53 | private static List tcList = null; 54 | private string nameSpace = ""; 55 | private string toolbarId = ""; 56 | // private GameScenes[] gameScenes; 57 | 58 | private string BlizzyToolbarIconActive = ""; 59 | private string BlizzyToolbarIconInactive = ""; 60 | private string StockToolbarIconActive = ""; 61 | private string StockToolbarIconInactive = ""; 62 | 63 | private ApplicationLauncher.AppScenes visibleInScenes; 64 | private string toolTip = null; 65 | 66 | //private bool spaceCenterVisited = false; 67 | /// 68 | /// The button's tool tip text. Set to null if no tool tip is desired. 69 | /// 70 | /// 71 | /// Tool Tip Text Should Always Use Headline Style Like This. 72 | /// 73 | public string ToolTip 74 | { 75 | set { toolTip = value; } 76 | get { return toolTip; } 77 | } 78 | 79 | public Vector2 buttonClickedMousePos 80 | { 81 | get; 82 | private set; 83 | } 84 | 85 | 86 | public delegate void TC_ClickHandler(); 87 | 88 | /// 89 | /// Sets flag to use either use or not use the Blizzy toolbar 90 | /// 91 | /// 92 | public void UseBlizzy(bool useBlizzy) 93 | { 94 | 95 | if (ToolbarManager.ToolbarAvailable && useBlizzy) 96 | { 97 | if (!blizzyActive) 98 | { 99 | blizzyActive = true; 100 | stockActive = false; 101 | SetBlizzySettings(); 102 | } 103 | } 104 | else 105 | { 106 | if (!stockActive) 107 | { 108 | stockActive = true; 109 | blizzyActive = false; 110 | SetStockSettings(); 111 | } 112 | } 113 | } 114 | 115 | /// 116 | /// Sets flag to use either use or not use the Blizzy toolbar 117 | /// 118 | /// 119 | public void UseStock(bool useStock) 120 | { 121 | 122 | if (/* !ToolbarManager.ToolbarAvailable || */ useStock) 123 | { 124 | if (!stockActive) 125 | { 126 | stockActive = true; 127 | blizzyActive = false; 128 | SetStockSettings(); 129 | } 130 | } 131 | else 132 | { 133 | if (!blizzyActive) 134 | { 135 | blizzyActive = true; 136 | stockActive = false; 137 | SetBlizzySettings(); 138 | } 139 | } 140 | } 141 | 142 | public void UseButtons(string NameSpace) 143 | { 144 | 145 | bool s = registeredMods[NameSpace].modToolbarControl.stockActive; 146 | bool b = registeredMods[NameSpace].modToolbarControl.blizzyActive; 147 | 148 | registeredMods[NameSpace].modToolbarControl.stockActive = registeredMods[NameSpace].useStock; 149 | registeredMods[NameSpace].modToolbarControl.blizzyActive = true; 150 | 151 | 152 | if (registeredMods[NameSpace].modToolbarControl.stockActive != s) 153 | registeredMods[NameSpace].modToolbarControl.SetStockSettings(); 154 | 155 | registeredMods[NameSpace].modToolbarControl.blizzyActive = registeredMods[NameSpace].useBlizzy; 156 | 157 | if (registeredMods[NameSpace].modToolbarControl.blizzyActive != b) 158 | registeredMods[NameSpace].modToolbarControl.SetBlizzySettings(); 159 | 160 | registeredMods[NameSpace].modToolbarControl.UpdateToolbarIcon(); 161 | } 162 | 163 | /// 164 | /// Whether this button is currently enabled (clickable) or not. This does not affect the player's ability to 165 | /// position the button on their toolbar. 166 | /// 167 | public bool Enabled 168 | { 169 | set { SetIsEnabled(value); } 170 | get { return isEnabled; } 171 | } 172 | 173 | private bool isEnabled = true; 174 | private void SetIsEnabled(bool b) 175 | { 176 | isEnabled = b; 177 | if (stockActive) 178 | { 179 | if (this.stockButton == null) 180 | return; 181 | if (b) 182 | this.stockButton.Enable(); 183 | else 184 | this.stockButton.Disable(); 185 | } 186 | if (ToolbarManager.ToolbarAvailable && blizzyActive) 187 | { 188 | if (blizzyButton == null) 189 | return; 190 | this.blizzyButton.Enabled = b; 191 | } 192 | } 193 | 194 | /// 195 | /// Only pass in the onTrue and onFalse 196 | /// 197 | /// 198 | /// 199 | /// 200 | /// 201 | /// 202 | /// 203 | /// 204 | public void AddToAllToolbars(TC_ClickHandler onTrue, TC_ClickHandler onFalse, 205 | ApplicationLauncher.AppScenes visibleInScenes, string nameSpace, string toolbarId, 206 | string largeToolbarIcon, 207 | string smallToolbarIcon, 208 | string toolTip = null) 209 | { 210 | AddToAllToolbars(onTrue, onFalse, null, null, null, null, 211 | visibleInScenes, nameSpace, toolbarId, largeToolbarIcon, largeToolbarIcon, smallToolbarIcon, smallToolbarIcon, toolTip); 212 | } 213 | 214 | public void AddToAllToolbars(TC_ClickHandler onTrue, TC_ClickHandler onFalse, 215 | ApplicationLauncher.AppScenes visibleInScenes, string nameSpace, string toolbarId, 216 | string largeToolbarIconActive, 217 | string largeToolbarIconInactive, 218 | string smallToolbarIconActive, 219 | string smallToolbarIconInactive, string toolTip = null) 220 | { 221 | AddToAllToolbars(onTrue, onFalse, null, null, null, null, 222 | visibleInScenes, nameSpace, toolbarId, largeToolbarIconActive, largeToolbarIconInactive, smallToolbarIconActive, smallToolbarIconInactive, toolTip); 223 | } 224 | /// 225 | /// Pass in all the callbacks 226 | /// 227 | /// 228 | /// 229 | /// 230 | /// 231 | /// 232 | /// 233 | /// 234 | /// 235 | /// 236 | /// 237 | /// 238 | public void AddToAllToolbars(TC_ClickHandler onTrue, TC_ClickHandler onFalse, TC_ClickHandler onHover, TC_ClickHandler onHoverOut, TC_ClickHandler onEnable, TC_ClickHandler onDisable, 239 | ApplicationLauncher.AppScenes visibleInScenes, string nameSpace, string toolbarId, string largeToolbarIcon, string smallToolbarIcon, string toolTip = "" 240 | ) 241 | { 242 | AddToAllToolbars(onTrue, onFalse, onHover, onHoverOut, onEnable, onDisable, 243 | visibleInScenes, nameSpace, toolbarId, largeToolbarIcon, largeToolbarIcon, smallToolbarIcon, smallToolbarIcon, toolTip); 244 | } 245 | 246 | /// 247 | /// AddLeftRightClickCallbacks 248 | /// 249 | /// 250 | /// 251 | public void AddLeftRightClickCallbacks(Callback onLeftClick, Callback onRightClick) 252 | { 253 | this.onLeftClick = onLeftClick; 254 | this.onRightClick = onRightClick; 255 | 256 | if (stockButton != null) 257 | { 258 | if (onLeftClick != null) 259 | stockButton.onLeftClick = (Callback)Delegate.Combine(stockButton.onLeftClick, this.onLeftClick); //combine delegates together 260 | if (onRightClick != null) 261 | stockButton.onRightClick = (Callback)Delegate.Combine(stockButton.onRightClick, this.onRightClick); //combine delegates together 262 | } 263 | } 264 | 265 | 266 | 267 | public void AddToAllToolbars(TC_ClickHandler onTrue, TC_ClickHandler onFalse, TC_ClickHandler onHover, TC_ClickHandler onHoverOut, TC_ClickHandler onEnable, TC_ClickHandler onDisable, 268 | ApplicationLauncher.AppScenes visibleInScenes, string nameSpace, string toolbarId, string largeToolbarIconActive, string largeToolbarIconInactive, string smallToolbarIconActive, string smallToolbarIconInactive, string toolTip = null) 269 | 270 | { 271 | Log.Debug(ConfigInfo.debugMode, "AddToAlltoolbars main, nameSpace: " + nameSpace + ", toolbarId: " + toolbarId + 272 | ", largeToolbarIconActive: " + largeToolbarIconActive + ", largeToolbarIconInactive: " + largeToolbarIconInactive + 273 | ", smallToolbarIconActive: " + smallToolbarIconActive + ", smallToolbarIconInactive: " + smallToolbarIconInactive + 274 | ", visibleInScenes: " + (int)visibleInScenes 275 | ); 276 | if (toolTip == null) 277 | Log.Debug(ConfigInfo.debugMode, "toolTip is null"); 278 | else 279 | Log.Debug(ConfigInfo.debugMode, "toolTip: " + toolTip); 280 | 281 | this.onTrue = onTrue; 282 | this.onFalse = onFalse; 283 | this.onHover = onHover; 284 | this.onHoverOut = onHoverOut; 285 | this.onEnable = onEnable; 286 | this.onDisable = onDisable; 287 | 288 | this.visibleInScenes = visibleInScenes; 289 | this.nameSpace = nameSpace; 290 | this.toolbarId = toolbarId; 291 | this.BlizzyToolbarIconActive = smallToolbarIconActive; 292 | this.BlizzyToolbarIconInactive = smallToolbarIconInactive; 293 | this.StockToolbarIconActive = largeToolbarIconActive; 294 | this.StockToolbarIconInactive = largeToolbarIconInactive; 295 | try 296 | { 297 | if (HighLogic.CurrentGame.Parameters.CustomParams().showStockTooltips) 298 | this.ToolTip = toolTip; 299 | } 300 | catch { } 301 | 302 | StartAfterInit(); 303 | if (registeredMods.ContainsKey(nameSpace)) 304 | { 305 | registeredMods[nameSpace].modToolbarControl = this; 306 | UseButtons(nameSpace); 307 | } 308 | else 309 | Log.Debug(ConfigInfo.debugMode, "Missing namespace: " + nameSpace); 310 | } 311 | 312 | string lastLarge = ""; 313 | string lastSmall = ""; 314 | public void SetTexture(string large, string small) 315 | { 316 | if (large == "" && small == "") 317 | { 318 | lastLarge = ""; 319 | lastSmall = ""; 320 | UpdateToolbarIcon(); 321 | return; 322 | } 323 | if (lastSmall != small) 324 | { 325 | lastSmall = small; 326 | if (ToolbarManager.ToolbarAvailable && blizzyActive) 327 | { 328 | blizzyButton.TexturePath = small; 329 | try { blizzyButton.BigTexturePath = large; } 330 | catch { Log.Error("****** Blizzy toolbar needs updating ******"); } 331 | } 332 | } 333 | if (stockActive) 334 | { 335 | if (lastLarge != large) 336 | { 337 | lastLarge = large; 338 | 339 | Texture2D tex = GetTexture(lastLarge, false); 340 | if (tex != null && stockButton != null) 341 | stockButton.SetTexture((Texture)tex); 342 | } 343 | } 344 | } 345 | 346 | public bool IsHovering 347 | { 348 | get 349 | { 350 | return stockButton.IsHovering || blizzyButton.IsHovering; 351 | } 352 | } 353 | 354 | public Rect? StockPosition 355 | { 356 | get 357 | { 358 | if (stockButton != null) 359 | { 360 | Camera _camera = UIMainCamera.Camera; 361 | Vector3 _pos = _camera.WorldToScreenPoint(stockButton.GetAnchorUL()); 362 | return new Rect(_pos.x, Screen.height - _pos.y, 41, 41); 363 | } 364 | return null; 365 | } 366 | } 367 | 368 | public Rect? BlizzyPosition 369 | { 370 | get { return null; } 371 | } 372 | 373 | public void DisableMutuallyExclusive() 374 | { 375 | mutuallyExclusive = false; 376 | if (stockButton != null) 377 | ApplicationLauncher.Instance.DisableMutuallyExclusive(stockButton); 378 | } 379 | 380 | public void EnableMutuallyExclusive() 381 | { 382 | if (stockButton != null) 383 | { 384 | Log.Info("EnableMutuallyExclusive, stock button is not null"); 385 | } 386 | else 387 | { 388 | Log.Info("EnableMutuallyExclusive, stock button is null"); 389 | } 390 | mutuallyExclusive = true; 391 | if (stockButton != null) 392 | ApplicationLauncher.Instance.EnableMutuallyExclusive(stockButton); 393 | 394 | } 395 | 396 | 397 | void SetButtonPos() 398 | { 399 | Vector2 pos = Input.mousePosition; 400 | pos.y = Screen.height - pos.y; 401 | buttonClickedMousePos = pos; 402 | } 403 | 404 | event TC_ClickHandler onTrue = null; 405 | event TC_ClickHandler onFalse = null; 406 | event Callback onLeftClick = null; 407 | event Callback onRightClick = null; 408 | event TC_ClickHandler onHover = null; 409 | event TC_ClickHandler onHoverOut = null; 410 | event TC_ClickHandler onEnable = null; 411 | event TC_ClickHandler onDisable = null; 412 | 413 | 414 | private ApplicationLauncherButton stockButton; 415 | private IButton blizzyButton; 416 | 417 | public bool buttonActive = false; 418 | 419 | bool stockActive = false; 420 | bool blizzyActive = false; 421 | private bool mutuallyExclusive = false; 422 | 423 | public void SetFalse() 424 | { 425 | if (stockButton != null) 426 | { 427 | stockButton.SetFalse(); 428 | } 429 | else 430 | { 431 | ToggleButtonActive(); 432 | } 433 | UpdateToolbarIcon(); 434 | } 435 | 436 | private void RemoveStockButton() 437 | { 438 | if (this.stockButton != null) 439 | { 440 | if (mutuallyExclusive) 441 | ApplicationLauncher.Instance.DisableMutuallyExclusive(stockButton); 442 | ApplicationLauncher.Instance.RemoveModApplication(this.stockButton); 443 | GameEvents.onGUIApplicationLauncherReady.Remove(OnGUIAppLauncherReady); 444 | GameEvents.onGUIApplicationLauncherDestroyed.Remove(OnGUIAppLauncherDestroyed); 445 | 446 | this.stockButton = null; 447 | } 448 | } 449 | 450 | private void RemoveBlizzyButton() 451 | { 452 | if (this.blizzyButton != null) 453 | { 454 | this.blizzyButton.Destroy(); 455 | this.blizzyButton = null; 456 | } 457 | } 458 | 459 | #region SetButtonSettings 460 | private void SetBlizzySettings() 461 | { 462 | if (!ToolbarManager.ToolbarAvailable) 463 | { 464 | this.stockActive = true; 465 | SetStockSettings(); 466 | return; 467 | } 468 | if (!this.stockActive) 469 | { 470 | this.RemoveStockButton(); 471 | } 472 | 473 | if (this.blizzyButton == null && this.blizzyActive) 474 | { 475 | Log.Debug(ConfigInfo.debugMode, "Adding blizzyButton, nameSpace: " + nameSpace + ", toolbarId: " + toolbarId + ", ToolTip: " + ToolTip); 476 | this.blizzyButton = ToolbarManager.Instance.add(nameSpace, toolbarId); 477 | this.blizzyButton.ToolTip = ToolTip; 478 | this.blizzyButton.OnClick += this.button_Click; 479 | 480 | this.blizzyButton.OnMouseLeave += (e) => 481 | { 482 | doOnHoverOut(); 483 | }; 484 | 485 | this.blizzyButton.OnMouseEnter += (e) => 486 | { 487 | doOnHover(); 488 | }; 489 | 490 | this.blizzyButton.Visibility = new TC_GameScenesVisibility(visibleInScenes); 491 | } 492 | if (!this.blizzyActive) 493 | { 494 | this.RemoveBlizzyButton(); 495 | } 496 | this.UpdateToolbarIcon(); 497 | } 498 | #if false 499 | private void OnMouseEnter() 500 | { 501 | 502 | } 503 | private void OnMouseLeave() 504 | { 505 | 506 | } 507 | #endif 508 | private void SetStockSettings() 509 | { 510 | if (!this.blizzyActive) 511 | { 512 | this.RemoveBlizzyButton(); 513 | } 514 | if (this.stockButton == null && this.stockActive) 515 | { 516 | // Blizzy toolbar not available, or Stock Toolbar selected Let's go stock :( 517 | GameEvents.onGUIApplicationLauncherReady.Add(this.OnGUIAppLauncherReady); 518 | GameEvents.onGUIApplicationLauncherDestroyed.Add(this.OnGUIAppLauncherDestroyed); 519 | this.OnGUIAppLauncherReady(); 520 | } 521 | if (!this.stockActive && ToolbarManager.ToolbarAvailable) 522 | { 523 | this.RemoveStockButton(); 524 | } 525 | this.UpdateToolbarIcon(true); 526 | } 527 | #endregion 528 | 529 | private void StartAfterInit() 530 | { 531 | if (tcList == null) 532 | tcList = new List(); 533 | 534 | tcList.Add(this); 535 | } 536 | 537 | bool destroyed = false; 538 | public void OnDestroy() 539 | { 540 | tcList.Remove(this); 541 | destroyed = true; 542 | 543 | if (stockActive) 544 | { 545 | RemoveStockButton(); 546 | 547 | } 548 | 549 | if (ToolbarManager.ToolbarAvailable && blizzyActive) 550 | { 551 | RemoveBlizzyButton(); 552 | } 553 | } 554 | 555 | private void UpdateToolbarIcon(bool firstTime = false) 556 | { 557 | SetIsEnabled(isEnabled); 558 | 559 | if (ToolbarManager.ToolbarAvailable && this.blizzyActive && this.blizzyButton != null) 560 | { 561 | if (this.lastSmall != "") 562 | { 563 | this.blizzyButton.TexturePath = lastSmall; 564 | try { this.blizzyButton.BigTexturePath = lastLarge; } 565 | catch { Log.Error("****** Blizzy toolbar needs updating ******"); } 566 | } 567 | else 568 | { 569 | this.blizzyButton.TexturePath = this.buttonActive ? this.BlizzyToolbarIconActive : this.BlizzyToolbarIconInactive; 570 | try { this.blizzyButton.BigTexturePath = this.buttonActive ? this.StockToolbarIconActive : this.StockToolbarIconInactive; } 571 | catch { Log.Error("****** Blizzy toolbar needs updating ******"); } 572 | } 573 | } 574 | //else 575 | if (this.stockActive) 576 | { 577 | if (this.stockButton == null && !firstTime) 578 | Log.Debug(ConfigInfo.debugMode, "stockButton is null, namespace: " + this.nameSpace); 579 | else 580 | { 581 | if (this.stockButton != null) 582 | { 583 | if (this.lastLarge != "") 584 | { 585 | var tex = (Texture)GetTexture(this.lastLarge, false); 586 | if (tex != null) 587 | { 588 | this.stockButton.SetTexture(tex); 589 | } 590 | } 591 | else 592 | { 593 | var tex = (Texture)GetTexture(this.buttonActive ? this.StockToolbarIconActive : this.StockToolbarIconInactive, false); 594 | if (tex != null) 595 | { 596 | this.stockButton.SetTexture(tex); 597 | } 598 | } 599 | } 600 | } 601 | } 602 | } 603 | 604 | // 605 | // The following function was initially copied from @JPLRepo's AmpYear mod, which is covered by the GPL, as is this mod 606 | // 607 | // This function will attempt to load either a PNG or a JPG from the specified path. 608 | // It first checks to see if the actual file is there, if not, it then looks for either a PNG or a JPG 609 | // 610 | // easier to specify different cases than to change case to lower. This will fail on MacOS and Linux 611 | // if a suffix has mixed case 612 | static string[] imgSuffixes = new string[] { ".png", ".jpg", ".gif", ".PNG", ".JPG", ".GIF", ".dds", ".DDS" }; 613 | public static Boolean LoadImageFromFile(ref Texture2D tex, String fileNamePath) 614 | { 615 | 616 | Boolean blnReturn = false; 617 | if (tex == null) 618 | { 619 | tex = new Texture2D(16, 16, TextureFormat.ARGB32, false); 620 | } 621 | bool dds = false; 622 | try 623 | { 624 | string path = fileNamePath; 625 | if (!System.IO.File.Exists(fileNamePath)) 626 | { 627 | // Look for the file with an appended suffix. 628 | for (int i = 0; i < imgSuffixes.Length; i++) 629 | 630 | if (System.IO.File.Exists(fileNamePath + imgSuffixes[i])) 631 | { 632 | path = fileNamePath + imgSuffixes[i]; 633 | dds = imgSuffixes[i] == ".dds" || imgSuffixes[i] == ".DDS"; 634 | break; 635 | } 636 | } 637 | 638 | //File Exists check 639 | if (System.IO.File.Exists(path)) 640 | { 641 | try 642 | { 643 | if (dds) 644 | { 645 | Log.Info("LoadImageFromFile, dds"); 646 | byte[] bytes = System.IO.File.ReadAllBytes(path); 647 | 648 | 649 | System.IO.BinaryReader binaryReader = new System.IO.BinaryReader(new System.IO.MemoryStream(bytes)); 650 | uint num = binaryReader.ReadUInt32(); 651 | 652 | if (num != DDSValues.uintMagic) 653 | { 654 | UnityEngine.Debug.LogError("DDS: File is not a DDS format file!"); 655 | return false; 656 | } 657 | DDSHeader ddSHeader = new DDSHeader(binaryReader); 658 | 659 | TextureFormat tf = TextureFormat.Alpha8; 660 | if (ddSHeader.ddspf.dwFourCC == DDSValues.uintDXT1) 661 | tf = TextureFormat.DXT1; 662 | if (ddSHeader.ddspf.dwFourCC == DDSValues.uintDXT5) 663 | tf = TextureFormat.DXT5; 664 | if (tf == TextureFormat.Alpha8) 665 | return false; 666 | 667 | 668 | tex = LoadTextureDXT(bytes, tf); 669 | } 670 | else 671 | { 672 | tex.LoadImage(System.IO.File.ReadAllBytes(path)); 673 | } 674 | blnReturn = true; 675 | } 676 | catch (Exception ex) 677 | { 678 | Log.Error("Failed to load the texture: " + path); 679 | Log.Error("Error: " + ex.Message); 680 | } 681 | } 682 | else 683 | { 684 | Log.Debug(ConfigInfo.debugMode, "Cannot find texture to load from file:" + fileNamePath); 685 | } 686 | } 687 | catch (Exception ex) 688 | { 689 | Log.Error("Failed to load (are you missing a file):" + fileNamePath); 690 | Log.Error(ex.Message); 691 | } 692 | return blnReturn; 693 | } 694 | 695 | public static Texture2D LoadTextureDXT(byte[] ddsBytes, TextureFormat textureFormat) 696 | { 697 | if (textureFormat != TextureFormat.DXT1 && textureFormat != TextureFormat.DXT5) 698 | throw new Exception("Invalid TextureFormat. Only DXT1 and DXT5 formats are supported by this method."); 699 | 700 | byte ddsSizeCheck = ddsBytes[4]; 701 | if (ddsSizeCheck != 124) 702 | throw new Exception("Invalid DDS DXTn texture. Unable to read"); //this header byte should be 124 for DDS image files 703 | 704 | int height = ddsBytes[13] * 256 + ddsBytes[12]; 705 | int width = ddsBytes[17] * 256 + ddsBytes[16]; 706 | 707 | int DDS_HEADER_SIZE = 128; 708 | byte[] dxtBytes = new byte[ddsBytes.Length - DDS_HEADER_SIZE]; 709 | Buffer.BlockCopy(ddsBytes, DDS_HEADER_SIZE, dxtBytes, 0, ddsBytes.Length - DDS_HEADER_SIZE); 710 | 711 | Texture2D texture = new Texture2D(width, height, textureFormat, false); 712 | texture.LoadRawTextureData(dxtBytes); 713 | texture.Apply(); 714 | 715 | return (texture); 716 | } 717 | 718 | Texture2D GetTexture(string path, bool b) 719 | { 720 | //Log.Debug(ConfigInfo.debugMode, "GetTexture, path: " + KSPUtil.ApplicationRootPath + "GameData/" + path); 721 | 722 | Texture2D tex = new Texture2D(16, 16, TextureFormat.ARGB32, false); 723 | 724 | // Since most mods have their button textures in files, try loading from the file first 725 | 726 | if (LoadImageFromFile(ref tex, KSPUtil.ApplicationRootPath + "GameData/" + path)) 727 | return tex; 728 | if (GameDatabase.Instance.ExistsTexture(path)) 729 | { 730 | tex = GameDatabase.Instance.GetTexture(path, false); 731 | return tex; 732 | } 733 | 734 | 735 | Log.Error("Cannot find texture to load:" + path); 736 | 737 | return null; 738 | } 739 | 740 | private void OnGUIAppLauncherReady() 741 | { 742 | if (destroyed) 743 | return; 744 | // Setup PW Stock Toolbar button 745 | if (ApplicationLauncher.Ready && stockButton == null) 746 | { 747 | // 748 | // The following is done because Unity will be calling 749 | // all the functions every frame. This way if none is defined, 750 | // then null is passed and Unity won't do the call 751 | // 752 | Callback tcOnTrue = null; 753 | if (this.onTrue != null) tcOnTrue = doOnTrue; 754 | Callback tcOnFalse = null; 755 | if (this.onFalse != null) tcOnFalse = doOnFalse; 756 | Callback tcOnHover = null; 757 | if (this.onHover != null) tcOnHover = doOnHover; 758 | Callback tcOnHoverOut = null; 759 | if (this.onHoverOut != null) tcOnHoverOut = doOnHoverOut; 760 | Callback tcOnEnable = null; 761 | if (this.onEnable != null) tcOnEnable = doOnEnable; 762 | Callback tcOnDisable = null; 763 | if (this.onDisable != null) tcOnDisable = doOnDisable; 764 | 765 | 766 | stockButton = ApplicationLauncher.Instance.AddModApplication( 767 | tcOnTrue, 768 | tcOnFalse, 769 | tcOnHover, 770 | tcOnHoverOut, 771 | tcOnEnable, 772 | tcOnDisable, 773 | visibleInScenes, 774 | (Texture)GetTexture(StockToolbarIconActive, false)); 775 | 776 | if (onLeftClick != null) 777 | stockButton.onLeftClick = (Callback)Delegate.Combine(stockButton.onLeftClick, onLeftClick); //combine delegates together 778 | if (onRightClick != null) 779 | stockButton.onRightClick = (Callback)Delegate.Combine(stockButton.onRightClick, onRightClick); //combine delegates together 780 | 781 | SetStockSettings(); 782 | if (doSetTrue) 783 | SetTrue(doSetTrueValue); 784 | if (doSetFalse) 785 | SetFalse(doSetFalseValue); 786 | if (mutuallyExclusive) 787 | { 788 | Log.Info("OnGUIAppLauncherReady, EnableMutuallyExclusive, stock button is not null"); 789 | ApplicationLauncher.Instance.EnableMutuallyExclusive(stockButton); 790 | } 791 | } 792 | } 793 | 794 | private void doOnTrue() 795 | { 796 | SetButtonPos(); 797 | if (this.onTrue != null) 798 | SetButtonActive(); 799 | } 800 | 801 | private void doOnFalse() 802 | { 803 | SetButtonPos(); 804 | if (this.onFalse != null) 805 | SetButtonInactive(); 806 | } 807 | 808 | private void doOnHover() 809 | { 810 | if (stockActive) 811 | { 812 | drawTooltip = true; 813 | starttimeToolTipShown = Time.fixedTime; 814 | } 815 | if (this.onHover != null) onHover(); 816 | } 817 | 818 | private void doOnHoverOut() { drawTooltip = false; if (this.onHoverOut != null) onHoverOut(); } 819 | private void doOnEnable() { if (this.onEnable != null) onEnable(); } 820 | private void doOnDisable() { if (this.onDisable != null) onDisable(); } 821 | 822 | 823 | 824 | private void button_Click(ClickEvent e) 825 | { 826 | SetButtonPos(); 827 | if (e.MouseButton == 0) 828 | { 829 | if (this.onTrue != null) 830 | this.ToggleButtonActive(); 831 | 832 | if (onLeftClick != null) 833 | onLeftClick(); 834 | } 835 | if (e.MouseButton == 1) 836 | { 837 | if (onRightClick != null) 838 | onRightClick(); 839 | } 840 | } 841 | 842 | #region ActiveInactive 843 | void SetButtonActive() 844 | { 845 | this.buttonActive = true; 846 | if (onTrue != null) 847 | onTrue(); 848 | UpdateToolbarIcon(); 849 | } 850 | 851 | void SetButtonInactive() 852 | { 853 | this.buttonActive = false; 854 | if (onFalse != null) 855 | onFalse(); 856 | UpdateToolbarIcon(); 857 | } 858 | 859 | private void ToggleButtonActive() 860 | { 861 | this.buttonActive = !this.buttonActive; 862 | 863 | if (this.buttonActive) 864 | { 865 | SetButtonActive(); 866 | } 867 | else 868 | { 869 | SetButtonInactive(); 870 | } 871 | } 872 | #endregion 873 | 874 | private void OnGUIAppLauncherDestroyed() 875 | { 876 | RemoveStockButton(); 877 | } 878 | 879 | #region tooltip 880 | bool drawTooltip = false; 881 | float starttimeToolTipShown = 0; 882 | Vector2 tooltipSize; 883 | float tooltipX, tooltipY; 884 | Rect tooltipRect; 885 | 886 | void OnGUI() 887 | { 888 | if (HighLogic.LoadedScene == GameScenes.SPACECENTER || 889 | HighLogic.LoadedScene == GameScenes.EDITOR || 890 | HighLogic.LoadedScene == GameScenes.FLIGHT || 891 | HighLogic.LoadedScene == GameScenes.TRACKSTATION) 892 | { 893 | if (!HighLogic.CurrentGame.Parameters.CustomParams().showStockTooltips) 894 | return; 895 | if (drawTooltip && ToolTip != null && ToolTip.Trim().Length > 0) 896 | { 897 | if (Time.fixedTime - starttimeToolTipShown > HighLogic.CurrentGame.Parameters.CustomParams().hoverTimeout) 898 | return; 899 | 900 | Rect brect = new Rect(Input.mousePosition.x, Input.mousePosition.y, 38, 38); 901 | SetupTooltip(); 902 | GUI.Window(12342, tooltipRect, TooltipWindow, ""); 903 | } 904 | } 905 | } 906 | 907 | 908 | void SetupTooltip() 909 | { 910 | if (ToolTip != null && ToolTip.Trim().Length > 0) 911 | { 912 | Vector2 mousePosition; 913 | mousePosition.x = Input.mousePosition.x; 914 | mousePosition.y = Screen.height - Input.mousePosition.y; 915 | 916 | int buttonsize = (int)(42 * GameSettings.UI_SCALE) + 2; 917 | tooltipSize = HighLogic.Skin.label.CalcSize(new GUIContent(ToolTip)); 918 | 919 | if (HighLogic.LoadedScene == GameScenes.EDITOR || HighLogic.LoadedScene == GameScenes.SPACECENTER || 920 | HighLogic.LoadedScene == GameScenes.TRACKSTATION) 921 | { 922 | tooltipX = (mousePosition.x + tooltipSize.x > Screen.width) ? (Screen.width - tooltipSize.x) : mousePosition.x; 923 | tooltipY = Math.Min(mousePosition.y, Screen.height - buttonsize); 924 | } 925 | else 926 | { 927 | tooltipX = Math.Min(mousePosition.x, Screen.width - buttonsize - tooltipSize.x); 928 | tooltipY = mousePosition.y; 929 | } 930 | 931 | if (tooltipX < 0) tooltipX = 0; 932 | if (tooltipY < 0) tooltipY = 0; 933 | tooltipRect = new Rect(tooltipX - 1, tooltipY - tooltipSize.y, tooltipSize.x + 4, tooltipSize.y); 934 | 935 | } 936 | } 937 | void TooltipWindow(int id) 938 | { 939 | GUI.Label(new Rect(2, 0, tooltipRect.width - 2, tooltipRect.height), ToolTip, HighLogic.Skin.label); 940 | } 941 | protected void DrawTooltip() 942 | { 943 | if (ToolTip != null && ToolTip.Trim().Length > 0) 944 | { 945 | GUI.Label(tooltipRect, ToolTip, HighLogic.Skin.label); 946 | } 947 | } 948 | #endregion 949 | 950 | /// 951 | /// Checks whether the given stock button was created by this mod. 952 | /// 953 | /// the button to check 954 | /// The namespace of the button 955 | /// the unique ID of the button 956 | /// true, if the button was created by the mod, false otherwise 957 | public static bool IsStockButtonManaged(ApplicationLauncherButton button, out string nameSpace, out string id, out string toolTip) 958 | { 959 | nameSpace = ""; 960 | id = ""; 961 | toolTip = ""; 962 | if (tcList == null) 963 | return false; 964 | foreach (var b in tcList) 965 | { 966 | if (b.stockActive) 967 | { 968 | if (b.stockButton == button) 969 | { 970 | nameSpace = b.nameSpace; 971 | id = b.toolbarId; 972 | toolTip = b.toolTip; 973 | return true; 974 | } 975 | } 976 | } 977 | return false; 978 | } 979 | 980 | 981 | /// 982 | /// Checks whether the given stock button was created by this mod. 983 | /// 984 | /// the button to check 985 | /// The namespace of the button 986 | /// the unique ID of the button 987 | /// true, if the button was created by the mod, false otherwise 988 | public static bool IsBlizzyButtonManaged(IButton blizzyButton, out string nameSpace, out string id, out string toolTip) 989 | { 990 | nameSpace = ""; 991 | id = ""; 992 | toolTip = ""; 993 | if (tcList == null) 994 | return false; 995 | foreach (var b in tcList) 996 | { 997 | if (b.stockActive) 998 | { 999 | if (b.blizzyButton == blizzyButton) 1000 | { 1001 | nameSpace = b.nameSpace; 1002 | id = b.toolbarId; 1003 | toolTip = b.toolTip; 1004 | return true; 1005 | } 1006 | } 1007 | } 1008 | return false; 1009 | } 1010 | 1011 | public void SetTrue(bool makeCall = false) 1012 | { 1013 | doSetTrue = false; 1014 | 1015 | if (stockButton == null && stockActive) 1016 | { 1017 | doSetTrue = true; 1018 | doSetTrueValue = makeCall; 1019 | } 1020 | if (ToolbarManager.ToolbarAvailable && blizzyButton == null && blizzyActive) 1021 | { 1022 | doSetTrue = true; 1023 | doSetTrueValue = makeCall; 1024 | } 1025 | if (stockButton == null && blizzyButton == null) 1026 | return; 1027 | doSetTrue = false; 1028 | 1029 | if (stockActive) 1030 | { 1031 | if (stockButton != null) 1032 | { 1033 | stockButton.SetTrue(makeCall); 1034 | makeCall = false; 1035 | } 1036 | else 1037 | Log.Error("SetTrue called before stockButton is initialized"); 1038 | } 1039 | //else 1040 | if (ToolbarManager.ToolbarAvailable && blizzyActive) 1041 | { 1042 | if (blizzyButton != null) 1043 | { 1044 | blizzyButton.TexturePath = BlizzyToolbarIconActive; 1045 | try { blizzyButton.BigTexturePath = StockToolbarIconActive; } 1046 | catch { Log.Error("****** Blizzy toolbar needs updating ******"); } 1047 | } 1048 | else 1049 | Log.Error("SetTrue called before blizzyButton is initialized"); 1050 | 1051 | if (onTrue != null && makeCall) 1052 | onTrue(); 1053 | } 1054 | buttonActive = true; 1055 | 1056 | UpdateToolbarIcon(false); 1057 | } 1058 | 1059 | bool doSetFalse = false, doSetFalseValue = false; 1060 | bool doSetTrue = false, doSetTrueValue = false; 1061 | 1062 | public void SetFalse(bool makeCall = false) 1063 | { 1064 | doSetFalse = false; 1065 | 1066 | 1067 | if (stockButton == null && stockActive) 1068 | { 1069 | doSetFalse = true; 1070 | doSetFalseValue = makeCall; 1071 | } 1072 | if (blizzyButton == null && ToolbarManager.ToolbarAvailable && blizzyActive) 1073 | { 1074 | doSetFalse = true; 1075 | doSetFalseValue = makeCall; 1076 | } 1077 | if (stockButton == null && blizzyButton == null) 1078 | return; 1079 | doSetFalse = false; 1080 | 1081 | if (stockButton != null && stockActive) 1082 | { 1083 | stockButton.SetFalse(makeCall); 1084 | makeCall = false; 1085 | } 1086 | //else 1087 | if (ToolbarManager.ToolbarAvailable && blizzyActive) 1088 | { 1089 | blizzyButton.TexturePath = BlizzyToolbarIconInactive; 1090 | try { blizzyButton.BigTexturePath = StockToolbarIconInactive; } 1091 | catch { Log.Error("****** Blizzy toolbar needs updating ******"); } 1092 | if (onFalse != null && makeCall) 1093 | onFalse(); 1094 | } 1095 | buttonActive = false; 1096 | 1097 | UpdateToolbarIcon(false); 1098 | } 1099 | } 1100 | } 1101 | -------------------------------------------------------------------------------- /ToolbarControl/ToolbarControl.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B146B9F2-61CB-4E43-BF7C-8737448116AE} 8 | Library 9 | Properties 10 | ToolbarControl_NS 11 | ToolbarControl 12 | v4.7.2 13 | 512 14 | 15 | 16 | 17 | true 18 | portable 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | false 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | false 34 | 35 | 36 | 37 | True 38 | True 39 | AssemblyVersion.tt 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | TextTemplatingFileGenerator 56 | AssemblyVersion.cs 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | False 78 | 79 | 80 | False 81 | 82 | 83 | False 84 | $(KSPDIR)\GameData\000_ClickThroughBlocker\Plugins\ClickThroughBlocker.dll 85 | 86 | 87 | 88 | 89 | 90 | "$(DevEnvDir)\texttransform.exe" "$(ProjectDir)AssemblyVersion.tt" 91 | 92 | 93 | 94 | set KSPDIR=$(KSPDIR) 95 | 96 | IF "%25KSPDIR%25"=="" ( 97 | 98 | ECHO Configuration error - KSPDIR not specified in project. 99 | 100 | ECHO Either set KSPDIR environment variable or edit BetterLoadSaveGame.Common.props 101 | 102 | PAUSE 103 | 104 | GOTO DONE 105 | 106 | ) 107 | 108 | start /D $(SolutionDir) /WAIT deploy.bat $(TargetDir) $(TargetFileName) $(TargetName) 109 | 110 | if $(ConfigurationName) == Release ( 111 | 112 | start /D $(SolutionDir) /WAIT buildRelease.bat $(TargetDir) $(TargetFileName) $(TargetName) 113 | 114 | ) 115 | 116 | -------------------------------------------------------------------------------- /ToolbarControl/ToolbarControl.csproj.173: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B146B9F2-61CB-4E43-BF7C-8737448116AE} 8 | Library 9 | Properties 10 | ToolbarControl_NS 11 | ToolbarControl 12 | v3.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | True 35 | True 36 | AssemblyVersion.tt 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | TextTemplatingFileGenerator 53 | AssemblyVersion.cs 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | False 75 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\Assembly-CSharp.dll 76 | 77 | 78 | False 79 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\Assembly-CSharp-firstpass.dll 80 | 81 | 82 | False 83 | R:\KSP_1.7.3_dev\GameData\000_ClickThroughBlocker\Plugins\ClickThroughBlocker.dll 84 | 85 | 86 | 87 | 88 | False 89 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\UnityEngine.dll 90 | 91 | 92 | False 93 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\UnityEngine.UI.dll 94 | 95 | 96 | 97 | 98 | 99 | set textTemplatingPath="%25ProgramFiles(x86)%25\Microsoft Visual Studio\2017\Community\Common7\IDE\texttransform.exe" 100 | 101 | %25textTemplatingPath%25 "$(ProjectDir)AssemblyVersion.tt" 102 | 103 | 104 | start /D D:\Users\jbb\github\ToolbarControl /WAIT deploy.bat $(TargetDir) $(TargetFileName) 105 | 106 | if $(ConfigurationName) == Release ( 107 | start /D D:\Users\jbb\github\ToolbarControl /WAIT buildRelease.bat $(TargetDir) $(TargetFileName) 108 | ) 109 | 110 | 111 | -------------------------------------------------------------------------------- /ToolbarControl/ToolbarControl.csproj.orig: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B146B9F2-61CB-4E43-BF7C-8737448116AE} 8 | Library 9 | Properties 10 | ToolbarControl_NS 11 | ToolbarControl 12 | v3.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | True 35 | True 36 | AssemblyVersion.tt 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | TextTemplatingFileGenerator 53 | AssemblyVersion.cs 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | False 75 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\Assembly-CSharp.dll 76 | 77 | 78 | False 79 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\Assembly-CSharp-firstpass.dll 80 | 81 | 82 | False 83 | R:\KSP_1.7.3_dev\GameData\000_ClickThroughBlocker\Plugins\ClickThroughBlocker.dll 84 | 85 | 86 | 87 | 88 | False 89 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\UnityEngine.dll 90 | 91 | 92 | False 93 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\UnityEngine.UI.dll 94 | 95 | 96 | 97 | 98 | 99 | set textTemplatingPath="%25ProgramFiles(x86)%25\Microsoft Visual Studio\2017\Community\Common7\IDE\texttransform.exe" 100 | 101 | %25textTemplatingPath%25 "$(ProjectDir)AssemblyVersion.tt" 102 | 103 | 104 | start /D D:\Users\jbb\github\ToolbarControl /WAIT deploy.bat $(TargetDir) $(TargetFileName) 105 | 106 | if $(ConfigurationName) == Release ( 107 | start /D D:\Users\jbb\github\ToolbarControl /WAIT buildRelease.bat $(TargetDir) $(TargetFileName) 108 | ) 109 | 110 | 111 | -------------------------------------------------------------------------------- /ToolbarControl/ToolbarWrapper.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013-2016, Maik Schreiber 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Reflection; 29 | using UnityEngine; 30 | 31 | 32 | // TODO: Change to your plugin's namespace here. 33 | namespace ToolbarControl_NS 34 | { 35 | 36 | 37 | 38 | /**********************************************************\ 39 | * --- DO NOT EDIT BELOW THIS COMMENT --- * 40 | * * 41 | * This file contains classes and interfaces to use the * 42 | * Toolbar Plugin without creating a hard dependency on it. * 43 | * * 44 | * There is nothing in this file that needs to be edited * 45 | * by hand. * 46 | * * 47 | * --- DO NOT EDIT BELOW THIS COMMENT --- * 48 | \**********************************************************/ 49 | 50 | 51 | 52 | /// 53 | /// The global tool bar manager. 54 | /// 55 | public partial class ToolbarManager : IToolbarManager 56 | { 57 | /// 58 | /// Whether the Toolbar Plugin is available. 59 | /// 60 | public static bool ToolbarAvailable 61 | { 62 | get 63 | { 64 | if (toolbarAvailable == null) 65 | { 66 | toolbarAvailable = Instance != null; 67 | } 68 | return (bool)toolbarAvailable; 69 | } 70 | } 71 | 72 | /// 73 | /// The global tool bar manager instance. 74 | /// 75 | public static IToolbarManager Instance 76 | { 77 | get 78 | { 79 | if ((toolbarAvailable != false) && (instance_ == null)) 80 | { 81 | Type type = ToolbarTypes.getType("Toolbar.ToolbarManager"); 82 | if (type != null) 83 | { 84 | object realToolbarManager = ToolbarTypes.getStaticProperty(type, "Instance").GetValue(null, null); 85 | instance_ = new ToolbarManager(realToolbarManager); 86 | } 87 | } 88 | return instance_; 89 | } 90 | } 91 | } 92 | 93 | #region interfaces 94 | 95 | /// 96 | /// A toolbar manager. 97 | /// 98 | public interface IToolbarManager 99 | { 100 | /// 101 | /// Adds a new button. 102 | /// 103 | /// 104 | /// To replace an existing button, just add a new button using the old button's namespace and ID. 105 | /// Note that the new button will inherit the screen position of the old button. 106 | /// 107 | /// The new button's namespace. This is usually the plugin's name. Must not include special characters like '.' 108 | /// The new button's ID. This ID must be unique across all buttons in the namespace. Must not include special characters like '.' 109 | /// The button created. 110 | IButton add(string ns, string id); 111 | } 112 | 113 | /// 114 | /// Represents a clickable button. 115 | /// 116 | public interface IButton 117 | { 118 | /// 119 | /// The text displayed on the button. Set to null to hide text. 120 | /// 121 | /// 122 | /// The text can be changed at any time to modify the button's appearance. Note that since this will also 123 | /// modify the button's size, this feature should be used sparingly, if at all. 124 | /// 125 | /// 126 | string Text 127 | { 128 | set; 129 | get; 130 | } 131 | 132 | /// 133 | /// The color the button text is displayed with. Defaults to Color.white. 134 | /// 135 | /// 136 | /// The text color can be changed at any time to modify the button's appearance. 137 | /// 138 | Color TextColor 139 | { 140 | set; 141 | get; 142 | } 143 | 144 | /// 145 | /// The path of a texture file to display an icon on the button. Set to null to hide icon. 146 | /// 147 | /// 148 | /// 149 | /// A texture path on a button will have precedence over text. That is, if both text and texture path 150 | /// have been set on a button, the button will show the texture, not the text. 151 | /// 152 | /// 153 | /// The texture size must not exceed 24x24 pixels. 154 | /// 155 | /// 156 | /// The texture path must be relative to the "GameData" directory, and must not specify a file name suffix. 157 | /// Valid example: MyAddon/Textures/icon_mybutton 158 | /// 159 | /// 160 | /// The texture path can be changed at any time to modify the button's appearance. 161 | /// 162 | /// 163 | /// 164 | string TexturePath 165 | { 166 | set; 167 | get; 168 | } 169 | string BigTexturePath 170 | { 171 | set; 172 | get; 173 | } 174 | /// 175 | /// The button's tool tip text. Set to null if no tool tip is desired. 176 | /// 177 | /// 178 | /// Tool Tip Text Should Always Use Headline Style Like This. 179 | /// 180 | string ToolTip 181 | { 182 | set; 183 | get; 184 | } 185 | 186 | /// 187 | /// Whether this button is currently visible or not. Can be used in addition to or as a replacement for . 188 | /// 189 | /// 190 | /// Setting this property to true does not affect the player's ability to hide the button using the configuration. 191 | /// Conversely, setting this property to false does not enable the player to show the button using the configuration. 192 | /// 193 | bool Visible 194 | { 195 | set; 196 | get; 197 | } 198 | 199 | /// 200 | /// Determines this button's visibility. Can be used in addition to or as a replacement for . 201 | /// 202 | /// 203 | /// The return value from IVisibility.Visible is subject to the same rules as outlined for 204 | /// . 205 | /// 206 | IVisibility Visibility 207 | { 208 | set; 209 | get; 210 | } 211 | 212 | /// 213 | /// Whether this button is currently effectively visible or not. This is a combination of 214 | /// and . 215 | /// 216 | /// 217 | /// Note that the toolbar is not visible in certain game scenes, for example the loading screens. This property 218 | /// does not reflect button invisibility in those scenes. In addition, this property does not reflect the 219 | /// player's configuration of the button's visibility. 220 | /// 221 | bool EffectivelyVisible 222 | { 223 | get; 224 | } 225 | bool IsHovering 226 | { 227 | get; 228 | } 229 | 230 | 231 | /// 232 | /// Whether this button is currently enabled (clickable) or not. This does not affect the player's ability to 233 | /// position the button on their toolbar. 234 | /// 235 | bool Enabled 236 | { 237 | set; 238 | get; 239 | } 240 | 241 | /// 242 | /// Whether this button is currently "important." Set to false to return to normal button behaviour. 243 | /// 244 | /// 245 | /// 246 | /// This can be used to temporarily force the button to be shown on screen regardless of the toolbar being 247 | /// currently in auto-hidden mode. For example, a button that signals the arrival of a private message in 248 | /// a chat room could mark itself as "important" as long as the message has not been read. 249 | /// 250 | /// 251 | /// Setting this property does not change the appearance of the button. Use to 252 | /// change the button's icon. 253 | /// 254 | /// 255 | /// Setting this property to true does not affect the player's ability to hide the button using the 256 | /// configuration. 257 | /// 258 | /// 259 | /// This feature should be used only sparingly, if at all, since it forces the button to be displayed on 260 | /// screen even when it normally wouldn't. 261 | /// 262 | /// 263 | bool Important 264 | { 265 | set; 266 | get; 267 | } 268 | 269 | /// 270 | /// A drawable that is tied to the current button. This can be anything from a popup menu to 271 | /// an informational window. Set to null to hide the drawable. 272 | /// 273 | IDrawable Drawable 274 | { 275 | set; 276 | get; 277 | } 278 | 279 | /// 280 | /// Event handler that can be registered with to receive "on click" events. 281 | /// 282 | /// 283 | /// 284 | /// IButton button = ... 285 | /// button.OnClick += (e) => { 286 | /// Debug.Log("button clicked, mouseButton: " + e.MouseButton); 287 | /// }; 288 | /// 289 | /// 290 | event ClickHandler OnClick; 291 | 292 | /// 293 | /// Event handler that can be registered with to receive "on mouse enter" events. 294 | /// 295 | /// 296 | /// 297 | /// IButton button = ... 298 | /// button.OnMouseEnter += (e) => { 299 | /// Debug.Log("mouse entered button"); 300 | /// }; 301 | /// 302 | /// 303 | event MouseEnterHandler OnMouseEnter; 304 | 305 | /// 306 | /// Event handler that can be registered with to receive "on mouse leave" events. 307 | /// 308 | /// 309 | /// 310 | /// IButton button = ... 311 | /// button.OnMouseLeave += (e) => { 312 | /// Debug.Log("mouse left button"); 313 | /// }; 314 | /// 315 | /// 316 | event MouseLeaveHandler OnMouseLeave; 317 | 318 | /// 319 | /// Permanently destroys this button so that it is no longer displayed. 320 | /// Should be used when a plugin is stopped to remove leftover buttons. 321 | /// 322 | void Destroy(); 323 | } 324 | 325 | /// 326 | /// A drawable that is tied to a particular button. This can be anything from a popup menu 327 | /// to an informational window. 328 | /// 329 | public interface IDrawable 330 | { 331 | /// 332 | /// Update any information. This is called once per frame. 333 | /// 334 | void Update(); 335 | 336 | /// 337 | /// Draws GUI widgets for this drawable. This is the equivalent to the OnGUI() message in 338 | /// . 339 | /// 340 | /// 341 | /// The drawable will be positioned near its parent toolbar according to the drawable's current 342 | /// width/height. 343 | /// 344 | /// The left/top position of where to draw this drawable. 345 | /// The current width/height of this drawable. 346 | Vector2 Draw(Vector2 position); 347 | } 348 | 349 | #endregion 350 | 351 | #region events 352 | 353 | /// 354 | /// Event describing a click on a button. 355 | /// 356 | public partial class ClickEvent : EventArgs 357 | { 358 | /// 359 | /// The button that has been clicked. 360 | /// 361 | public readonly IButton Button; 362 | 363 | /// 364 | /// The mouse button which the button was clicked with. 365 | /// 366 | /// 367 | /// Is 0 for left mouse button, 1 for right mouse button, and 2 for middle mouse button. 368 | /// 369 | public readonly int MouseButton; 370 | } 371 | 372 | /// 373 | /// An event handler that is invoked whenever a button has been clicked. 374 | /// 375 | /// An event describing the button click. 376 | public delegate void ClickHandler(ClickEvent e); 377 | 378 | /// 379 | /// Event describing the mouse pointer moving about a button. 380 | /// 381 | public abstract partial class MouseMoveEvent 382 | { 383 | /// 384 | /// The button in question. 385 | /// 386 | public readonly IButton button; 387 | } 388 | 389 | /// 390 | /// Event describing the mouse pointer entering a button's area. 391 | /// 392 | public partial class MouseEnterEvent : MouseMoveEvent 393 | { 394 | } 395 | 396 | /// 397 | /// Event describing the mouse pointer leaving a button's area. 398 | /// 399 | public partial class MouseLeaveEvent : MouseMoveEvent 400 | { 401 | } 402 | 403 | /// 404 | /// An event handler that is invoked whenever the mouse pointer enters a button's area. 405 | /// 406 | /// An event describing the mouse pointer entering. 407 | public delegate void MouseEnterHandler(MouseEnterEvent e); 408 | 409 | /// 410 | /// An event handler that is invoked whenever the mouse pointer leaves a button's area. 411 | /// 412 | /// An event describing the mouse pointer leaving. 413 | public delegate void MouseLeaveHandler(MouseLeaveEvent e); 414 | 415 | #endregion 416 | 417 | #region visibility 418 | 419 | /// 420 | /// Determines visibility of a button. 421 | /// 422 | /// 423 | public interface IVisibility 424 | { 425 | /// 426 | /// Whether a button is currently visible or not. 427 | /// 428 | /// 429 | bool Visible 430 | { 431 | get; 432 | } 433 | } 434 | 435 | /// 436 | /// Determines visibility of a button in relation to the currently running game scene. 437 | /// 438 | /// 439 | /// 440 | /// IButton button = ... 441 | /// button.Visibility = new GameScenesVisibility(GameScenes.EDITOR, GameScenes.FLIGHT); 442 | /// 443 | /// 444 | /// 445 | public class GameScenesVisibility : IVisibility 446 | { 447 | public bool Visible 448 | { 449 | get 450 | { 451 | return (bool)visibleProperty.GetValue(realGameScenesVisibility, null); 452 | } 453 | } 454 | 455 | private object realGameScenesVisibility; 456 | private PropertyInfo visibleProperty; 457 | 458 | public GameScenesVisibility(params GameScenes[] gameScenes) 459 | { 460 | Type gameScenesVisibilityType = ToolbarTypes.getType("Toolbar.GameScenesVisibility"); 461 | realGameScenesVisibility = Activator.CreateInstance(gameScenesVisibilityType, new object[] { gameScenes }); 462 | visibleProperty = ToolbarTypes.getProperty(gameScenesVisibilityType, "Visible"); 463 | } 464 | } 465 | 466 | #endregion 467 | 468 | #region drawable 469 | 470 | /// 471 | /// A drawable that draws a popup menu. 472 | /// 473 | public partial class PopupMenuDrawable : IDrawable 474 | { 475 | /// 476 | /// Event handler that can be registered with to receive "any menu option clicked" events. 477 | /// 478 | public event Action OnAnyOptionClicked 479 | { 480 | add 481 | { 482 | onAnyOptionClickedEvent.AddEventHandler(realPopupMenuDrawable, value); 483 | } 484 | remove 485 | { 486 | onAnyOptionClickedEvent.RemoveEventHandler(realPopupMenuDrawable, value); 487 | } 488 | } 489 | 490 | private object realPopupMenuDrawable; 491 | private MethodInfo updateMethod; 492 | private MethodInfo drawMethod; 493 | private MethodInfo addOptionMethod; 494 | private MethodInfo addSeparatorMethod; 495 | private MethodInfo destroyMethod; 496 | private EventInfo onAnyOptionClickedEvent; 497 | 498 | public PopupMenuDrawable() 499 | { 500 | Type popupMenuDrawableType = ToolbarTypes.getType("Toolbar.PopupMenuDrawable"); 501 | realPopupMenuDrawable = Activator.CreateInstance(popupMenuDrawableType, null); 502 | updateMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "Update"); 503 | drawMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "Draw"); 504 | addOptionMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "AddOption"); 505 | addSeparatorMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "AddSeparator"); 506 | destroyMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "Destroy"); 507 | onAnyOptionClickedEvent = ToolbarTypes.getEvent(popupMenuDrawableType, "OnAnyOptionClicked"); 508 | } 509 | 510 | public void Update() 511 | { 512 | updateMethod.Invoke(realPopupMenuDrawable, null); 513 | } 514 | 515 | public Vector2 Draw(Vector2 position) 516 | { 517 | return (Vector2)drawMethod.Invoke(realPopupMenuDrawable, new object[] { position }); 518 | } 519 | 520 | /// 521 | /// Adds a new option to the popup menu. 522 | /// 523 | /// The text of the option. 524 | /// A button that can be used to register clicks on the menu option. 525 | public IButton AddOption(string text) 526 | { 527 | object realButton = addOptionMethod.Invoke(realPopupMenuDrawable, new object[] { text }); 528 | return new Button(realButton, new ToolbarTypes()); 529 | } 530 | 531 | /// 532 | /// Adds a separator to the popup menu. 533 | /// 534 | public void AddSeparator() 535 | { 536 | addSeparatorMethod.Invoke(realPopupMenuDrawable, null); 537 | } 538 | 539 | /// 540 | /// Destroys this drawable. This must always be called before disposing of this drawable. 541 | /// 542 | public void Destroy() 543 | { 544 | destroyMethod.Invoke(realPopupMenuDrawable, null); 545 | } 546 | } 547 | 548 | #endregion 549 | 550 | #region private implementations 551 | 552 | public partial class ToolbarManager : IToolbarManager 553 | { 554 | private static bool? toolbarAvailable = null; 555 | private static IToolbarManager instance_; 556 | 557 | private object realToolbarManager; 558 | private MethodInfo addMethod; 559 | private Dictionary buttons = new Dictionary(); 560 | private ToolbarTypes types = new ToolbarTypes(); 561 | 562 | private ToolbarManager(object realToolbarManager) 563 | { 564 | this.realToolbarManager = realToolbarManager; 565 | 566 | addMethod = ToolbarTypes.getMethod(types.iToolbarManagerType, "add"); 567 | } 568 | 569 | public IButton add(string ns, string id) 570 | { 571 | object realButton = addMethod.Invoke(realToolbarManager, new object[] { ns, id }); 572 | IButton button = new Button(realButton, types); 573 | buttons.Add(realButton, button); 574 | return button; 575 | } 576 | } 577 | 578 | internal class Button : IButton 579 | { 580 | private object realButton; 581 | private ToolbarTypes types; 582 | private Delegate realClickHandler; 583 | private Delegate realMouseEnterHandler; 584 | private Delegate realMouseLeaveHandler; 585 | 586 | internal Button(object realButton, ToolbarTypes types) 587 | { 588 | this.realButton = realButton; 589 | this.types = types; 590 | 591 | realClickHandler = attachEventHandler(types.button.onClickEvent, "clicked", realButton); 592 | realMouseEnterHandler = attachEventHandler(types.button.onMouseEnterEvent, "mouseEntered", realButton); 593 | realMouseLeaveHandler = attachEventHandler(types.button.onMouseLeaveEvent, "mouseLeft", realButton); 594 | } 595 | 596 | private Delegate attachEventHandler(EventInfo @event, string methodName, object realButton) 597 | { 598 | MethodInfo method = GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); 599 | Delegate d = Delegate.CreateDelegate(@event.EventHandlerType, this, method); 600 | @event.AddEventHandler(realButton, d); 601 | return d; 602 | } 603 | 604 | public string Text 605 | { 606 | set 607 | { 608 | types.button.textProperty.SetValue(realButton, value, null); 609 | } 610 | get 611 | { 612 | return (string)types.button.textProperty.GetValue(realButton, null); 613 | } 614 | } 615 | 616 | public Color TextColor 617 | { 618 | set 619 | { 620 | types.button.textColorProperty.SetValue(realButton, value, null); 621 | } 622 | get 623 | { 624 | return (Color)types.button.textColorProperty.GetValue(realButton, null); 625 | } 626 | } 627 | 628 | public string TexturePath 629 | { 630 | set 631 | { 632 | types.button.texturePathProperty.SetValue(realButton, value, null); 633 | } 634 | get 635 | { 636 | return (string)types.button.texturePathProperty.GetValue(realButton, null); 637 | } 638 | } 639 | public string BigTexturePath 640 | { 641 | set 642 | { 643 | types.button.bigTexturePathProperty.SetValue(realButton, value, null); 644 | } 645 | get 646 | { 647 | return (string)types.button.bigTexturePathProperty.GetValue(realButton, null); 648 | } 649 | } 650 | 651 | public string ToolTip 652 | { 653 | set 654 | { 655 | types.button.toolTipProperty.SetValue(realButton, value, null); 656 | } 657 | get 658 | { 659 | return (string)types.button.toolTipProperty.GetValue(realButton, null); 660 | } 661 | } 662 | 663 | public bool Visible 664 | { 665 | set 666 | { 667 | types.button.visibleProperty.SetValue(realButton, value, null); 668 | } 669 | get 670 | { 671 | return (bool)types.button.visibleProperty.GetValue(realButton, null); 672 | } 673 | } 674 | 675 | public IVisibility Visibility 676 | { 677 | set 678 | { 679 | object functionVisibility = null; 680 | if (value != null) 681 | { 682 | functionVisibility = Activator.CreateInstance(types.functionVisibilityType, new object[] { new Func(() => value.Visible) }); 683 | } 684 | types.button.visibilityProperty.SetValue(realButton, functionVisibility, null); 685 | visibility_ = value; 686 | } 687 | get 688 | { 689 | return visibility_; 690 | } 691 | } 692 | private IVisibility visibility_; 693 | 694 | public bool EffectivelyVisible 695 | { 696 | get 697 | { 698 | return (bool)types.button.effectivelyVisibleProperty.GetValue(realButton, null); 699 | } 700 | } 701 | public bool IsHovering 702 | { 703 | get 704 | { 705 | return (bool)types.button.isHoveringProperty.GetValue(realButton, null); 706 | } 707 | } 708 | 709 | public bool Enabled 710 | { 711 | set 712 | { 713 | types.button.enabledProperty.SetValue(realButton, value, null); 714 | } 715 | get 716 | { 717 | return (bool)types.button.enabledProperty.GetValue(realButton, null); 718 | } 719 | } 720 | 721 | public bool Important 722 | { 723 | set 724 | { 725 | types.button.importantProperty.SetValue(realButton, value, null); 726 | } 727 | get 728 | { 729 | return (bool)types.button.importantProperty.GetValue(realButton, null); 730 | } 731 | } 732 | 733 | public IDrawable Drawable 734 | { 735 | set 736 | { 737 | object functionDrawable = null; 738 | if (value != null) 739 | { 740 | functionDrawable = Activator.CreateInstance(types.functionDrawableType, new object[] { 741 | new Action(() => value.Update()), 742 | new Func((pos) => value.Draw(pos)) 743 | }); 744 | } 745 | types.button.drawableProperty.SetValue(realButton, functionDrawable, null); 746 | drawable_ = value; 747 | } 748 | get 749 | { 750 | return drawable_; 751 | } 752 | } 753 | private IDrawable drawable_; 754 | 755 | public event ClickHandler OnClick; 756 | 757 | private void clicked(object realEvent) 758 | { 759 | if (OnClick != null) 760 | { 761 | OnClick(new ClickEvent(realEvent, this)); 762 | } 763 | } 764 | 765 | public event MouseEnterHandler OnMouseEnter; 766 | 767 | private void mouseEntered(object realEvent) 768 | { 769 | if (OnMouseEnter != null) 770 | { 771 | OnMouseEnter(new MouseEnterEvent(this)); 772 | } 773 | } 774 | 775 | public event MouseLeaveHandler OnMouseLeave; 776 | 777 | private void mouseLeft(object realEvent) 778 | { 779 | if (OnMouseLeave != null) 780 | { 781 | OnMouseLeave(new MouseLeaveEvent(this)); 782 | } 783 | } 784 | 785 | public void Destroy() 786 | { 787 | detachEventHandler(types.button.onClickEvent, realClickHandler, realButton); 788 | detachEventHandler(types.button.onMouseEnterEvent, realMouseEnterHandler, realButton); 789 | detachEventHandler(types.button.onMouseLeaveEvent, realMouseLeaveHandler, realButton); 790 | 791 | types.button.destroyMethod.Invoke(realButton, null); 792 | } 793 | 794 | private void detachEventHandler(EventInfo @event, Delegate d, object realButton) 795 | { 796 | @event.RemoveEventHandler(realButton, d); 797 | } 798 | } 799 | 800 | public partial class ClickEvent : EventArgs 801 | { 802 | internal ClickEvent(object realEvent, IButton button) 803 | { 804 | Type type = realEvent.GetType(); 805 | Button = button; 806 | MouseButton = (int)type.GetField("MouseButton", BindingFlags.Public | BindingFlags.Instance).GetValue(realEvent); 807 | } 808 | } 809 | 810 | public abstract partial class MouseMoveEvent : EventArgs 811 | { 812 | internal MouseMoveEvent(IButton button) 813 | { 814 | this.button = button; 815 | } 816 | } 817 | 818 | public partial class MouseEnterEvent : MouseMoveEvent 819 | { 820 | internal MouseEnterEvent(IButton button) 821 | : base(button) 822 | { 823 | } 824 | } 825 | 826 | public partial class MouseLeaveEvent : MouseMoveEvent 827 | { 828 | internal MouseLeaveEvent(IButton button) 829 | : base(button) 830 | { 831 | } 832 | } 833 | 834 | internal class ToolbarTypes 835 | { 836 | internal readonly Type iToolbarManagerType; 837 | internal readonly Type functionVisibilityType; 838 | internal readonly Type functionDrawableType; 839 | internal readonly ButtonTypes button; 840 | 841 | internal ToolbarTypes() 842 | { 843 | iToolbarManagerType = getType("Toolbar.IToolbarManager"); 844 | functionVisibilityType = getType("Toolbar.FunctionVisibility"); 845 | functionDrawableType = getType("Toolbar.FunctionDrawable"); 846 | 847 | Type iButtonType = getType("Toolbar.IButton"); 848 | button = new ButtonTypes(iButtonType); 849 | } 850 | 851 | internal static Type getType(string name) 852 | { 853 | Type type = null; 854 | AssemblyLoader.loadedAssemblies.TypeOperation(t => { 855 | if (t.FullName == name) 856 | { 857 | type = t; 858 | } 859 | }); 860 | return type; 861 | } 862 | 863 | internal static PropertyInfo getProperty(Type type, string name) 864 | { 865 | return type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance); 866 | } 867 | 868 | internal static PropertyInfo getStaticProperty(Type type, string name) 869 | { 870 | return type.GetProperty(name, BindingFlags.Public | BindingFlags.Static); 871 | } 872 | 873 | internal static EventInfo getEvent(Type type, string name) 874 | { 875 | return type.GetEvent(name, BindingFlags.Public | BindingFlags.Instance); 876 | } 877 | 878 | internal static MethodInfo getMethod(Type type, string name) 879 | { 880 | return type.GetMethod(name, BindingFlags.Public | BindingFlags.Instance); 881 | } 882 | } 883 | 884 | internal class ButtonTypes 885 | { 886 | internal readonly Type iButtonType; 887 | internal readonly PropertyInfo textProperty; 888 | internal readonly PropertyInfo textColorProperty; 889 | internal readonly PropertyInfo texturePathProperty; 890 | internal readonly PropertyInfo bigTexturePathProperty; 891 | internal readonly PropertyInfo toolTipProperty; 892 | internal readonly PropertyInfo visibleProperty; 893 | internal readonly PropertyInfo visibilityProperty; 894 | internal readonly PropertyInfo effectivelyVisibleProperty; 895 | internal readonly PropertyInfo isHoveringProperty; 896 | internal readonly PropertyInfo enabledProperty; 897 | internal readonly PropertyInfo importantProperty; 898 | internal readonly PropertyInfo drawableProperty; 899 | internal readonly EventInfo onClickEvent; 900 | internal readonly EventInfo onMouseEnterEvent; 901 | internal readonly EventInfo onMouseLeaveEvent; 902 | internal readonly MethodInfo destroyMethod; 903 | 904 | internal ButtonTypes(Type iButtonType) 905 | { 906 | this.iButtonType = iButtonType; 907 | 908 | textProperty = ToolbarTypes.getProperty(iButtonType, "Text"); 909 | textColorProperty = ToolbarTypes.getProperty(iButtonType, "TextColor"); 910 | texturePathProperty = ToolbarTypes.getProperty(iButtonType, "TexturePath"); 911 | bigTexturePathProperty = ToolbarTypes.getProperty(iButtonType, "BigTexturePath"); 912 | toolTipProperty = ToolbarTypes.getProperty(iButtonType, "ToolTip"); 913 | visibleProperty = ToolbarTypes.getProperty(iButtonType, "Visible"); 914 | visibilityProperty = ToolbarTypes.getProperty(iButtonType, "Visibility"); 915 | effectivelyVisibleProperty = ToolbarTypes.getProperty(iButtonType, "EffectivelyVisible"); 916 | isHoveringProperty = ToolbarTypes.getProperty(iButtonType, "IsHovering"); 917 | 918 | enabledProperty = ToolbarTypes.getProperty(iButtonType, "Enabled"); 919 | importantProperty = ToolbarTypes.getProperty(iButtonType, "Important"); 920 | drawableProperty = ToolbarTypes.getProperty(iButtonType, "Drawable"); 921 | onClickEvent = ToolbarTypes.getEvent(iButtonType, "OnClick"); 922 | onMouseEnterEvent = ToolbarTypes.getEvent(iButtonType, "OnMouseEnter"); 923 | onMouseLeaveEvent = ToolbarTypes.getEvent(iButtonType, "OnMouseLeave"); 924 | destroyMethod = ToolbarTypes.getMethod(iButtonType, "Destroy"); 925 | } 926 | } 927 | 928 | #endregion 929 | } 930 | -------------------------------------------------------------------------------- /buildRelease.bat: -------------------------------------------------------------------------------- 1 | 2 | @echo off 3 | 4 | rem Put the following text into the Post-build event command line: 5 | rem without the "rem": 6 | 7 | rem start /D D:\Users\jbb\github\IFI-Life-Support /WAIT deploy.bat $(TargetDir) $(TargetFileName) 8 | rem 9 | rem if $(ConfigurationName) == Release ( 10 | rem 11 | rem start /D D:\Users\jbb\github\IFI-Life-Support /WAIT buildRelease.bat $(TargetDir) $(TargetFileName) 12 | rem 13 | rem ) 14 | 15 | 16 | rem Set variables here 17 | 18 | rem H is the destination game folder 19 | rem GAMEDIR is the name of the mod folder (usually the mod name) 20 | rem GAMEDATA is the name of the local GameData 21 | rem VERSIONFILE is the name of the version file, usually the same as GAMEDATA, 22 | rem but not always 23 | rem LICENSE is the license file 24 | rem README is the readme file 25 | 26 | set GAMEDIR=001_ToolbarControl 27 | set GAMEDATA="GameData\" 28 | set VERSIONFILE=ToolbarControl.version 29 | set LICENSE=LICENSE.md 30 | set README=README.md 31 | 32 | set RELEASEDIR=d:\Users\jbb\release 33 | set ZIP="c:\Program Files\7-zip\7z.exe" 34 | 35 | rem Copy files to GameData locations 36 | 37 | copy /Y "%1%2" "%GAMEDATA%\%GAMEDIR%\Plugins" 38 | copy /Y %VERSIONFILE% %GAMEDATA%\%GAMEDIR% 39 | 40 | if "%LICENSE%" NEQ "" copy /y %LICENSE% %GAMEDATA%\%GAMEDIR% 41 | if "%README%" NEQ "" copy /Y %README% %GAMEDATA%\%GAMEDIR% 42 | 43 | rem Get Version info 44 | 45 | copy %VERSIONFILE% tmp.version 46 | set VERSIONFILE=tmp.version 47 | rem The following requires the JQ program, available here: https://stedolan.github.io/jq/download/ 48 | c:\local\jq-win64 ".VERSION.MAJOR" %VERSIONFILE% >tmpfile 49 | set /P major=tmpfile 52 | set /P minor=tmpfile 55 | set /P patch=tmpfile 58 | set /P build=