├── .gitattributes ├── .gitignore ├── KeeTheme.sln ├── KeeTheme ├── ControlVisitor.cs ├── Decorators │ ├── ControlSnapshot.cs │ ├── KnownColorsDecorator.cs │ ├── ListViewDecorator.cs │ ├── ListViewGroupsPainter.cs │ ├── ListViewHeaderPainter.cs │ ├── ListViewNativeWindow.cs │ ├── ObjectListViewDecorator.cs │ ├── PwGeneratorMenuDecorator.cs │ ├── RichTextBoxDecorator.cs │ ├── RichTextBoxNativeWindow.cs │ └── SplitButtonExDecorator.cs ├── Editor │ ├── ColorConverter.cs │ ├── ColorEditor.cs │ ├── GenericTypeConverter.cs │ ├── TemplateEditorForm.Designer.cs │ ├── TemplateEditorForm.cs │ └── TemplateEditorForm.resx ├── FormAddedEventHandler.cs ├── FormsArrayList.cs ├── KeeTheme.cs ├── KeeTheme.csproj ├── KeeThemeExt.cs ├── Options │ ├── KeeThemeOptions.cs │ ├── OptionsPanel.Designer.cs │ ├── OptionsPanel.cs │ └── OptionsPanel.resx ├── Properties │ ├── AssemblyInfo.cs │ ├── Resource.Designer.cs │ └── Resource.resx ├── Resources │ ├── DarkTheme.ini │ ├── DarkThemeWin11.ini │ └── PluginIcon.png ├── TemplateFile.cs ├── TemplateReader.cs ├── Theme │ ├── ButtonLook.cs │ ├── CheckBoxButtonLook.cs │ ├── CheckBoxLook.cs │ ├── ControlLook.cs │ ├── CustomColorTable.cs │ ├── CustomTheme.cs │ ├── CustomThemeTemplate.cs │ ├── CustomToolStripRenderer.cs │ ├── ITheme.cs │ ├── IniFile.cs │ ├── LinkLabelLook.cs │ ├── ListViewLook.cs │ ├── MenuLook.cs │ ├── OtherLook.cs │ ├── Palette.cs │ ├── PropertyGridLook.cs │ ├── RichTextBoxLook.cs │ ├── ToolStripLook.cs │ └── TreeViewLook.cs └── Win10ThemeMonitor.cs ├── LICENSE ├── README.md ├── build ├── build.cmd └── plgxexclude.txt ├── choco ├── keetheme.nuspec ├── publish.ps1 └── tools │ ├── chocolateyinstall.ps1 │ ├── chocolateyuninstall.ps1 │ └── common.ps1 ├── docs ├── KeePassDarkTheme.png ├── KeePassDarkThemeCustomOptions.png ├── KeePassDarkThemeEditor.png ├── KeePassDarkThemeOpenDatabase.png ├── KeePassDarkThemeOptions.png ├── KeePassDarkThemeWin11.png ├── KeePassDarkThemeWin11OpenDatabase.png └── KeePassDarkThemeWin11Options.png └── themes ├── DarkTheme.ini └── KeeTheme.ini /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | 332 | # Build artifacts 333 | /build/KeeTheme.dll 334 | /build/KeeTheme.plgx 335 | 336 | # Chocolatey artifacts 337 | /choco/choco.key 338 | /choco/KeeTheme.plgx 339 | -------------------------------------------------------------------------------- /KeeTheme.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28803.156 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeeTheme", "KeeTheme\KeeTheme.csproj", "{B82CD066-1BB1-42DB-B75A-F5489EF4A32D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {B82CD066-1BB1-42DB-B75A-F5489EF4A32D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {B82CD066-1BB1-42DB-B75A-F5489EF4A32D}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {B82CD066-1BB1-42DB-B75A-F5489EF4A32D}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {B82CD066-1BB1-42DB-B75A-F5489EF4A32D}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {07FAE6CB-E9A4-4F83-B77E-121ACFBD5DCB} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /KeeTheme/ControlVisitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace KeeTheme 5 | { 6 | internal class ControlVisitor 7 | { 8 | private readonly Action _onVisit; 9 | 10 | public ControlVisitor(Action onVisit) 11 | { 12 | _onVisit = onVisit; 13 | } 14 | 15 | public void Visit(Control control) 16 | { 17 | _onVisit(control); 18 | Visit(control.Controls); 19 | } 20 | 21 | private void Visit(Control.ControlCollection formControls) 22 | { 23 | foreach (Control control in formControls) 24 | { 25 | _onVisit(control); 26 | Visit(control.Controls); 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /KeeTheme/Decorators/ControlSnapshot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | 6 | namespace KeeTheme.Decorators 7 | { 8 | static class ControlSnapshot 9 | { 10 | public static void Make(Control control) 11 | { 12 | var disabledControlName = control.Name + "Snapshot"; 13 | 14 | var parent = control.Parent; 15 | if (!parent.Enabled) 16 | { 17 | if (parent.Controls.ContainsKey(disabledControlName)) 18 | return; 19 | 20 | // Can't use control.DrawToBitmap because: 21 | // RichTextBox - it does not draw text 22 | // ListView - it does not draw correct header color 23 | var screenCopy = TryCopyFromScreen(control); 24 | if (screenCopy == null) 25 | return; 26 | 27 | var controlSnapshot = new PictureBox(); 28 | controlSnapshot.Name = disabledControlName; 29 | controlSnapshot.Size = control.Size; 30 | controlSnapshot.Location = control.Location; 31 | controlSnapshot.Image = screenCopy; 32 | parent.Controls.Add(controlSnapshot); 33 | parent.Controls.SetChildIndex(controlSnapshot, 0); 34 | } 35 | else 36 | { 37 | parent.Controls.RemoveByKey(disabledControlName); 38 | } 39 | } 40 | 41 | private static Bitmap TryCopyFromScreen(Control control) 42 | { 43 | try 44 | { 45 | return CopyFromScreen(control); 46 | } 47 | catch (ArgumentException) 48 | { 49 | return null; 50 | } 51 | catch (InvalidOperationException) 52 | { 53 | return null; 54 | } 55 | catch (Win32Exception) 56 | { 57 | return null; 58 | } 59 | } 60 | 61 | private static Bitmap CopyFromScreen(Control control) 62 | { 63 | control.Update(); // Ensure control is fully painted 64 | var bitmap = new Bitmap(control.Bounds.Width, control.Bounds.Height); 65 | using (var g = Graphics.FromImage(bitmap)) 66 | { 67 | // ListView.PointToScreen returns result without border 68 | var upperLeftSource = control is ListView 69 | ? control.Parent.PointToScreen(Point.Empty) 70 | : control.PointToScreen(Point.Empty); 71 | 72 | g.CopyFromScreen(upperLeftSource, Point.Empty, control.Bounds.Size); 73 | } 74 | return bitmap; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /KeeTheme/Decorators/KnownColorsDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Reflection; 4 | using KeePassLib.Utility; 5 | using KeeTheme.Theme; 6 | 7 | namespace KeeTheme.Decorators 8 | { 9 | internal static class KnownColorsDecorator 10 | { 11 | private static int[] _originalColorTable; 12 | 13 | public static void Apply(ITheme theme, bool enabled) 14 | { 15 | var colorTableFieldName = MonoWorkarounds.IsRequired() ? "s_colorTable" : "colorTable"; 16 | var colorTableField = typeof(Color).Assembly.GetType("System.Drawing.KnownColorTable") 17 | .GetField(colorTableFieldName, BindingFlags.Static | BindingFlags.NonPublic); 18 | 19 | if (colorTableField == null) 20 | return; 21 | 22 | var colorTable = (int[]) colorTableField.GetValue(null); 23 | if (_originalColorTable == null) 24 | { 25 | _originalColorTable = new int[colorTable.Length]; 26 | Array.Copy(colorTable, _originalColorTable, colorTable.Length); 27 | } 28 | 29 | if (enabled) 30 | { 31 | colorTable[(int) KnownColor.ControlText] = theme.Control.ForeColor.ToArgb(); 32 | colorTable[(int) KnownColor.Control] = theme.Control.BackColor.ToArgb(); 33 | } 34 | else 35 | { 36 | Array.Copy(_originalColorTable, colorTable, colorTable.Length); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /KeeTheme/Decorators/ListViewDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Imaging; 4 | using System.Windows.Forms; 5 | using KeePass; 6 | using KeePass.UI; 7 | using KeePassLib.Utility; 8 | using KeeTheme.Theme; 9 | using CheckBoxState = System.Windows.Forms.VisualStyles.CheckBoxState; 10 | 11 | namespace KeeTheme.Decorators 12 | { 13 | class ListViewDecorator : Control 14 | { 15 | private readonly ListView _listView; 16 | private readonly ListViewHeaderPainter _headerPainter; 17 | private readonly ListViewGroupsPainter _groupsPainter; 18 | 19 | private ITheme _theme; 20 | private bool _enabled; 21 | 22 | public ListViewDecorator(ListView listView, ITheme theme) 23 | { 24 | _listView = listView; 25 | _theme = theme; 26 | 27 | if (!MonoWorkarounds.IsRequired()) 28 | { 29 | _headerPainter = new ListViewHeaderPainter(_listView); 30 | _headerPainter.Paint += HandleHeaderPaint; 31 | 32 | _groupsPainter = new ListViewGroupsPainter(_listView); 33 | _groupsPainter.Paint += HandleGroupsPaint; 34 | } 35 | 36 | _listView.Controls.Add(this); 37 | } 38 | 39 | private void HandleHeaderPaint(object sender, PaintEventArgs e) 40 | { 41 | if (!_enabled) 42 | return; 43 | 44 | using (var brush = new SolidBrush(_theme.ListView.HeaderBackColor)) 45 | { 46 | e.Graphics.FillRectangle(brush, e.ClipRectangle); 47 | using (var pen = new Pen(_theme.ListView.HeaderColumnBorderColor)) 48 | { 49 | e.Graphics.DrawLine(pen, 50 | e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Right, e.ClipRectangle.Y); 51 | } 52 | } 53 | } 54 | 55 | private void HandleGroupsPaint(object sender, GroupPaintEventArgs e) 56 | { 57 | if (!_enabled || !GroupColorsAreDefined()) 58 | return; 59 | 60 | // We have to redraw whole background. BufferedGraphicsContext is created to prevent flickering. 61 | using (var context = new BufferedGraphicsContext()) 62 | using (var g = context.Allocate(e.Graphics, e.ClipRectangle)) 63 | using (var highlightBrush = new SolidBrush(_theme.ListView.GroupHighlightColor)) 64 | using (var backBrush = new SolidBrush(_theme.ListView.GroupBackColor)) 65 | using (var foreBrush = new SolidBrush(_theme.ListView.GroupForeColor)) 66 | using (var forePen = new Pen(_theme.ListView.GroupForeColor)) 67 | using (var columnPen = new Pen(_theme.ListView.ColumnBorderColor)) 68 | 69 | { 70 | var isMouseOver = e.ClipRectangle.Contains(_listView.PointToClient(MousePosition)); 71 | g.Graphics.FillRectangle(isMouseOver ? highlightBrush : backBrush, e.ClipRectangle); 72 | 73 | SizeF textSize; 74 | using (var font = new Font(_listView.Font, FontStyle.Bold)) 75 | { 76 | textSize = e.Graphics.MeasureString(" " + _listView.Groups[e.GroupId].Header + " ", font); 77 | } 78 | 79 | var textRect = new Rectangle( 80 | e.ClipRectangle.X + 8, e.ClipRectangle.Y, (int)textSize.Width, e.ClipRectangle.Height - 1); 81 | 82 | using (var sf = new StringFormat()) 83 | { 84 | sf.Alignment = StringAlignment.Center; 85 | sf.LineAlignment = StringAlignment.Center; 86 | g.Graphics.DrawString(_listView.Groups[e.GroupId].Header, _listView.Font, foreBrush, textRect, sf); 87 | } 88 | 89 | var columnOffset = -2; // Initial padding 90 | foreach (ColumnHeader column in _listView.Columns) 91 | { 92 | columnOffset += column.Width; 93 | g.Graphics.DrawLine(columnPen, e.ClipRectangle.X + columnOffset, e.ClipRectangle.Y, 94 | e.ClipRectangle.X + columnOffset, e.ClipRectangle.Bottom); 95 | } 96 | 97 | var lineY = e.ClipRectangle.Y + e.ClipRectangle.Height / 2; 98 | g.Graphics.DrawLine(forePen, textRect.Right, lineY, e.ClipRectangle.Right, lineY); 99 | 100 | g.Render(e.Graphics); 101 | } 102 | 103 | } 104 | 105 | private bool GroupColorsAreDefined() 106 | { 107 | return _theme.ListView.GroupForeColor != Color.Empty 108 | && _theme.ListView.GroupBackColor != Color.Empty 109 | && _theme.ListView.GroupHighlightColor != Color.Empty; 110 | } 111 | 112 | private void Apply(Control control) 113 | { 114 | var listView = (ListView)control; 115 | 116 | if (!listView.OwnerDraw && listView.View == View.Details) 117 | { 118 | listView.OwnerDraw = true; 119 | 120 | listView.Resize += HandleListViewResize; 121 | listView.DrawColumnHeader += HandleListViewDrawColumnHeader; 122 | listView.DrawItem += HandleListViewDrawItem; 123 | listView.DrawSubItem += HandleListViewDrawSubItem; 124 | listView.Parent.EnabledChanged += ListViewParentEnabledChanged; 125 | } 126 | 127 | // Setting borders style throws exception on Mono 128 | if (!MonoWorkarounds.IsRequired()) 129 | listView.BorderStyle = _theme.ListView.BorderStyle; 130 | 131 | listView.BackColor = _theme.ListView.BackColor; 132 | 133 | if (_theme.ListViewBackgroundTiled) 134 | { 135 | listView.BackgroundImage = _theme.ListViewBackground; 136 | listView.BackgroundImageTiled = _theme.ListViewBackgroundTiled; 137 | } 138 | } 139 | 140 | private void ListViewParentEnabledChanged(object sender, EventArgs e) 141 | { 142 | if (_enabled) 143 | ControlSnapshot.Make(_listView); 144 | } 145 | 146 | private void HandleListViewResize(object sender, EventArgs e) 147 | { 148 | var listView = (ListView)sender; 149 | if (string.IsNullOrEmpty(_theme.ListView.BackgroundImage)) 150 | { 151 | if (!_theme.ListViewBackgroundTiled) 152 | { 153 | if (listView.BackgroundImage != null) 154 | listView.BackgroundImage.Dispose(); 155 | 156 | listView.BackgroundImage = null; 157 | } 158 | 159 | return; 160 | } 161 | 162 | if (_theme.ListViewBackground == null) 163 | return; 164 | 165 | var alignment = _theme.ListView.BackgroundImageAlignment > 0 166 | ? _theme.ListView.BackgroundImageAlignment 167 | : ContentAlignment.TopLeft; 168 | 169 | var bgSize = new Size(listView.ClientSize.Width, listView.ClientSize.Height - _headerPainter.HeaderHeight); 170 | var image = new Bitmap(bgSize.Width, bgSize.Height, PixelFormat.Format32bppArgb); 171 | 172 | using (var g = Graphics.FromImage(image)) 173 | using (var brush = new SolidBrush(_theme.ListView.BackColor)) 174 | using (var pen = new Pen(_theme.ListView.ColumnBorderColor)) 175 | { 176 | g.FillRectangle(brush, 0, 0, bgSize.Width, bgSize.Height); 177 | 178 | var location = GetImageLocation(alignment, bgSize, _theme.ListViewBackground.Size); 179 | g.DrawImage(_theme.ListViewBackground, location.X, location.Y); 180 | 181 | var offset = 0; 182 | foreach (ColumnHeader column in listView.Columns) 183 | { 184 | g.DrawLine(pen, offset + column.Width - 2, 0, offset + column.Width - 2, bgSize.Height); 185 | offset += column.Width; 186 | } 187 | } 188 | 189 | var prevImage = listView.BackgroundImage; 190 | listView.BackgroundImage = image; 191 | if (prevImage != null) 192 | prevImage.Dispose(); 193 | } 194 | 195 | private Point GetImageLocation(ContentAlignment alignment, Size bgSize, Size imageSize) 196 | { 197 | switch (alignment) 198 | { 199 | case ContentAlignment.TopLeft: return new Point(0, 0); 200 | case ContentAlignment.TopCenter: return new Point((bgSize.Width - imageSize.Width) / 2, 0); 201 | case ContentAlignment.TopRight: return new Point(bgSize.Width - imageSize.Width, 0); 202 | case ContentAlignment.MiddleLeft: 203 | return new Point(0, (bgSize.Height - imageSize.Height) / 2); 204 | case ContentAlignment.MiddleCenter: 205 | return new Point((bgSize.Width - imageSize.Width) / 2, (bgSize.Height - imageSize.Height) / 2); 206 | case ContentAlignment.MiddleRight: 207 | return new Point(bgSize.Width - imageSize.Width, (bgSize.Height - imageSize.Height) / 2); 208 | case ContentAlignment.BottomLeft: 209 | return new Point(0, bgSize.Height - imageSize.Height); 210 | case ContentAlignment.BottomCenter: 211 | return new Point((bgSize.Width - imageSize.Width) / 2, bgSize.Height - imageSize.Height); 212 | case ContentAlignment.BottomRight: 213 | return new Point(bgSize.Width - imageSize.Width, bgSize.Height - imageSize.Height); 214 | default: 215 | return new Point(0, 0); 216 | } 217 | } 218 | private void HandleListViewDrawItem(object sender, DrawListViewItemEventArgs e) 219 | { 220 | if (!_enabled) 221 | { 222 | e.DrawDefault = true; 223 | return; 224 | } 225 | 226 | if (e.State == 0) 227 | { 228 | e.DrawFocusRectangle(); 229 | return; 230 | } 231 | 232 | var backColor = GetAlternatingBackColor(e.Item.Index); 233 | 234 | var listItem = e.Item.Tag as PwListItem; 235 | if (listItem != null && !listItem.Entry.BackgroundColor.IsEmpty) 236 | { 237 | backColor = listItem.Entry.BackgroundColor; 238 | } 239 | 240 | if (_theme.ListViewBackground != null) 241 | backColor = Color.FromArgb(191, backColor); 242 | 243 | using (var brush = new SolidBrush(backColor)) 244 | { 245 | e.Graphics.FillRectangle(brush, e.Bounds); 246 | } 247 | 248 | e.DrawFocusRectangle(); 249 | } 250 | 251 | private Color GetAlternatingBackColor(int itemIndex) 252 | { 253 | if (!Program.Config.MainWindow.EntryListAlternatingBgColors) 254 | return _theme.ListView.OddRowColor; 255 | 256 | if ((itemIndex & 1) == 0) 257 | return _theme.ListView.EvenRowColor; 258 | 259 | var customAlternatingBgColor = Program.Config.MainWindow.EntryListAlternatingBgColor; 260 | return _listView.Name == "m_lvEntries" && customAlternatingBgColor != 0 261 | ? Color.FromArgb(customAlternatingBgColor) 262 | : _theme.ListView.OddRowColor; 263 | } 264 | 265 | private void HandleListViewDrawSubItem(object sender, DrawListViewSubItemEventArgs e) 266 | { 267 | if (!_enabled) 268 | { 269 | e.DrawDefault = true; 270 | return; 271 | } 272 | 273 | var bounds = e.Bounds; 274 | if (e.ColumnIndex == 0 && e.Header.DisplayIndex > 0) 275 | { 276 | // Fixes ListView internal error VSWhidbey #163674 277 | bounds.Offset(e.Item.Position.X - 4, 0); 278 | } 279 | 280 | var flags = GetTextFormatFlags(e.Header.TextAlign); 281 | var text = e.ItemIndex == -1 ? e.Item.Text : e.SubItem.Text; 282 | var font = e.ItemIndex == -1 ? e.Item.Font : e.SubItem.Font; 283 | var color = e.ItemIndex == -1 ? e.Item.ForeColor : e.SubItem.ForeColor; 284 | var textBounds = new Rectangle(bounds.Location, bounds.Size); 285 | 286 | var listItem = e.Item.Tag as PwListItem; 287 | if (listItem != null && !listItem.Entry.ForegroundColor.IsEmpty) 288 | { 289 | color = listItem.Entry.ForegroundColor; 290 | } 291 | 292 | text = " " + text + " "; 293 | if (e.ColumnIndex == 0 && e.Item.ImageIndex > -1) 294 | { 295 | var image = e.Item.ImageList.Images[e.Item.ImageIndex]; 296 | e.Item.ImageList.Draw(e.Graphics, bounds.X + 4, bounds.Y + 1, image.Width, image.Height, 297 | e.Item.ImageIndex); 298 | 299 | textBounds.Inflate(-image.Width - 4 - 2, 0); 300 | text = text.Remove(0, 1); 301 | } 302 | 303 | var listView = (ListView)sender; 304 | if (listView.CheckBoxes && e.ColumnIndex == 0) 305 | { 306 | var state = e.Item.Checked ? CheckBoxState.CheckedNormal : CheckBoxState.UncheckedNormal; 307 | CheckBoxRenderer.DrawCheckBox(e.Graphics, new Point(e.Bounds.X + 4, e.Bounds.Y + 1), state); 308 | 309 | textBounds.Inflate(-CheckBoxRenderer.GetGlyphSize(e.Graphics, state).Width - 4 - 2, 0); 310 | text = text.Remove(0, 1); 311 | } 312 | 313 | TextRenderer.DrawText(e.Graphics, text, font, textBounds, color, flags | TextFormatFlags.NoPrefix); 314 | 315 | using (var pen = new Pen(_theme.ListView.ColumnBorderColor)) 316 | e.Graphics.DrawLine(pen, bounds.Right - 2, bounds.Y, bounds.Right - 2, bounds.Bottom); 317 | } 318 | 319 | private void HandleListViewDrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) 320 | { 321 | if (!_enabled) 322 | { 323 | e.DrawDefault = true; 324 | return; 325 | } 326 | 327 | var listView = (ListView)sender; 328 | if (_theme.ListViewBackgroundTiled) 329 | { 330 | listView.BackgroundImage = listView.Items.Count == 0 ? _theme.ListViewBackground : null; 331 | } 332 | 333 | var graphics = e.Graphics; 334 | var r = e.Bounds; 335 | 336 | using (Brush backBrush = new SolidBrush(_theme.ListView.HeaderBackColor)) 337 | { 338 | graphics.FillRectangle(backBrush, r); 339 | } 340 | 341 | using (var pen = new Pen(_theme.ListView.HeaderColumnBorderColor)) 342 | { 343 | graphics.DrawLine(pen, r.X, r.Y, r.Right, r.Y); 344 | graphics.DrawLine(pen, r.Right - 2, r.Y, r.Right - 2, r.Bottom); 345 | } 346 | 347 | var flags = GetTextFormatFlags(e.Header.TextAlign); 348 | TextRenderer.DrawText(graphics, " " + e.Header.Text + " ", e.Font, r, 349 | _theme.ListView.HeaderForeColor, flags); 350 | } 351 | 352 | private static TextFormatFlags GetTextFormatFlags(HorizontalAlignment textAlign) 353 | { 354 | var flags = textAlign == HorizontalAlignment.Left 355 | ? TextFormatFlags.Left 356 | : textAlign == HorizontalAlignment.Center 357 | ? TextFormatFlags.HorizontalCenter 358 | : TextFormatFlags.Right; 359 | 360 | return flags | TextFormatFlags.WordEllipsis | TextFormatFlags.VerticalCenter; 361 | } 362 | 363 | public void EnableTheme(bool enabled, ITheme theme) 364 | { 365 | _enabled = enabled; 366 | _theme = theme; 367 | 368 | Apply(_listView); 369 | } 370 | } 371 | } 372 | -------------------------------------------------------------------------------- /KeeTheme/Decorators/ListViewGroupsPainter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Runtime.InteropServices; 4 | using System.Windows.Forms; 5 | 6 | namespace KeeTheme.Decorators 7 | { 8 | class ListViewGroupsPainter : ListViewNativeWindow 9 | { 10 | [StructLayout(LayoutKind.Sequential)] 11 | internal struct LVGROUP_V6 12 | { 13 | internal int cbSize; 14 | internal int mask; 15 | internal IntPtr pszHeader; 16 | internal int cchHeader; 17 | internal IntPtr pszFooter; 18 | internal int cchFooter; 19 | internal int iGroupID; 20 | internal int stateMask; 21 | internal int state; 22 | internal int align; 23 | 24 | internal IntPtr pszSubtitle; 25 | internal int cchSubtitle; 26 | internal IntPtr pszTask; 27 | internal int cchTask; 28 | internal IntPtr pszDescriptionTop; 29 | internal int cchDescriptionTop; 30 | internal IntPtr pszDescriptionBottom; 31 | internal int cchDescriptionBottom; 32 | internal int iTitleImage; 33 | internal int iExtendedImage; 34 | internal int iFirstItem; 35 | internal int cItems; 36 | internal IntPtr pszSubsetTitle; 37 | internal int cchSubsetTitle; 38 | 39 | public LVGROUP_V6(int cbSize) : this() 40 | { 41 | this.cbSize = cbSize; 42 | iGroupID = -1; 43 | } 44 | } 45 | 46 | const int LVM_GETGROUPRECT = LVM_FIRST + 0x62; 47 | const int LVM_GETGROUPINFOBYINDEX = LVM_FIRST + 0x99; 48 | const int LVGF_GROUPID = 0x0010; 49 | const int LVGGR_HEADER = 0x0001; 50 | 51 | private readonly ListView _listView; 52 | 53 | internal event GroupPaintEventHandler Paint; 54 | 55 | public ListViewGroupsPainter(ListView listView) 56 | { 57 | _listView = listView; 58 | 59 | AssignHandle(_listView.Handle); 60 | 61 | _listView.HandleCreated += HandleListViewHandleCreated; 62 | _listView.HandleDestroyed += HandleListViewHandleDestroyed; 63 | } 64 | 65 | private void HandleListViewHandleCreated(object sender, EventArgs e) 66 | { 67 | if (_listView != null) AssignHandle(_listView.Handle); 68 | } 69 | 70 | private void HandleListViewHandleDestroyed(object sender, EventArgs e) 71 | { 72 | ReleaseHandle(); 73 | } 74 | 75 | protected override void WndProc(ref Message m) 76 | { 77 | base.WndProc(ref m); 78 | 79 | if (m.Msg != WM_PAINT) 80 | return; 81 | 82 | // The first group is without header 83 | for (int i = 1; i <= _listView.Groups.Count; i++) 84 | { 85 | PaintGroup(i); 86 | } 87 | } 88 | 89 | private void PaintGroup(int i) 90 | { 91 | var groupId = GetGroupId(i); 92 | var rect = new RECT { Top = LVGGR_HEADER }; 93 | var rectSize = Marshal.SizeOf(typeof(RECT)); 94 | var lParam = Marshal.AllocHGlobal(rectSize); 95 | try 96 | { 97 | Marshal.StructureToPtr(rect, lParam, false); 98 | var retVal = SendMessage(_listView.Handle, LVM_GETGROUPRECT, new IntPtr(groupId), lParam); 99 | if (retVal == IntPtr.Zero) 100 | { 101 | return; 102 | } 103 | 104 | var retRc = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT)); 105 | using (var g = Graphics.FromHwnd(_listView.Handle)) 106 | { 107 | var groupRect = 108 | new Rectangle(retRc.Left, retRc.Top, retRc.Right - retRc.Left, retRc.Bottom - retRc.Top); 109 | 110 | var args = new GroupPaintEventArgs(i - 1, g, groupRect); 111 | OnPaint(args); 112 | } 113 | } 114 | finally 115 | { 116 | Marshal.FreeHGlobal(lParam); 117 | } 118 | } 119 | 120 | private int GetGroupId(int i) 121 | { 122 | var lvGroupSize = Marshal.SizeOf(typeof(LVGROUP_V6)); 123 | var groupInfo = new LVGROUP_V6(lvGroupSize) { mask = LVGF_GROUPID }; 124 | var lParam = Marshal.AllocHGlobal(lvGroupSize); 125 | try 126 | { 127 | Marshal.StructureToPtr(groupInfo, lParam, false); 128 | var retVal = SendMessage(_listView.Handle, LVM_GETGROUPINFOBYINDEX, (IntPtr)i, lParam); 129 | var retGroupInfo = (LVGROUP_V6)Marshal.PtrToStructure(lParam, typeof(LVGROUP_V6)); 130 | if (retVal == IntPtr.Zero) 131 | { 132 | return -1; 133 | } 134 | 135 | return retGroupInfo.iGroupID; 136 | } 137 | finally 138 | { 139 | Marshal.FreeHGlobal(lParam); 140 | } 141 | } 142 | 143 | protected virtual void OnPaint(GroupPaintEventArgs e) 144 | { 145 | if (Paint != null) 146 | Paint.Invoke(this, e); 147 | } 148 | } 149 | 150 | internal delegate void GroupPaintEventHandler(object sender, GroupPaintEventArgs args); 151 | 152 | internal class GroupPaintEventArgs : PaintEventArgs 153 | { 154 | public int GroupId { get; private set; } 155 | 156 | public GroupPaintEventArgs(int groupId, Graphics graphics, Rectangle clipRect) 157 | : base(graphics, clipRect) 158 | { 159 | GroupId = groupId; 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /KeeTheme/Decorators/ListViewHeaderPainter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Runtime.InteropServices; 4 | using System.Windows.Forms; 5 | 6 | namespace KeeTheme.Decorators 7 | { 8 | class ListViewHeaderPainter : ListViewNativeWindow 9 | { 10 | const int LVM_GETHEADER = LVM_FIRST + 0x1F; 11 | 12 | [DllImport("user32.dll")] 13 | static extern bool GetWindowRect(HandleRef hwnd, out RECT lpRect); 14 | 15 | private readonly ListView _listView; 16 | 17 | internal int HeaderHeight { get; private set; } 18 | internal event PaintEventHandler Paint; 19 | 20 | public ListViewHeaderPainter(ListView listView) 21 | { 22 | _listView = listView; 23 | 24 | AssignHeaderHandle(); 25 | _listView.HandleCreated += HandleListViewHandleCreated; 26 | _listView.HandleDestroyed += HandleListViewHandleDestroyed; 27 | } 28 | 29 | private void HandleListViewHandleCreated(object sender, EventArgs e) 30 | { 31 | if (_listView != null) AssignHeaderHandle(); 32 | } 33 | 34 | private void HandleListViewHandleDestroyed(object sender, EventArgs e) 35 | { 36 | ReleaseHandle(); 37 | } 38 | 39 | private void AssignHeaderHandle() 40 | { 41 | var headerHwnd = SendMessage(_listView.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero); 42 | if (headerHwnd != IntPtr.Zero) 43 | { 44 | RECT rect; 45 | if (GetWindowRect(new HandleRef(null, headerHwnd), out rect)) 46 | { 47 | HeaderHeight = rect.Bottom - rect.Top; 48 | } 49 | 50 | AssignHandle(headerHwnd); 51 | } 52 | } 53 | 54 | protected override void WndProc(ref Message m) 55 | { 56 | base.WndProc(ref m); 57 | 58 | if (m.Msg != WM_PAINT) 59 | return; 60 | 61 | var width = 0; 62 | foreach (ColumnHeader column in _listView.Columns) 63 | { 64 | width += column.Width; 65 | } 66 | 67 | using (var g = Graphics.FromHwnd(m.HWnd)) 68 | { 69 | var rect = new Rectangle(width, 0, _listView.ClientSize.Width - width, HeaderHeight); 70 | var args = new PaintEventArgs(g, rect); 71 | OnPaint(args); 72 | } 73 | } 74 | 75 | protected virtual void OnPaint(PaintEventArgs e) 76 | { 77 | if (Paint != null) 78 | Paint.Invoke(this, e); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /KeeTheme/Decorators/ListViewNativeWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Windows.Forms; 4 | 5 | namespace KeeTheme.Decorators 6 | { 7 | class ListViewNativeWindow : NativeWindow 8 | { 9 | [StructLayout(LayoutKind.Sequential)] 10 | internal struct RECT 11 | { 12 | internal int Left; 13 | internal int Top; 14 | internal int Right; 15 | internal int Bottom; 16 | } 17 | 18 | internal const int WM_PAINT = 0x000F; 19 | internal const int LVM_FIRST = 0x1000; 20 | 21 | [DllImport("user32.dll", EntryPoint = "SendMessage")] 22 | internal static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /KeeTheme/Decorators/ObjectListViewDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Windows.Forms; 6 | using KeeTheme.Theme; 7 | 8 | namespace KeeTheme.Decorators 9 | { 10 | internal class ObjectListViewDecorator 11 | { 12 | private static Assembly _brightIdeasSoftwareAssembly; 13 | private static Type _objectListViewType; 14 | private static PropertyInfo _alternateRowBackColorProperty; 15 | private static PropertyInfo _headerUsesThemesProperty; 16 | private static PropertyInfo _headerFormatStyleProperty; 17 | 18 | private static Type _headerFormatStyleType; 19 | private static MethodInfo _setForeColorMethod; 20 | private static MethodInfo _setBackColorMethod; 21 | 22 | private static Type _hyperlinkStyleType; 23 | private static PropertyInfo _hyperlinkStyleProperty; 24 | private static PropertyInfo _hyperlinkStyleNormalProperty; 25 | 26 | private static Type _cellStyleType; 27 | private static PropertyInfo _cellStyleForeColorProperty; 28 | 29 | public static void Initialize() 30 | { 31 | if (_objectListViewType != null) 32 | return; 33 | 34 | _objectListViewType = GetType("BrightIdeasSoftware.ObjectListView"); 35 | if (_objectListViewType == null) 36 | return; 37 | 38 | _brightIdeasSoftwareAssembly = _objectListViewType.Assembly; 39 | _alternateRowBackColorProperty = _objectListViewType.GetProperty("AlternateRowBackColor"); 40 | _headerFormatStyleProperty = _objectListViewType.GetProperty("HeaderFormatStyle"); 41 | _headerUsesThemesProperty = _objectListViewType.GetProperty("HeaderUsesThemes"); 42 | 43 | _headerFormatStyleType = _brightIdeasSoftwareAssembly.GetType("BrightIdeasSoftware.HeaderFormatStyle"); 44 | _setForeColorMethod = _headerFormatStyleType.GetMethod("SetForeColor"); 45 | _setBackColorMethod = _headerFormatStyleType.GetMethod("SetBackColor"); 46 | 47 | _hyperlinkStyleProperty = _objectListViewType.GetProperty("HyperlinkStyle"); 48 | _hyperlinkStyleType = _brightIdeasSoftwareAssembly.GetType("BrightIdeasSoftware.HyperlinkStyle"); 49 | _hyperlinkStyleNormalProperty = _hyperlinkStyleType.GetProperty("Normal"); 50 | _cellStyleType = _brightIdeasSoftwareAssembly.GetType("BrightIdeasSoftware.CellStyle"); 51 | _cellStyleForeColorProperty = _cellStyleType.GetProperty("ForeColor"); 52 | } 53 | 54 | private static Type GetType(string name) 55 | { 56 | return AppDomain.CurrentDomain.GetAssemblies() 57 | .SelectMany(TryGetTypes).FirstOrDefault(x => x.FullName.StartsWith(name)); 58 | } 59 | 60 | private static IEnumerable TryGetTypes(Assembly assembly) 61 | { 62 | try 63 | { 64 | return assembly.GetTypes(); 65 | } 66 | catch (ReflectionTypeLoadException) 67 | { 68 | // If assembly types cannot be loaded - ignore. 69 | return new Type[0]; 70 | } 71 | } 72 | 73 | public static bool CanDecorate(ListView listView) 74 | { 75 | return _objectListViewType != null && _objectListViewType.IsInstanceOfType(listView); 76 | } 77 | 78 | public static void Apply(ListView listView, ITheme theme) 79 | { 80 | _alternateRowBackColorProperty.SetValue(listView, theme.ListView.EvenRowColor, null); 81 | _headerUsesThemesProperty.SetValue(listView, false, null); 82 | 83 | var headerFormatStyle = Activator.CreateInstance(_headerFormatStyleType); 84 | _setForeColorMethod.Invoke(headerFormatStyle, new object[] { theme.ListView.HeaderForeColor }); 85 | _setBackColorMethod.Invoke(headerFormatStyle, new object[] { theme.ListView.HeaderBackColor }); 86 | _headerFormatStyleProperty.SetValue(listView, headerFormatStyle, null); 87 | 88 | var hyperLinkStyle = _hyperlinkStyleProperty.GetValue(listView, null); 89 | if (hyperLinkStyle != null) 90 | { 91 | var hyperLinkNormal = _hyperlinkStyleNormalProperty.GetValue(hyperLinkStyle, null); 92 | _cellStyleForeColorProperty.SetValue(hyperLinkNormal, theme.LinkLabel.LinkColor, null); 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /KeeTheme/Decorators/PwGeneratorMenuDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Windows.Forms; 6 | using KeePass.UI; 7 | 8 | namespace KeeTheme.Decorators 9 | { 10 | public static class PwGeneratorMenuDecorator 11 | { 12 | internal static void TryFindAndDecorate(object sender, KeeTheme keeTheme) 13 | { 14 | if (!keeTheme.Enabled) 15 | return; 16 | 17 | try 18 | { 19 | FindAndDecorate(sender, keeTheme); 20 | } 21 | catch (Exception e) 22 | { 23 | // Ignore because users should be able to use KeePass anyways. 24 | } 25 | } 26 | 27 | private static void FindAndDecorate(object sender, KeeTheme keeTheme) 28 | { 29 | var fields = sender.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic); 30 | var pwGeneratorMenuField = fields.FirstOrDefault(x => x.FieldType.Name == "PwGeneratorMenu"); 31 | if (pwGeneratorMenuField == null) 32 | return; 33 | 34 | var pwGeneratorMenuType = pwGeneratorMenuField.FieldType; 35 | var pwGeneratorMenu = pwGeneratorMenuField.GetValue(sender); 36 | 37 | var btnHostField = pwGeneratorMenuType.GetField("m_btnHost", BindingFlags.Instance | BindingFlags.NonPublic); 38 | var btnHost = (Button) btnHostField.GetValue(pwGeneratorMenu); 39 | 40 | var onHostBtnClickMethod = 41 | pwGeneratorMenuType.GetMethod("OnHostBtnClick", BindingFlags.Instance | BindingFlags.NonPublic); 42 | var onHostBtnClick = Delegate.CreateDelegate(typeof(EventHandler), pwGeneratorMenu, onHostBtnClickMethod.Name); 43 | 44 | var eventInstance = typeof(Control) 45 | .GetField("EventClick", BindingFlags.Static | BindingFlags.NonPublic).GetValue(btnHost); 46 | 47 | var eventHandlerList = (EventHandlerList) typeof(Button) 48 | .GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(btnHost, null); 49 | 50 | eventHandlerList.RemoveHandler(eventInstance, onHostBtnClick); 51 | 52 | var constructContextMenuMethod = 53 | pwGeneratorMenuType.GetMethod("ConstructContextMenu", BindingFlags.Instance | BindingFlags.NonPublic); 54 | 55 | btnHost.Click += (o, args) => 56 | { 57 | constructContextMenuMethod.Invoke(pwGeneratorMenu, null); 58 | var contextMenuField = pwGeneratorMenuType.GetField("m_ctx", BindingFlags.Instance | BindingFlags.NonPublic); 59 | var contextMenu = (CustomContextMenuStripEx) contextMenuField.GetValue(pwGeneratorMenu); 60 | 61 | keeTheme.Apply(contextMenu); 62 | 63 | contextMenu.ShowEx(btnHost); 64 | }; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /KeeTheme/Decorators/RichTextBoxDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | using KeePass.Forms; 6 | using KeePass.UI; 7 | using KeeTheme.Theme; 8 | 9 | namespace KeeTheme.Decorators 10 | { 11 | sealed class RichTextBoxDecorator : Panel 12 | { 13 | private class Link 14 | { 15 | public int Index { get; set; } 16 | public string Text { get; set; } 17 | } 18 | 19 | private readonly List _detectedLinks = new List(); 20 | private string _lastText; 21 | 22 | private readonly RichTextBox _richTextBox; 23 | private readonly RichTextBoxNativeWindow _richTextBoxNativeWindow; 24 | 25 | private ITheme _theme; 26 | private bool _enabled; 27 | 28 | public RichTextBoxDecorator(RichTextBox richTextBox, ITheme theme) 29 | { 30 | _theme = theme; 31 | _richTextBox = richTextBox; 32 | 33 | Padding = new Padding(1); 34 | Location = richTextBox.Location; 35 | Size = richTextBox.Size; 36 | Dock = richTextBox.Dock; 37 | 38 | // RichTextBox.BorderStyle.FixedSingle doesn't work 39 | var parent = richTextBox.Parent; 40 | var index = parent.Controls.GetChildIndex(richTextBox); 41 | parent.Controls.Remove(richTextBox); 42 | parent.Controls.Add(this); 43 | parent.Controls.SetChildIndex(this, index); 44 | BorderStyle = _theme.RichTextBox.BorderStyle; 45 | richTextBox.BorderStyle = BorderStyle.None; 46 | richTextBox.Location = Point.Empty; 47 | Controls.Add(richTextBox); 48 | EnabledChanged += HandleEnabledChanged; 49 | 50 | if (Parent.GetType() == typeof(DataEditorForm)) 51 | { 52 | // Original font colors should be kept in the attachment viewer RTF document 53 | var customRichTextBox = richTextBox as CustomRichTextBoxEx; 54 | if (customRichTextBox != null && customRichTextBox.SimpleTextOnly) 55 | richTextBox.TextChanged += HandleRichTextBoxTextChanged; 56 | } 57 | else 58 | { 59 | // An exception for custom keystroke sequence in EditAutoTypeItemForm 60 | // Original font color should be kept to indicate valid and invalid placeholders 61 | if (richTextBox.Name != "m_rbKeySeq") 62 | { 63 | richTextBox.TextChanged += HandleRichTextBoxTextChanged; 64 | } 65 | _richTextBoxNativeWindow = new RichTextBoxNativeWindow(richTextBox); 66 | _richTextBoxNativeWindow.Paint += HandleRichTextBoxPaint; 67 | _richTextBoxNativeWindow.LinkCreated += HandleRichTextBoxLinkCreated; 68 | HandleTabStop(richTextBox); 69 | richTextBox.TabStopChanged += HandleTabStopChanges; 70 | richTextBox.TabIndexChanged += HandleTabStopChanges; 71 | } 72 | 73 | richTextBox.DockChanged += HandleRichTextBoxDockChanged; 74 | richTextBox.SizeChanged += HandleRichTextBoxSizeChanged; 75 | SizeChanged += HandleSizeChanged; 76 | } 77 | 78 | private void HandleSizeChanged(object sender, EventArgs e) 79 | { 80 | _richTextBox.Size = Size; 81 | } 82 | 83 | private void HandleRichTextBoxSizeChanged(object sender, EventArgs e) 84 | { 85 | Control c = sender as Control; 86 | if (c == null) return; 87 | Size = c.Size; 88 | } 89 | 90 | private void HandleTabStopChanges(object sender, EventArgs e) 91 | { 92 | HandleTabStop(sender as RichTextBox); 93 | } 94 | 95 | private void HandleTabStop(RichTextBox richTextBox) 96 | { 97 | if (richTextBox == null) return; 98 | TabStop = richTextBox.TabStop; 99 | TabIndex = richTextBox.TabIndex; 100 | } 101 | 102 | private void HandleRichTextBoxLinkCreated(object sender, EventArgs e) 103 | { 104 | var customRichTextBox = sender as CustomRichTextBoxEx; 105 | if (customRichTextBox == null) 106 | return; 107 | 108 | var link = new Link(); 109 | link.Index = customRichTextBox.SelectionStart; 110 | link.Text = customRichTextBox.Text.Substring(link.Index, customRichTextBox.SelectionLength); 111 | _detectedLinks.Add(link); 112 | } 113 | 114 | private void HandleRichTextBoxPaint(object sender, PaintEventArgs e) 115 | { 116 | var customRichTextBox = sender as CustomRichTextBoxEx; 117 | if (customRichTextBox == null || customRichTextBox.Text.Length == 0 || !_enabled) 118 | return; 119 | 120 | using (var font = new Font(customRichTextBox.Font, FontStyle.Underline)) 121 | { 122 | foreach (var link in _detectedLinks) 123 | { 124 | DrawLink(customRichTextBox, link, e.Graphics, font); 125 | } 126 | } 127 | } 128 | 129 | private void DrawLink(CustomRichTextBoxEx customRichTextBox, Link link, Graphics graphics, Font font) 130 | { 131 | var ranges = Subtract(link.Index, link.Text.Length, customRichTextBox.SelectionStart, 132 | customRichTextBox.SelectionLength); 133 | 134 | foreach (var range in ranges) 135 | { 136 | var linkText = link.Text.Substring(range.First - link.Index, range.Length); 137 | var startPoint = customRichTextBox.GetPositionFromCharIndex(range.First); 138 | var textSize = TextRenderer.MeasureText(linkText, font); 139 | using (var brush = new SolidBrush(customRichTextBox.BackColor)) 140 | { 141 | graphics.FillRectangle(brush, new Rectangle(startPoint, textSize)); 142 | } 143 | TextRenderer.DrawText(graphics, linkText, font, startPoint, _theme.LinkLabel.LinkColor); 144 | } 145 | } 146 | 147 | private List Subtract(int linkStart, int linkLength, int selectionStart, int selectionLength) 148 | { 149 | var linkEnd = linkStart + linkLength; 150 | var selectionEnd = selectionStart + selectionLength; 151 | 152 | // Empty selection or selection not in range of link 153 | if (selectionLength == 0 || linkStart > selectionEnd || linkEnd < selectionStart) 154 | { 155 | var range = new CharacterRange(linkStart, linkLength); 156 | return new List { range }; 157 | } 158 | 159 | // Selection overlaps whole link 160 | if (selectionStart <= linkStart && selectionEnd >= linkEnd) 161 | return new List(); 162 | 163 | // Selection starts before link and ends inside link 164 | if (selectionStart <= linkStart && selectionEnd < linkEnd) 165 | { 166 | var result = new CharacterRange(selectionEnd, linkEnd - selectionEnd); 167 | return new List { result }; 168 | } 169 | 170 | // Selection starts inside link and ends after link 171 | if (selectionStart > linkStart && selectionEnd >= linkEnd) 172 | { 173 | var result = new CharacterRange(linkStart, selectionStart - linkStart); 174 | return new List { result }; 175 | } 176 | 177 | // Selection is inside link 178 | var result1 = new CharacterRange(linkStart, selectionStart - linkStart); 179 | var result2 = new CharacterRange(selectionEnd, linkEnd - selectionEnd); 180 | return new List { result1, result2 }; 181 | } 182 | 183 | private void HandleRichTextBoxDockChanged(object sender, EventArgs e) 184 | { 185 | Dock = ((RichTextBox) sender).Dock; 186 | } 187 | 188 | private void HandleEnabledChanged(object sender, EventArgs e) 189 | { 190 | if (_enabled) 191 | ControlSnapshot.Make(_richTextBox); 192 | } 193 | 194 | private void HandleRichTextBoxTextChanged(object sender, EventArgs e) 195 | { 196 | if (!_enabled) 197 | return; 198 | 199 | var richTextBox = (RichTextBox)sender; 200 | ApplyFontColor(richTextBox); 201 | if (_lastText != richTextBox.Text) 202 | { 203 | _lastText = richTextBox.Text; 204 | _detectedLinks.Clear(); 205 | } 206 | } 207 | 208 | private void ApplyFontColor(RichTextBox richTextBox) 209 | { 210 | var selectionStart = richTextBox.SelectionStart; 211 | var selectionLength = richTextBox.SelectionLength; 212 | 213 | richTextBox.SelectAll(); 214 | richTextBox.SelectionColor = _theme.RichTextBox.SelectionColor; 215 | richTextBox.Select(selectionStart, selectionLength); 216 | } 217 | 218 | public void EnableTheme(bool enabled, ITheme theme) 219 | { 220 | _theme = theme; 221 | _enabled = enabled; 222 | if (!enabled) 223 | ApplyFontColor(_richTextBox); 224 | 225 | BorderStyle = _theme.RichTextBox.BorderStyle; 226 | } 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /KeeTheme/Decorators/RichTextBoxNativeWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Runtime.InteropServices; 4 | using System.Windows.Forms; 5 | 6 | namespace KeeTheme.Decorators 7 | { 8 | class RichTextBoxNativeWindow : NativeWindow 9 | { 10 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 11 | internal struct CHARFORMAT2 12 | { 13 | public UInt32 cbSize; 14 | public UInt32 dwMask; 15 | public UInt32 dwEffects; 16 | public Int32 yHeight; 17 | public Int32 yOffset; 18 | public UInt32 crTextColor; 19 | public Byte bCharSet; 20 | public Byte bPitchAndFamily; 21 | 22 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] 23 | public string szFaceName; 24 | 25 | public UInt16 wWeight; 26 | public UInt16 sSpacing; 27 | public Int32 crBackColor; 28 | public Int32 lcid; 29 | public UInt32 dwReserved; 30 | public Int16 sStyle; 31 | public Int16 wKerning; 32 | public Byte bUnderlineType; 33 | public Byte bAnimation; 34 | public Byte bRevAuthor; 35 | public Byte bReserved1; 36 | } 37 | 38 | private const int WM_SETFOCUS = 0x0007; 39 | private const int WM_ENABLE = 0x000A; 40 | private const int WM_PAINT = 0x000F; 41 | private const int WM_SETCURSOR = 0x0020; 42 | private const int WM_USER = 0x0400; 43 | private const int EM_SETCHARFORMAT = WM_USER + 68; 44 | private const uint CFE_LINK = 0x0020; 45 | 46 | private readonly RichTextBox _richTextBox; 47 | private bool _enabled; 48 | 49 | internal event PaintEventHandler Paint; 50 | internal event EventHandler LinkCreated; 51 | 52 | public RichTextBoxNativeWindow(RichTextBox richTextBox) 53 | { 54 | _richTextBox = richTextBox; 55 | _enabled = richTextBox.Enabled; 56 | if (TryAssignHandle(_richTextBox.Handle)) 57 | { 58 | _richTextBox.HandleCreated += HandleRichTextBoxHandleCreated; 59 | _richTextBox.HandleDestroyed += HandleRichTextBoxHandleDestroyed; 60 | } 61 | } 62 | 63 | private bool TryAssignHandle(IntPtr handle) 64 | { 65 | try 66 | { 67 | AssignHandle(handle); 68 | return true; 69 | } 70 | catch (InvalidOperationException e) 71 | { 72 | return false; 73 | } 74 | } 75 | 76 | private void HandleRichTextBoxHandleCreated(object sender, EventArgs e) 77 | { 78 | if (_richTextBox != null) 79 | AssignHandle(_richTextBox.Handle); 80 | } 81 | 82 | private void HandleRichTextBoxHandleDestroyed(object sender, EventArgs e) 83 | { 84 | ReleaseHandle(); 85 | } 86 | 87 | protected override void WndProc(ref Message m) 88 | { 89 | if (m.Msg == WM_ENABLE) 90 | { 91 | _enabled = m.WParam != IntPtr.Zero; 92 | m.WParam = new IntPtr(1); 93 | } 94 | 95 | if (_enabled || m.Msg != WM_SETFOCUS && m.Msg != WM_SETCURSOR) 96 | { 97 | base.WndProc(ref m); 98 | } 99 | 100 | if (m.Msg == EM_SETCHARFORMAT) 101 | { 102 | var cf = (CHARFORMAT2) Marshal.PtrToStructure(m.LParam, typeof(CHARFORMAT2)); 103 | if ((cf.dwEffects & CFE_LINK) != 0) 104 | { 105 | var args = new EventArgs(); 106 | OnLinkCreated(args); 107 | } 108 | } 109 | 110 | if (m.Msg == WM_PAINT) 111 | { 112 | using (var g = Graphics.FromHwnd(m.HWnd)) 113 | { 114 | var rect = new Rectangle(0, 0, _richTextBox.ClientSize.Width, _richTextBox.ClientSize.Height); 115 | var args = new PaintEventArgs(g, rect); 116 | OnPaint(args); 117 | } 118 | } 119 | } 120 | 121 | protected virtual void OnLinkCreated(EventArgs e) 122 | { 123 | if (LinkCreated != null) 124 | LinkCreated.Invoke(_richTextBox, e); 125 | } 126 | 127 | protected virtual void OnPaint(PaintEventArgs e) 128 | { 129 | if (Paint != null) 130 | Paint.Invoke(_richTextBox, e); 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /KeeTheme/Decorators/SplitButtonExDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.Reflection; 6 | using System.Windows.Forms; 7 | using KeePass.UI; 8 | using KeeTheme.Theme; 9 | 10 | namespace KeeTheme.Decorators 11 | { 12 | internal class SplitButtonExDecorator : Control 13 | { 14 | const string EventClick = "EventClick"; 15 | 16 | private ITheme _theme; 17 | private bool _enabled; 18 | 19 | private readonly SplitButtonEx _button; 20 | private readonly ContentAlignment _imageAlign; 21 | private readonly Image _image; 22 | private readonly EventHandler _clickHandler; 23 | 24 | public SplitButtonExDecorator(SplitButtonEx button, ITheme theme) 25 | { 26 | _button = button; 27 | _theme = theme; 28 | 29 | _imageAlign = button.ImageAlign; 30 | _image = button.Image; 31 | _clickHandler = (EventHandler) GetClickEvent(_button); 32 | 33 | button.Controls.Add(this); 34 | } 35 | 36 | private static void RemoveClickEvent(SplitButtonEx button) 37 | { 38 | try 39 | { 40 | var eventInstance = typeof(Control) 41 | .GetField(EventClick, BindingFlags.Static | BindingFlags.NonPublic).GetValue(button); 42 | 43 | var list = (EventHandlerList) typeof(SplitButtonEx) 44 | .GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(button, null); 45 | 46 | list.RemoveHandler(eventInstance, list[eventInstance]); 47 | } 48 | catch (NullReferenceException) 49 | { 50 | } 51 | } 52 | 53 | private static object GetClickEvent(Component button) 54 | { 55 | try 56 | { 57 | var privateBinding = BindingFlags.Instance | BindingFlags.NonPublic; 58 | var key = typeof(Control) 59 | .GetField(EventClick, BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); 60 | 61 | var events = typeof(Component).GetField("events", privateBinding).GetValue(button); 62 | var listEntry = typeof(EventHandlerList).GetMethod("Find", privateBinding).Invoke(events, new [] {key}); 63 | var handler = listEntry.GetType().GetField("handler", privateBinding).GetValue(listEntry); 64 | return handler; 65 | } 66 | catch (ArgumentNullException) 67 | { 68 | return null; 69 | } 70 | catch (NullReferenceException) 71 | { 72 | return null; 73 | } 74 | } 75 | 76 | private void HandleButtonMouseClick(object sender, MouseEventArgs e) 77 | { 78 | var rect = new Rectangle(_button.Width - 20, 0, 20, _button.Height); 79 | if (rect.Contains(e.Location)) 80 | { 81 | _button.SplitDropDownMenu.ShowEx(_button); 82 | // The menu is not showing for the first time. I've got no idea why. 83 | if (!_button.SplitDropDownMenu.Visible) 84 | _button.SplitDropDownMenu.ShowEx(_button); 85 | } 86 | else 87 | { 88 | if (_clickHandler != null) 89 | _clickHandler(this, e); 90 | } 91 | } 92 | 93 | private Image GetButtonDownArrow() 94 | { 95 | var bitmap = new Bitmap(16, 16); 96 | using (var g = Graphics.FromImage(bitmap)) 97 | using (var brush = new SolidBrush(ForeColor)) 98 | { 99 | g.SmoothingMode = SmoothingMode.AntiAlias; 100 | g.FillPolygon(brush, new[] {new Point(4, 6), new Point(12, 6), new Point(8, 10)}); 101 | } 102 | 103 | return bitmap; 104 | } 105 | 106 | public void EnableTheme(bool enabled, ITheme theme) 107 | { 108 | _enabled = enabled; 109 | _theme = theme; 110 | 111 | Apply(_button); 112 | } 113 | 114 | private void Apply(SplitButtonEx button) 115 | { 116 | if (_theme.Button.FlatStyle == FlatStyle.System) 117 | return; 118 | 119 | if (_enabled) 120 | { 121 | button.ImageAlign = ContentAlignment.MiddleRight; 122 | button.Image = GetButtonDownArrow(); 123 | button.MouseClick += HandleButtonMouseClick; 124 | RemoveClickEvent(_button); 125 | } 126 | else 127 | { 128 | button.ImageAlign = _imageAlign; 129 | button.Image = _image; 130 | button.MouseClick -= HandleButtonMouseClick; 131 | button.Click += _clickHandler; 132 | } 133 | } 134 | } 135 | } -------------------------------------------------------------------------------- /KeeTheme/Editor/ColorConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Globalization; 5 | using KeeTheme.Theme; 6 | 7 | namespace KeeTheme.Editor 8 | { 9 | public class ColorConverter : TypeConverter 10 | { 11 | // This is used, for example, by DefaultValueAttribute to convert from string to Color. 12 | public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 13 | { 14 | if (value.GetType() == typeof(string)) 15 | return Palette.ParseColor((string)value); 16 | 17 | return base.ConvertFrom(context, culture, value); 18 | } 19 | 20 | // This is used, for example, by the PropertyGrid to convert Color to a string. 21 | public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destType) 22 | { 23 | if (destType == typeof(string) && value is Color) 24 | { 25 | var color = (Color) value; 26 | if (color == Color.Empty) 27 | return ""; 28 | 29 | return '#' + color.R.ToString("X2") + color.G.ToString("X2") + color.B.ToString("X2"); 30 | } 31 | return base.ConvertTo(context, culture, value, destType); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /KeeTheme/Editor/ColorEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Drawing.Design; 5 | using System.Windows.Forms; 6 | using System.Windows.Forms.Design; 7 | using KeeTheme.Theme; 8 | 9 | namespace KeeTheme.Editor 10 | { 11 | public class ColorEditor : UITypeEditor 12 | { 13 | private IWindowsFormsEditorService _service; 14 | 15 | public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) 16 | { 17 | // This tells it to show the [...] button which is clickable firing off EditValue below. 18 | return UITypeEditorEditStyle.Modal; 19 | } 20 | 21 | public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) 22 | { 23 | if (provider != null) 24 | _service = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); 25 | 26 | if (_service != null && context != null) 27 | { 28 | var colorDialog = new ColorDialog(); 29 | colorDialog.AllowFullOpen = true; 30 | colorDialog.FullOpen = true; 31 | colorDialog.AnyColor = true; 32 | colorDialog.Color = (Color) value; 33 | colorDialog.CustomColors = GetPaletteColors(context); 34 | if (colorDialog.ShowDialog() == DialogResult.OK); 35 | { 36 | value = colorDialog.Color; 37 | SetPaletteColors(context, colorDialog.CustomColors); 38 | } 39 | } 40 | 41 | return value; 42 | } 43 | 44 | private void SetPaletteColors(ITypeDescriptorContext context, int[] colorDialogCustomColors) 45 | { 46 | var ownerGridProperty = context.GetType().GetProperty("OwnerGrid"); 47 | if (ownerGridProperty == null) 48 | return; 49 | 50 | var propertyGrid = (PropertyGrid) ownerGridProperty.GetValue(context, null); 51 | var customThemeTemplate = (CustomThemeTemplate) propertyGrid.SelectedObject; 52 | var palette = customThemeTemplate.Palette; 53 | palette.FromBgrArray(colorDialogCustomColors); 54 | } 55 | 56 | private int[] GetPaletteColors(ITypeDescriptorContext context) 57 | { 58 | var ownerGridProperty = context.GetType().GetProperty("OwnerGrid"); 59 | if (ownerGridProperty == null) 60 | return new int[0]; 61 | 62 | var propertyGrid = (PropertyGrid) ownerGridProperty.GetValue(context, null); 63 | var customThemeTemplate = (CustomThemeTemplate) propertyGrid.SelectedObject; 64 | var palette = customThemeTemplate.Palette; 65 | return palette.ToBgrArray(); 66 | } 67 | 68 | public override bool GetPaintValueSupported(ITypeDescriptorContext context) 69 | { 70 | return true; 71 | } 72 | 73 | public override void PaintValue(PaintValueEventArgs e) 74 | { 75 | using (var brush = new SolidBrush((Color)e.Value)) 76 | e.Graphics.FillRectangle(brush, e.Bounds); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /KeeTheme/Editor/GenericTypeConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using KeeTheme.Theme; 4 | 5 | namespace KeeTheme.Editor 6 | { 7 | internal class GenericTypeConverter : TypeConverter 8 | { 9 | public override bool GetPropertiesSupported(ITypeDescriptorContext context) 10 | { 11 | return true; 12 | } 13 | 14 | public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) 15 | { 16 | return TypeDescriptor.GetProperties(typeof(T)); 17 | } 18 | } 19 | 20 | internal class OtherLookTypeConverter : GenericTypeConverter 21 | { 22 | } 23 | 24 | internal class MenuLookTypeConverter : GenericTypeConverter 25 | { 26 | } 27 | 28 | internal class ListViewLookTypeConverter : GenericTypeConverter 29 | { 30 | } 31 | 32 | internal class LinkLabelLookTypeConverter : GenericTypeConverter 33 | { 34 | } 35 | 36 | internal class RichTextBoxLookTypeConverter : GenericTypeConverter 37 | { 38 | } 39 | 40 | internal class TreeViewLookTypeConverter : GenericTypeConverter 41 | { 42 | } 43 | 44 | internal class ControlLookTypeConverter : GenericTypeConverter 45 | { 46 | } 47 | 48 | internal class CheckBoxLookTypeConverter : GenericTypeConverter 49 | { 50 | } 51 | 52 | internal class CheckBoxButtonLookTypeConverter : GenericTypeConverter 53 | { 54 | } 55 | 56 | internal class ButtonLookTypeConverter : GenericTypeConverter 57 | { 58 | } 59 | 60 | internal class ToolStripLookTypeConverter : GenericTypeConverter 61 | { 62 | } 63 | 64 | internal class PropertyGridLookTypeConverter : GenericTypeConverter 65 | { 66 | } 67 | } -------------------------------------------------------------------------------- /KeeTheme/Editor/TemplateEditorForm.Designer.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace KeeTheme.Editor 4 | { 5 | partial class TemplateEditorForm 6 | { 7 | /// 8 | /// Required designer variable. 9 | /// 10 | private IContainer components = null; 11 | 12 | /// 13 | /// Clean up any resources being used. 14 | /// 15 | /// true if managed resources should be disposed; otherwise, false. 16 | protected override void Dispose(bool disposing) 17 | { 18 | if (disposing && (components != null)) 19 | { 20 | components.Dispose(); 21 | } 22 | 23 | base.Dispose(disposing); 24 | } 25 | 26 | #region Windows Form Designer generated code 27 | 28 | /// 29 | /// Required method for Designer support - do not modify 30 | /// the contents of this method with the code editor. 31 | /// 32 | private void InitializeComponent() 33 | { 34 | this.propertyGrid = new System.Windows.Forms.PropertyGrid(); 35 | this.loadButton = new System.Windows.Forms.Button(); 36 | this.saveButton = new System.Windows.Forms.Button(); 37 | this.previewButton = new System.Windows.Forms.Button(); 38 | this.SuspendLayout(); 39 | // 40 | // propertyGrid 41 | // 42 | this.propertyGrid.Anchor = ((System.Windows.Forms.AnchorStyles) ((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); 43 | this.propertyGrid.Location = new System.Drawing.Point(0, 0); 44 | this.propertyGrid.Name = "propertyGrid"; 45 | this.propertyGrid.Size = new System.Drawing.Size(364, 400); 46 | this.propertyGrid.TabIndex = 0; 47 | // 48 | // loadButton 49 | // 50 | this.loadButton.Anchor = ((System.Windows.Forms.AnchorStyles) ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 51 | this.loadButton.Location = new System.Drawing.Point(93, 406); 52 | this.loadButton.Name = "loadButton"; 53 | this.loadButton.Size = new System.Drawing.Size(75, 23); 54 | this.loadButton.TabIndex = 1; 55 | this.loadButton.Text = "Load"; 56 | this.loadButton.UseVisualStyleBackColor = true; 57 | this.loadButton.Click += new System.EventHandler(this.HandleLoadButtonClick); 58 | // 59 | // saveButton 60 | // 61 | this.saveButton.Anchor = ((System.Windows.Forms.AnchorStyles) ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 62 | this.saveButton.Location = new System.Drawing.Point(12, 406); 63 | this.saveButton.Name = "saveButton"; 64 | this.saveButton.Size = new System.Drawing.Size(75, 23); 65 | this.saveButton.TabIndex = 2; 66 | this.saveButton.Text = "Save"; 67 | this.saveButton.UseVisualStyleBackColor = true; 68 | this.saveButton.Click += new System.EventHandler(this.HandleSaveButtonClick); 69 | // 70 | // previewButton 71 | // 72 | this.previewButton.Anchor = ((System.Windows.Forms.AnchorStyles) ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); 73 | this.previewButton.Location = new System.Drawing.Point(277, 406); 74 | this.previewButton.Name = "previewButton"; 75 | this.previewButton.Size = new System.Drawing.Size(75, 23); 76 | this.previewButton.TabIndex = 3; 77 | this.previewButton.Text = "Preview"; 78 | this.previewButton.UseVisualStyleBackColor = true; 79 | this.previewButton.Click += new System.EventHandler(this.HandlePreviewButtonClick); 80 | // 81 | // TemplateEditorForm 82 | // 83 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 84 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 85 | this.ClientSize = new System.Drawing.Size(364, 441); 86 | this.Controls.Add(this.previewButton); 87 | this.Controls.Add(this.saveButton); 88 | this.Controls.Add(this.loadButton); 89 | this.Controls.Add(this.propertyGrid); 90 | this.MinimumSize = new System.Drawing.Size(280, 280); 91 | this.Name = "TemplateEditorForm"; 92 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 93 | this.Text = "KeeTheme Editor"; 94 | this.ResumeLayout(false); 95 | } 96 | 97 | private System.Windows.Forms.Button loadButton; 98 | private System.Windows.Forms.Button saveButton; 99 | private System.Windows.Forms.Button previewButton; 100 | 101 | private System.Windows.Forms.PropertyGrid propertyGrid; 102 | 103 | #endregion 104 | } 105 | } -------------------------------------------------------------------------------- /KeeTheme/Editor/TemplateEditorForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | using System.Drawing.Design; 5 | using System.IO; 6 | using System.Threading; 7 | using System.Windows.Forms; 8 | using KeePassLib.Utility; 9 | using KeeTheme.Options; 10 | using KeeTheme.Theme; 11 | 12 | namespace KeeTheme.Editor 13 | { 14 | public partial class TemplateEditorForm : Form 15 | { 16 | private static TemplateEditorForm _instance; 17 | private static Thread _thread; 18 | 19 | public static TemplateEditorForm Instance 20 | { 21 | get { return _instance; } 22 | } 23 | 24 | public event EventHandler PreviewButtonClick 25 | { 26 | add { previewButton.Click += value; } 27 | remove { previewButton.Click -= value; } 28 | } 29 | 30 | private readonly KeeThemeOptions _options; 31 | private readonly string _template; 32 | private readonly string _tempFileName; 33 | 34 | private CustomThemeTemplate _customTheme; 35 | private bool _previewMode; 36 | 37 | static TemplateEditorForm() 38 | { 39 | TypeDescriptor.AddAttributes(typeof(Color), new TypeConverterAttribute(typeof(ColorConverter))); 40 | TypeDescriptor.AddAttributes(typeof(Color), new EditorAttribute(typeof(ColorEditor), typeof(UITypeEditor))); 41 | TypeDescriptor.AddAttributes(typeof(Color), new DefaultValueAttribute(typeof(Color), "Empty")); 42 | TypeDescriptor.AddAttributes(typeof(FlatStyle), new DefaultValueAttribute(FlatStyle.Flat)); 43 | TypeDescriptor.AddAttributes(typeof(BorderStyle), new DefaultValueAttribute(BorderStyle.None)); 44 | } 45 | 46 | private TemplateEditorForm(CustomThemeTemplate customTheme, KeeThemeOptions options) 47 | { 48 | _customTheme = customTheme; 49 | _options = options; 50 | _template = options.Template; 51 | _tempFileName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); 52 | 53 | InitializeComponent(); 54 | 55 | propertyGrid.SelectedObject = _customTheme; 56 | 57 | Closed += HandleClosed; 58 | } 59 | 60 | private void HandleClosed(object sender, EventArgs e) 61 | { 62 | if (_previewMode) 63 | { 64 | _options.Template = _template; 65 | } 66 | 67 | _instance = null; 68 | } 69 | 70 | private void HandleLoadButtonClick(object sender, EventArgs e) 71 | { 72 | using (var fileDialog = new OpenFileDialog()) 73 | { 74 | fileDialog.DefaultExt = "ini"; 75 | fileDialog.Filter = @"KeeTheme template (*.ini)|*.ini"; 76 | fileDialog.InitialDirectory = TemplateReader.GetTemplatesDir(); 77 | if (fileDialog.ShowDialog() == DialogResult.OK) 78 | { 79 | var template = TemplateReader.Get("file:" + fileDialog.FileName); 80 | if (template == null || TemplateReader.GetTemplateName(fileDialog.FileName) == null) 81 | { 82 | MessageService.ShowWarning("Unable to load template from file:", fileDialog.FileName); 83 | return; 84 | } 85 | 86 | _customTheme = new CustomThemeTemplate(template); 87 | propertyGrid.SelectedObject = _customTheme; 88 | _previewMode = false; 89 | } 90 | } 91 | } 92 | 93 | private void HandleSaveButtonClick(object sender, EventArgs e) 94 | { 95 | using (var fileDialog = new SaveFileDialog()) 96 | { 97 | fileDialog.DefaultExt = "ini"; 98 | fileDialog.Filter = @"KeeTheme template (*.ini)|*.ini"; 99 | fileDialog.InitialDirectory = TemplateReader.GetTemplatesDir(); 100 | if (fileDialog.ShowDialog() == DialogResult.OK) 101 | { 102 | var iniFile = _customTheme.GetIniFile(); 103 | iniFile.SaveFile(fileDialog.FileName); 104 | _options.Template = _template; 105 | _options.Template = "file:" + fileDialog.FileName; 106 | _previewMode = false; 107 | Close(); 108 | } 109 | } 110 | } 111 | 112 | private void HandlePreviewButtonClick(object sender, EventArgs e) 113 | { 114 | const string previewSuffix = "(preview)"; 115 | var name = _customTheme.Name; 116 | if (!_customTheme.Name.EndsWith(previewSuffix)) 117 | _customTheme.Name += " " + previewSuffix; 118 | 119 | var iniFile = _customTheme.GetIniFile(); 120 | _customTheme.Name = name; 121 | iniFile.SaveFile(_tempFileName); 122 | _options.Template = _template; 123 | _options.Template = "file:" + _tempFileName; 124 | 125 | _previewMode = true; 126 | } 127 | 128 | public static TemplateEditorForm Create(KeeThemeOptions options) 129 | { 130 | if (_instance != null) 131 | return _instance; 132 | 133 | var theme = new CustomThemeTemplate(TemplateReader.Get(options.Template)); 134 | _instance = new TemplateEditorForm(theme, options); 135 | return _instance; 136 | } 137 | } 138 | } -------------------------------------------------------------------------------- /KeeTheme/Editor/TemplateEditorForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /KeeTheme/FormAddedEventHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | namespace KeeTheme 4 | { 5 | public delegate void FormAddedEventHandler(object sender, FormAddedEventArgs args); 6 | 7 | public class FormAddedEventArgs 8 | { 9 | public Form Form { get; set; } 10 | 11 | public FormAddedEventArgs(Form form) 12 | { 13 | Form = form; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /KeeTheme/FormsArrayList.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Windows.Forms; 3 | 4 | namespace KeeTheme 5 | { 6 | public class FormsArrayList : ArrayList 7 | { 8 | public event FormAddedEventHandler Added; 9 | 10 | public override int Add(object value) 11 | { 12 | var args = new FormAddedEventArgs((Form) value); 13 | if (Added != null) 14 | Added.Invoke(this, args); 15 | return base.Add(value); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /KeeTheme/KeeTheme.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Runtime.InteropServices; 8 | using System.Windows.Forms; 9 | using System.Windows.Forms.VisualStyles; 10 | using KeePass.App; 11 | using KeePass.UI; 12 | using KeePassLib.Utility; 13 | using KeeTheme.Decorators; 14 | using KeeTheme.Options; 15 | using KeeTheme.Theme; 16 | 17 | namespace KeeTheme 18 | { 19 | internal class KeeTheme 20 | { 21 | private readonly KeeThemeOptions _options; 22 | private readonly CustomTheme _defaultTheme; 23 | 24 | private ITheme _customTheme; 25 | private ITheme _theme; 26 | private bool _enabled; 27 | 28 | public bool Enabled 29 | { 30 | get { return _enabled; } 31 | set { SetEnable(value); } 32 | } 33 | 34 | public string Name 35 | { 36 | get { return _customTheme.Name; } 37 | } 38 | 39 | public KeeTheme(KeeThemeOptions options) 40 | { 41 | _options = options; 42 | _defaultTheme = CustomTheme.GetDefaultTheme(); 43 | _customTheme = GetCustomTheme(); 44 | _theme = _defaultTheme; 45 | } 46 | 47 | private void SetEnable(bool enable) 48 | { 49 | _enabled = enable; 50 | 51 | if (_enabled) 52 | _customTheme = GetCustomTheme(); 53 | 54 | _theme = _enabled ? _customTheme : _defaultTheme; 55 | 56 | ToolStripManager.Renderer = _theme.ToolStripRenderer; 57 | ObjectListViewDecorator.Initialize(); 58 | KnownColorsDecorator.Apply(_theme, _enabled); 59 | 60 | ApplyOther(); 61 | } 62 | 63 | private ITheme GetCustomTheme() 64 | { 65 | var templateFile = TemplateReader.Get(_options.Template) ?? TemplateReader.GetDefaultTemplate(); 66 | var themeTemplate = new CustomThemeTemplate(templateFile); 67 | return new CustomTheme(themeTemplate); 68 | } 69 | 70 | private void ApplyOther() 71 | { 72 | var colorControlNormalField = 73 | typeof(AppDefs).GetField("ColorControlNormal", BindingFlags.Static | BindingFlags.Public); 74 | var colorControlDisabledField = 75 | typeof(AppDefs).GetField("ColorControlDisabled", BindingFlags.Static | BindingFlags.Public); 76 | var colorEditError = 77 | typeof(AppDefs).GetField("ColorEditError", BindingFlags.Static | BindingFlags.Public); 78 | 79 | if (colorControlNormalField != null) 80 | colorControlNormalField.SetValue(null, _theme.Other.ControlNormalColor); 81 | 82 | if (colorControlDisabledField != null) 83 | colorControlDisabledField.SetValue(null, _theme.Other.ControlDisabledColor); 84 | 85 | if (colorEditError != null) 86 | colorEditError.SetValue(null, _theme.Other.ColorEditError); 87 | } 88 | 89 | public void Apply(Control control) 90 | { 91 | if (control.InvokeRequired) 92 | { 93 | control.Invoke(new MethodInvoker(() => Apply(control))); 94 | } 95 | 96 | if (!(control is ToolStrip)) 97 | { 98 | control.BackColor = _theme.Control.BackColor; 99 | control.ForeColor = _theme.Control.ForeColor; 100 | } 101 | 102 | var form = control as Form; 103 | if (form != null) Apply(form); 104 | 105 | var userControl = control as UserControl; 106 | if (userControl != null) Apply(userControl); 107 | 108 | var dataGridView = control as DataGridView; 109 | if (dataGridView != null) Apply(dataGridView); 110 | 111 | var button = control as Button; 112 | if (button != null) Apply(button); 113 | 114 | var treeView = control as TreeView; 115 | if (treeView != null) Apply(treeView); 116 | 117 | var richTextBox = control as RichTextBox; 118 | if (richTextBox != null) Apply(richTextBox); 119 | 120 | var linkLabel = control as LinkLabel; 121 | if (linkLabel != null) Apply(linkLabel); 122 | 123 | var listView = control as ListView; 124 | if (listView != null) Apply(listView); 125 | 126 | var secureTextBoxEx = control as SecureTextBoxEx; 127 | if (secureTextBoxEx != null) Apply(secureTextBoxEx); 128 | 129 | var hotKeyControlEx = control as HotKeyControlEx; 130 | if (hotKeyControlEx != null) Apply(hotKeyControlEx); 131 | 132 | var toolStrip = control as ToolStrip; 133 | if (toolStrip != null) Apply(toolStrip); 134 | 135 | var menuStrip = control as MenuStrip; 136 | if (menuStrip != null) Apply(menuStrip); 137 | 138 | var contextMenuStrip = control as ContextMenuStrip; 139 | if (contextMenuStrip != null) Apply(contextMenuStrip); 140 | 141 | var statusStrip = control as StatusStrip; 142 | if (statusStrip != null) Apply(statusStrip); 143 | 144 | var tabControl = control as TabControl; 145 | if (tabControl != null) Apply(tabControl); 146 | 147 | var qualityProgressBar = control as QualityProgressBar; 148 | if (qualityProgressBar != null) Apply(qualityProgressBar); 149 | 150 | var comboBox = control as ComboBox; 151 | if (comboBox != null) Apply(comboBox); 152 | 153 | var checkBox = control as CheckBox; 154 | if (checkBox != null) Apply(checkBox); 155 | 156 | var propertyGrid = control as PropertyGrid; 157 | if (propertyGrid != null) Apply(propertyGrid); 158 | 159 | OverrideResetBackground(control); 160 | } 161 | 162 | private void OverrideResetBackground(Control control) 163 | { 164 | if (control.Name == "m_cmbStringName" && control.Parent.Name == "EditStringForm") 165 | { 166 | control.BackColorChanged += (sender, args) => 167 | { 168 | if (control.BackColor.IsSystemColor) 169 | control.BackColor = _theme.Control.BackColor; 170 | }; 171 | } 172 | } 173 | 174 | private void Apply(DataGridView dataGridView) 175 | { 176 | dataGridView.BackgroundColor = _theme.Control.BackColor; 177 | dataGridView.RowsDefaultCellStyle.BackColor = _theme.Control.BackColor; 178 | dataGridView.RowsDefaultCellStyle.ForeColor = _theme.Control.ForeColor; 179 | } 180 | 181 | private void Apply(CheckBox checkBox) 182 | { 183 | var checkBoxLook = checkBox.Appearance == Appearance.Button 184 | ? _theme.CheckBoxButton 185 | : _theme.CheckBox; 186 | 187 | checkBox.BackColor = checkBoxLook.BackColor; 188 | checkBox.ForeColor = checkBoxLook.ForeColor; 189 | checkBox.FlatStyle = checkBoxLook.FlatStyle; 190 | checkBox.FlatAppearance.BorderColor = checkBoxLook.BorderColor; 191 | checkBox.FlatAppearance.CheckedBackColor = checkBoxLook.CheckedBackColor; 192 | checkBox.FlatAppearance.MouseDownBackColor = checkBoxLook.MouseDownBackColor; 193 | checkBox.FlatAppearance.MouseOverBackColor = checkBoxLook.MouseOverBackColor; 194 | 195 | checkBox.EnabledChanged -= HandleCheckBoxEnabledChanged; 196 | checkBox.EnabledChanged += HandleCheckBoxEnabledChanged; 197 | } 198 | 199 | private void HandleCheckBoxEnabledChanged(object sender, EventArgs e) 200 | { 201 | var checkBox = (CheckBox) sender; 202 | if (checkBox.Enabled) 203 | { 204 | checkBox.Paint -= HandleCheckBoxPaint; 205 | checkBox.Invalidate(); 206 | } 207 | else 208 | { 209 | checkBox.Paint += HandleCheckBoxPaint; 210 | } 211 | } 212 | 213 | private void HandleCheckBoxPaint(object sender, PaintEventArgs e) 214 | { 215 | var checkBox = (CheckBox)sender; 216 | var disabledForeColor = ControlPaint.Dark(_theme.Button.ForeColor, 0.25f); 217 | var glyphSize = CheckBoxRenderer.GetGlyphSize(e.Graphics, CheckBoxState.UncheckedNormal); 218 | var flags = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine; 219 | var clientRectangle = new Rectangle(glyphSize.Width, -1, 220 | checkBox.ClientRectangle.Size.Width - glyphSize.Width, checkBox.ClientRectangle.Size.Height); 221 | 222 | TextRenderer.DrawText(e.Graphics, checkBox.Text, checkBox.Font, clientRectangle, disabledForeColor, flags); 223 | } 224 | 225 | private void Apply(ComboBox comboBox) 226 | { 227 | if (comboBox.DropDownStyle == ComboBoxStyle.DropDownList) 228 | comboBox.FlatStyle = FlatStyle.Popup; 229 | 230 | comboBox.BackColorChanged -= HandleComboBoxBackColorChanged; 231 | comboBox.BackColorChanged += HandleComboBoxBackColorChanged; 232 | } 233 | 234 | private void HandleComboBoxBackColorChanged(object sender, EventArgs e) 235 | { 236 | if (!_enabled) 237 | { 238 | return; 239 | } 240 | 241 | var comboBox = (ComboBox) sender; 242 | if (comboBox.BackColor == SystemColors.Window) 243 | comboBox.BackColor = _theme.Control.BackColor; 244 | } 245 | 246 | private void Apply(QualityProgressBar qualityProgressBar) 247 | { 248 | qualityProgressBar.ForeColor = _theme.Form.BackColor; 249 | } 250 | 251 | private void Apply(TabControl tabControl) 252 | { 253 | tabControl.ControlAdded -= HandleTabControlAdded; 254 | tabControl.ControlAdded += HandleTabControlAdded; 255 | } 256 | 257 | private void HandleTabControlAdded(object sender, ControlEventArgs e) 258 | { 259 | if (e.Control is TabPage) 260 | { 261 | var visitor = new ControlVisitor(Apply); 262 | visitor.Visit(e.Control); 263 | } 264 | } 265 | 266 | private void Apply(StatusStrip statusStrip) 267 | { 268 | statusStrip.BackColor = _theme.MenuItem.BackColor; 269 | statusStrip.ForeColor = _theme.MenuItem.ForeColor; 270 | 271 | Apply(statusStrip.Items); 272 | } 273 | 274 | private void Apply(ContextMenuStrip contextMenuStrip) 275 | { 276 | contextMenuStrip.BackColor = _theme.MenuItem.BackColor; 277 | contextMenuStrip.ForeColor = _theme.MenuItem.ForeColor; 278 | 279 | Apply(contextMenuStrip.Items); 280 | } 281 | 282 | private void Apply(MenuStrip menuStrip) 283 | { 284 | menuStrip.BackColor = _theme.MenuItem.BackColor; 285 | menuStrip.ForeColor = _theme.MenuItem.ForeColor; 286 | 287 | Apply(menuStrip.Items); 288 | } 289 | 290 | private void Apply(ToolStrip toolStrip) 291 | { 292 | toolStrip.BackColor = _theme.MenuItem.BackColor; 293 | toolStrip.ForeColor = _theme.MenuItem.ForeColor; 294 | 295 | Apply(toolStrip.Items); 296 | } 297 | 298 | private void Apply(ToolStripItemCollection toolStripItemCollection) 299 | { 300 | foreach (ToolStripItem item in toolStripItemCollection) 301 | { 302 | item.ForeColor = _theme.MenuItem.ForeColor; 303 | item.BackColor = _theme.MenuItem.BackColor; 304 | 305 | var menuItem = item as ToolStripMenuItem; 306 | if (menuItem != null) 307 | { 308 | menuItem.DropDownOpening -= HandleMenuItemOnDropDownOpening; 309 | menuItem.DropDownOpening += HandleMenuItemOnDropDownOpening; 310 | } 311 | } 312 | } 313 | 314 | private void HandleMenuItemOnDropDownOpening(object sender, EventArgs e) 315 | { 316 | var menuItem = (ToolStripMenuItem) sender; 317 | Apply(menuItem.DropDownItems); 318 | } 319 | 320 | private void Apply(SecureTextBoxEx secureTextBoxEx) 321 | { 322 | secureTextBoxEx.BackColorChanged -= HandleSecureTextBoxExOnBackColorChanged; 323 | secureTextBoxEx.BackColorChanged += HandleSecureTextBoxExOnBackColorChanged; 324 | } 325 | 326 | private void HandleSecureTextBoxExOnBackColorChanged(object sender, EventArgs e) 327 | { 328 | if (!_enabled) 329 | { 330 | return; 331 | } 332 | 333 | var textBox = (SecureTextBoxEx)sender; 334 | if (textBox.BackColor == SystemColors.Window) 335 | textBox.BackColor = _theme.SecureTextBox.BackColor; 336 | } 337 | 338 | private void Apply(HotKeyControlEx hotKeyControlEx) 339 | { 340 | hotKeyControlEx.BackColorChanged -= HandleHotKeyControlExOnBackColorChanged; 341 | hotKeyControlEx.BackColorChanged += HandleHotKeyControlExOnBackColorChanged; 342 | } 343 | 344 | private void HandleHotKeyControlExOnBackColorChanged(object sender, EventArgs e) 345 | { 346 | if (!_enabled) 347 | { 348 | return; 349 | } 350 | 351 | var textBox = (HotKeyControlEx) sender; 352 | if (textBox.BackColor == SystemColors.Window) 353 | textBox.BackColor = _theme.Control.BackColor; 354 | } 355 | 356 | private void Apply(Form form) 357 | { 358 | form.BackColor = _theme.Form.BackColor; 359 | form.ForeColor = _theme.Form.ForeColor; 360 | 361 | foreach (var component in GetComponents(form)) 362 | { 363 | Apply(component); 364 | } 365 | } 366 | 367 | private void Apply(UserControl userControl) 368 | { 369 | userControl.BackColor = _theme.Form.BackColor; 370 | userControl.ForeColor = _theme.Form.ForeColor; 371 | 372 | foreach (var component in GetComponents(userControl)) 373 | { 374 | Apply(component); 375 | } 376 | } 377 | 378 | private IEnumerable GetComponents(ContainerControl containerControl) 379 | { 380 | var componentsField = containerControl.GetType() 381 | .GetField("components", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 382 | 383 | if (componentsField != null) 384 | { 385 | var components = componentsField.GetValue(containerControl) as IContainer; 386 | if (components != null) 387 | { 388 | return components.Components.OfType(); 389 | } 390 | } 391 | 392 | return Enumerable.Empty(); 393 | } 394 | 395 | private void Apply(Button button) 396 | { 397 | button.BackColor = _theme.Button.BackColor; 398 | button.ForeColor = _theme.Button.ForeColor; 399 | button.FlatAppearance.BorderColor = _theme.Button.BorderColor; 400 | button.FlatStyle = _theme.Button.FlatStyle; 401 | 402 | if (button is SplitButtonEx) 403 | { 404 | var decorator = button.Controls.OfType().FirstOrDefault() 405 | ?? new SplitButtonExDecorator((SplitButtonEx) button, _theme); 406 | 407 | decorator.EnableTheme(_enabled, _theme); 408 | } 409 | 410 | button.EnabledChanged -= HandleButtonEnabledChanged; 411 | button.EnabledChanged += HandleButtonEnabledChanged; 412 | } 413 | 414 | private void HandleButtonEnabledChanged(object sender, EventArgs e) 415 | { 416 | var button = (Button) sender; 417 | if (button.Enabled) 418 | { 419 | button.Paint -= HandleButtonPaint; 420 | } 421 | else 422 | { 423 | button.Paint += HandleButtonPaint; 424 | } 425 | } 426 | 427 | private void HandleButtonPaint(object sender, PaintEventArgs e) 428 | { 429 | var button = (Button)sender; 430 | var disabledForeColor = ControlPaint.Dark(_theme.Button.ForeColor, 0.25f); 431 | if (button.Enabled) 432 | { 433 | disabledForeColor = _theme.Button.ForeColor; 434 | } 435 | var flags = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak; 436 | TextRenderer.DrawText(e.Graphics, button.Text, button.Font, button.ClientRectangle, disabledForeColor, flags); 437 | } 438 | 439 | private void Apply(LinkLabel linkLabel) 440 | { 441 | linkLabel.LinkColor = _theme.LinkLabel.LinkColor; 442 | } 443 | 444 | private void Apply(TreeView treeView) 445 | { 446 | treeView.BorderStyle = _theme.TreeView.BorderStyle; 447 | treeView.BackColor = _theme.TreeView.BackColor; 448 | 449 | TrySetWindowTheme(treeView.Handle, _enabled); 450 | 451 | if (!MonoWorkarounds.IsRequired()) 452 | { 453 | treeView.DrawMode = _theme.TreeViewDrawMode; 454 | treeView.DrawNode -= HandleTreeViewDrawNode; 455 | treeView.DrawNode += HandleTreeViewDrawNode; 456 | } 457 | } 458 | 459 | [DllImport("UxTheme.dll", ExactSpelling = true, CharSet = CharSet.Unicode)] 460 | private static extern int SetWindowTheme(IntPtr hWnd, string pszSubAppName, string pszSubIdList); 461 | 462 | private static void TrySetWindowTheme(IntPtr hWnd, bool enable) 463 | { 464 | if (hWnd == IntPtr.Zero || MonoWorkarounds.IsRequired()) 465 | return; 466 | 467 | try 468 | { 469 | SetWindowTheme(hWnd, enable ? "" : "explorer", null); 470 | } 471 | catch (Exception) 472 | { 473 | // ignored 474 | } 475 | } 476 | 477 | private void HandleTreeViewDrawNode(object sender, DrawTreeNodeEventArgs e) 478 | { 479 | // DrawDefault = true does not have TextFormatFlags.NoPrefix flag set 480 | var node = e.Node; 481 | 482 | var isNodeSelected = (e.State & TreeNodeStates.Selected) == TreeNodeStates.Selected; 483 | var foreColor = isNodeSelected && node.TreeView.Focused 484 | ? _theme.TreeView.SelectionColor 485 | : _theme.TreeView.ForeColor != Color.Empty ? _theme.TreeView.ForeColor : node.TreeView.ForeColor; 486 | 487 | var backColor = isNodeSelected ? _theme.TreeView.SelectionBackColor : _theme.TreeView.BackColor; 488 | 489 | var font = node.NodeFont ?? node.TreeView.Font; 490 | var size = TextRenderer.MeasureText(node.Text, font, e.Bounds.Size, TextFormatFlags.NoPrefix); 491 | var rectangle = new Rectangle(new Point(node.Bounds.X - 1, node.Bounds.Y), new Size(size.Width, node.Bounds.Height)); 492 | 493 | using (var backColorBrush = new SolidBrush(backColor)) 494 | e.Graphics.FillRectangle(backColorBrush, rectangle); 495 | 496 | if (isNodeSelected && node.TreeView.Focused) 497 | ControlPaint.DrawFocusRectangle(e.Graphics, rectangle, foreColor, backColor); 498 | 499 | TextRenderer.DrawText(e.Graphics, node.Text, font, rectangle, foreColor, TextFormatFlags.NoPrefix); 500 | } 501 | 502 | private void Apply(RichTextBox richTextBox) 503 | { 504 | var decorator = richTextBox.Parent as RichTextBoxDecorator; 505 | if (decorator == null) 506 | { 507 | decorator = new RichTextBoxDecorator(richTextBox, _theme); 508 | } 509 | 510 | decorator.EnableTheme(_enabled, _theme); 511 | 512 | } 513 | 514 | private void Apply(ListView listView) 515 | { 516 | if (ObjectListViewDecorator.CanDecorate(listView)) 517 | { 518 | ObjectListViewDecorator.Apply(listView, _theme); 519 | return; 520 | } 521 | 522 | var decorator = listView.Controls.OfType().FirstOrDefault() 523 | ?? new ListViewDecorator(listView , _theme); 524 | 525 | decorator.EnableTheme(_enabled, _theme); 526 | } 527 | 528 | private void Apply(PropertyGrid propertyGrid) 529 | { 530 | propertyGrid.CategoryForeColor = _theme.PropertyGrid.CategoryForeColor; 531 | propertyGrid.LineColor = _theme.PropertyGrid.LineColor; 532 | } 533 | } 534 | } -------------------------------------------------------------------------------- /KeeTheme/KeeTheme.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B82CD066-1BB1-42DB-B75A-F5489EF4A32D} 8 | Library 9 | Properties 10 | KeeTheme 11 | KeeTheme 12 | v3.5 13 | 512 14 | true 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 0 25 | false 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | false 35 | 36 | 37 | 38 | False 39 | C:\Program Files\KeePass Password Safe 2\KeePass.exe 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Component 60 | 61 | 62 | 63 | 64 | Component 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | Form 73 | 74 | 75 | TemplateEditorForm.cs 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | True 107 | True 108 | Resource.resx 109 | 110 | 111 | UserControl 112 | 113 | 114 | OptionsPanel.cs 115 | 116 | 117 | 118 | 119 | 120 | TemplateEditorForm.cs 121 | 122 | 123 | ResXFileCodeGenerator 124 | Resource.Designer.cs 125 | Designer 126 | 127 | 128 | OptionsPanel.cs 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | copy /Y $(TargetPath) $(SolutionDir)\..\KeePass\Plugins 139 | 140 | -------------------------------------------------------------------------------- /KeeTheme/KeeThemeExt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Drawing; 4 | using System.Reflection; 5 | using System.Windows.Forms; 6 | using KeePass; 7 | using KeePass.Forms; 8 | using KeePass.Plugins; 9 | using KeePassLib; 10 | using KeePassLib.Utility; 11 | using KeeTheme.Decorators; 12 | using KeeTheme.Options; 13 | using KeeTheme.Properties; 14 | 15 | namespace KeeTheme 16 | { 17 | public sealed class KeeThemeExt : Plugin 18 | { 19 | // Copied from EcasEventIDs.AppInitPost instead of using reflection because probably it will never change 20 | private static readonly PwUuid AppInitPost = new PwUuid(new byte[] { 21 | 0xD4, 0xCE, 0xCD, 0xB5, 0x4B, 0x98, 0x4F, 0xF2, 22 | 0xA6, 0xA9, 0xE2, 0x55, 0x26, 0x1E, 0xC8, 0xE8 23 | }); 24 | 25 | private ControlVisitor _controlVisitor; 26 | private KeeTheme _theme; 27 | private IPluginHost _host; 28 | private ToolStripMenuItem _menuItem; 29 | private KeeThemeOptions _options; 30 | private OptionsPanel _optionsPanel; 31 | private Win10ThemeMonitor _win10ThemeMonitor; 32 | 33 | public override bool Initialize(IPluginHost host) 34 | { 35 | if (host == null) 36 | return false; 37 | 38 | _host = host; 39 | 40 | _options = new KeeThemeOptions(host); 41 | _controlVisitor = new ControlVisitor(HandleControlVisit); 42 | _theme = new KeeTheme(_options); 43 | 44 | _win10ThemeMonitor = new Win10ThemeMonitor(_options); 45 | _win10ThemeMonitor.Initialize(); 46 | 47 | if (Program.TriggerSystem.Enabled) 48 | { 49 | // It's better to enable theme as late as possible, but not too late 50 | Program.TriggerSystem.RaisingEvent += HandleTriggerSystemRaisingEvent; 51 | } 52 | else 53 | { 54 | InitializeTheme(); 55 | } 56 | 57 | AttachApplicationOpenFormsAddedHandler(); 58 | 59 | return true; 60 | } 61 | 62 | private void AttachApplicationOpenFormsAddedHandler() 63 | { 64 | var customArrayList = new FormsArrayList(); 65 | customArrayList.AddRange(Application.OpenForms); 66 | customArrayList.Added += HandleOpenFormsAdded; 67 | 68 | var listField = typeof(ReadOnlyCollectionBase).GetField("list", BindingFlags.Instance | BindingFlags.NonPublic); 69 | if (listField != null) 70 | listField.SetValue(Application.OpenForms, customArrayList); 71 | } 72 | 73 | private void HandleOpenFormsAdded(object sender, FormAddedEventArgs args) 74 | { 75 | if (_theme.Enabled) 76 | _controlVisitor.Visit(args.Form); 77 | 78 | Win10ThemeMonitor.UseImmersiveDarkMode(args.Form, _theme.Enabled); 79 | 80 | var optionsForm = args.Form as OptionsForm; 81 | if (optionsForm != null) 82 | { 83 | optionsForm.Shown += HandleOptionsFormShown; 84 | } 85 | 86 | var editStringForm = args.Form as EditStringForm; 87 | if (editStringForm != null) 88 | { 89 | editStringForm.Load += HandleEditStringFormLoad; 90 | } 91 | 92 | var pwEntryForm = args.Form as PwEntryForm; 93 | if (pwEntryForm != null) 94 | { 95 | pwEntryForm.Load += HandlePwEntryFormFormLoad; 96 | } 97 | } 98 | 99 | private void HandlePwEntryFormFormLoad(object sender, EventArgs e) 100 | { 101 | PwGeneratorMenuDecorator.TryFindAndDecorate(sender, _theme); 102 | } 103 | 104 | private void HandleEditStringFormLoad(object sender, EventArgs e) 105 | { 106 | PwGeneratorMenuDecorator.TryFindAndDecorate(sender, _theme); 107 | } 108 | 109 | private void HandleTriggerSystemRaisingEvent(object sender, KeePass.Ecas.EcasRaisingEventArgs e) 110 | { 111 | if (e.Event.Type.Equals(AppInitPost)) 112 | { 113 | InitializeTheme(); 114 | 115 | Program.TriggerSystem.RaisingEvent -= HandleTriggerSystemRaisingEvent; 116 | } 117 | } 118 | 119 | private void InitializeTheme() 120 | { 121 | _theme.Enabled = _options.Enabled; 122 | if (_theme.Enabled) 123 | ApplyThemeInOpenForms(); 124 | 125 | _options.EnabledChanged += enable => 126 | { 127 | _theme.Enabled = enable; 128 | ApplyThemeInOpenForms(); 129 | }; 130 | 131 | _options.TemplateChanged += templatePath => 132 | { 133 | if (_theme.Enabled) 134 | { 135 | _theme.Enabled = false; 136 | _theme.Enabled = true; 137 | 138 | _menuItem.Text = TemplateReader.GetTemplateName(templatePath); 139 | 140 | ApplyThemeInOpenForms(); 141 | } 142 | }; 143 | } 144 | 145 | public override ToolStripMenuItem GetMenuItem(PluginMenuType t) 146 | { 147 | if (t == PluginMenuType.Main) 148 | { 149 | _menuItem = new ToolStripMenuItem(_theme.Name); 150 | _menuItem.CheckOnClick = true; 151 | _menuItem.Checked = _options.Enabled; 152 | _menuItem.ShortcutKeys = _options.HotKey; 153 | _menuItem.Click += HandleToggleKeeThemeMenuItemClick; 154 | _options.HotKeyChanged += keys => _menuItem.ShortcutKeys = keys; 155 | return _menuItem; 156 | } 157 | 158 | return base.GetMenuItem(t); 159 | } 160 | 161 | private void HandleToggleKeeThemeMenuItemClick(object sender, EventArgs eventArgs) 162 | { 163 | _options.Enabled = !_options.Enabled; 164 | } 165 | 166 | private void ApplyThemeInOpenForms() 167 | { 168 | foreach (Form openForm in Application.OpenForms) 169 | { 170 | Win10ThemeMonitor.UseImmersiveDarkMode(openForm, _theme.Enabled); 171 | _controlVisitor.Visit(openForm); 172 | } 173 | Program.MainForm.RefreshEntriesList(); 174 | } 175 | 176 | private void HandleControlVisit(Control control) 177 | { 178 | _theme.Apply(control); 179 | } 180 | 181 | private void HandleOptionsFormShown(object sender, EventArgs e) 182 | { 183 | var optionsForm = (OptionsForm) sender; 184 | OptionsPanel.Create(optionsForm, _options); 185 | } 186 | 187 | public override string UpdateUrl 188 | { 189 | get { return "https://nibiru.pl/keepass/plugins.php?name=KeeTheme"; } 190 | } 191 | 192 | public override Image SmallIcon 193 | { 194 | get { return GfxUtil.ScaleImage(Resource.PluginIcon, 16, 16); } 195 | } 196 | } 197 | } -------------------------------------------------------------------------------- /KeeTheme/Options/KeeThemeOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using KeePass.Plugins; 4 | 5 | namespace KeeTheme.Options 6 | { 7 | public class KeeThemeOptions 8 | { 9 | private const string TemplateOption = "KeeTheme.Template"; 10 | private const string EnabledOption = "KeeTheme.Enabled"; 11 | private const string HotKeyOption = "KeeTheme.HotKey"; 12 | private const string AutoSyncWithWin10ThemeOption = "KeeTheme.AutoSyncWithWin10Theme"; 13 | 14 | private readonly IPluginHost _pluginHost; 15 | private bool _enabled; 16 | private Keys _hotKey; 17 | private bool _autoSyncWithWin10Theme; 18 | private string _template; 19 | 20 | public bool Enabled 21 | { 22 | get { return _enabled; } 23 | set 24 | { 25 | _enabled = value; 26 | _pluginHost.CustomConfig.SetBool(EnabledOption, value); 27 | if (EnabledChanged != null) 28 | EnabledChanged.Invoke(value); 29 | } 30 | } 31 | 32 | public Keys HotKey 33 | { 34 | get { return _hotKey; } 35 | set 36 | { 37 | _hotKey = value; 38 | _pluginHost.CustomConfig.SetString(HotKeyOption, value.ToString()); 39 | if (HotKeyChanged != null) 40 | HotKeyChanged.Invoke(value); 41 | } 42 | } 43 | 44 | public bool AutoSyncWithWin10Theme 45 | { 46 | get { return _autoSyncWithWin10Theme; } 47 | set 48 | { 49 | _autoSyncWithWin10Theme = value; 50 | _pluginHost.CustomConfig.SetBool(AutoSyncWithWin10ThemeOption, value); 51 | if (AutoSyncWithWin10ThemeChanged != null) 52 | AutoSyncWithWin10ThemeChanged.Invoke(value); 53 | } 54 | } 55 | 56 | public string Template 57 | { 58 | get { return _template; } 59 | set 60 | { 61 | if (_template == value) 62 | return; 63 | 64 | _template = value; 65 | _pluginHost.CustomConfig.SetString(TemplateOption, value); 66 | if (TemplateChanged != null) 67 | TemplateChanged.Invoke(value); 68 | } 69 | } 70 | 71 | public event Action EnabledChanged; 72 | public event Action HotKeyChanged; 73 | public event Action AutoSyncWithWin10ThemeChanged; 74 | public event Action TemplateChanged; 75 | 76 | public KeeThemeOptions(IPluginHost pluginHost) 77 | { 78 | _pluginHost = pluginHost; 79 | 80 | _enabled = pluginHost.CustomConfig.GetBool(EnabledOption, false); 81 | var hotKey = pluginHost.CustomConfig.GetString(HotKeyOption, "T, Control"); 82 | _hotKey = (Keys) Enum.Parse(typeof(Keys), hotKey); 83 | _autoSyncWithWin10Theme = pluginHost.CustomConfig.GetBool(AutoSyncWithWin10ThemeOption, false); 84 | _template = pluginHost.CustomConfig.GetString(TemplateOption, TemplateReader.DefaultTemplatePath); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /KeeTheme/Options/OptionsPanel.Designer.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Windows.Forms; 3 | 4 | namespace KeeTheme.Options 5 | { 6 | partial class OptionsPanel 7 | { 8 | /// 9 | /// Required designer variable. 10 | /// 11 | private IContainer components = null; 12 | 13 | /// 14 | /// Clean up any resources being used. 15 | /// 16 | /// true if managed resources should be disposed; otherwise, false. 17 | protected override void Dispose(bool disposing) 18 | { 19 | if (disposing && (components != null)) 20 | { 21 | components.Dispose(); 22 | } 23 | 24 | base.Dispose(disposing); 25 | } 26 | 27 | #region Component Designer generated code 28 | 29 | /// 30 | /// Required method for Designer support - do not modify 31 | /// the contents of this method with the code editor. 32 | /// 33 | private void InitializeComponent() 34 | { 35 | this.hotKeyLabel = new System.Windows.Forms.Label(); 36 | this.hotKeyTextBox = new KeePass.UI.HotKeyControlEx(); 37 | this.autoSyncWin10ThemeCheckBox = new System.Windows.Forms.CheckBox(); 38 | this.autoSyncWin10ThemeLabel = new System.Windows.Forms.Label(); 39 | this.themeTemplate = new System.Windows.Forms.Label(); 40 | this.themeTemplateComboBox = new System.Windows.Forms.ComboBox(); 41 | this.editTemplateButton = new System.Windows.Forms.Button(); 42 | this.SuspendLayout(); 43 | // 44 | // hotKeyLabel 45 | // 46 | this.hotKeyLabel.Location = new System.Drawing.Point(9, 67); 47 | this.hotKeyLabel.Name = "hotKeyLabel"; 48 | this.hotKeyLabel.Size = new System.Drawing.Size(110, 23); 49 | this.hotKeyLabel.TabIndex = 0; 50 | this.hotKeyLabel.Text = "KeeTheme hot key:"; 51 | // 52 | // hotKeyTextBox 53 | // 54 | this.hotKeyTextBox.Location = new System.Drawing.Point(125, 64); 55 | this.hotKeyTextBox.Name = "hotKeyTextBox"; 56 | this.hotKeyTextBox.Size = new System.Drawing.Size(166, 20); 57 | this.hotKeyTextBox.TabIndex = 1; 58 | // 59 | // autoSyncWin10ThemeCheckBox 60 | // 61 | this.autoSyncWin10ThemeCheckBox.Location = new System.Drawing.Point(189, 90); 62 | this.autoSyncWin10ThemeCheckBox.Name = "autoSyncWin10ThemeCheckBox"; 63 | this.autoSyncWin10ThemeCheckBox.Size = new System.Drawing.Size(102, 24); 64 | this.autoSyncWin10ThemeCheckBox.TabIndex = 2; 65 | this.autoSyncWin10ThemeCheckBox.UseVisualStyleBackColor = true; 66 | // 67 | // autoSyncWin10ThemeLabel 68 | // 69 | this.autoSyncWin10ThemeLabel.Location = new System.Drawing.Point(9, 95); 70 | this.autoSyncWin10ThemeLabel.Name = "autoSyncWin10ThemeLabel"; 71 | this.autoSyncWin10ThemeLabel.Size = new System.Drawing.Size(174, 23); 72 | this.autoSyncWin10ThemeLabel.TabIndex = 3; 73 | this.autoSyncWin10ThemeLabel.Text = "Auto-sync with Windows 10 theme:"; 74 | // 75 | // themeTemplate 76 | // 77 | this.themeTemplate.Location = new System.Drawing.Point(9, 11); 78 | this.themeTemplate.Name = "themeTemplate"; 79 | this.themeTemplate.Size = new System.Drawing.Size(110, 23); 80 | this.themeTemplate.TabIndex = 4; 81 | this.themeTemplate.Text = "KeeTheme template:"; 82 | // 83 | // themeTemplateComboBox 84 | // 85 | this.themeTemplateComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 86 | this.themeTemplateComboBox.FormattingEnabled = true; 87 | this.themeTemplateComboBox.Location = new System.Drawing.Point(125, 8); 88 | this.themeTemplateComboBox.Name = "themeTemplateComboBox"; 89 | this.themeTemplateComboBox.Size = new System.Drawing.Size(166, 21); 90 | this.themeTemplateComboBox.TabIndex = 6; 91 | // 92 | // editTemplateButton 93 | // 94 | this.editTemplateButton.Location = new System.Drawing.Point(125, 35); 95 | this.editTemplateButton.Name = "editTemplateButton"; 96 | this.editTemplateButton.Size = new System.Drawing.Size(166, 23); 97 | this.editTemplateButton.TabIndex = 7; 98 | this.editTemplateButton.Text = "Open Editor"; 99 | this.editTemplateButton.UseVisualStyleBackColor = true; 100 | this.editTemplateButton.Click += new System.EventHandler(this.HandleEditTemplateButtonClick); 101 | // 102 | // OptionsPanel 103 | // 104 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 105 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 106 | this.Controls.Add(this.editTemplateButton); 107 | this.Controls.Add(this.themeTemplateComboBox); 108 | this.Controls.Add(this.themeTemplate); 109 | this.Controls.Add(this.autoSyncWin10ThemeLabel); 110 | this.Controls.Add(this.autoSyncWin10ThemeCheckBox); 111 | this.Controls.Add(this.hotKeyTextBox); 112 | this.Controls.Add(this.hotKeyLabel); 113 | this.Name = "OptionsPanel"; 114 | this.Size = new System.Drawing.Size(645, 200); 115 | this.ResumeLayout(false); 116 | this.PerformLayout(); 117 | } 118 | 119 | private System.Windows.Forms.Button editTemplateButton; 120 | 121 | private System.Windows.Forms.Label themeTemplate; 122 | private System.Windows.Forms.ComboBox themeTemplateComboBox; 123 | 124 | private System.Windows.Forms.CheckBox autoSyncWin10ThemeCheckBox; 125 | 126 | private System.Windows.Forms.Label autoSyncWin10ThemeLabel; 127 | 128 | private System.Windows.Forms.Label syncWin10ThemeLabel; 129 | private System.Windows.Forms.CheckBox syncWin10ThemeCheckBox; 130 | 131 | private System.Windows.Forms.CheckBox checkBox1; 132 | private System.Windows.Forms.Label syncWinThemeLabel; 133 | 134 | private System.Windows.Forms.Label hotKeyLabel; 135 | private KeePass.UI.HotKeyControlEx hotKeyTextBox; 136 | 137 | #endregion 138 | } 139 | } -------------------------------------------------------------------------------- /KeeTheme/Options/OptionsPanel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Linq; 4 | using System.Windows.Forms; 5 | using KeePass.Forms; 6 | using KeePass.UI; 7 | using KeePass.Util; 8 | using KeeTheme.Editor; 9 | 10 | namespace KeeTheme.Options 11 | { 12 | public partial class OptionsPanel : UserControl 13 | { 14 | private readonly KeeThemeOptions _options; 15 | 16 | public OptionsPanel() 17 | { 18 | InitializeComponent(); 19 | 20 | if (!WinUtil.IsAtLeastWindows10) 21 | autoSyncWin10ThemeCheckBox.Enabled = false; 22 | } 23 | 24 | private OptionsPanel(KeeThemeOptions options) : this() 25 | { 26 | _options = options; 27 | 28 | LoadOptions(); 29 | } 30 | 31 | public static void Create(OptionsForm optionsForm, KeeThemeOptions options) 32 | { 33 | var controls = optionsForm.Controls.Find("m_tabMain", false); 34 | if (controls.Length != 1) 35 | return; 36 | 37 | var tabControl = controls[0] as TabControl; 38 | if (tabControl == null) 39 | return; 40 | 41 | if (tabControl.ImageList == null) 42 | { 43 | tabControl.ImageList = new ImageList(); 44 | tabControl.ImageList.ImageSize = new Size(DpiUtil.ScaleIntX(16), DpiUtil.ScaleIntY(16)); 45 | } 46 | var imageIndex = tabControl.ImageList.Images.Add(Properties.Resource.PluginIcon, Color.Transparent); 47 | 48 | var optionsPanel = new OptionsPanel(options); 49 | var tabPage = new TabPage("KeeTheme"); 50 | tabPage.ImageIndex = imageIndex; 51 | tabPage.Controls.Add(optionsPanel); 52 | tabPage.UseVisualStyleBackColor = true; 53 | tabControl.TabPages.Add(tabPage); 54 | optionsPanel.Dock = DockStyle.Fill; 55 | 56 | if (TemplateEditorForm.Instance != null) 57 | { 58 | TemplateEditorForm.Instance.PreviewButtonClick += optionsPanel.HandleTemplateEditorPreviewButtonClick; 59 | TemplateEditorForm.Instance.Closed += optionsPanel.HandleTemplateEditorPreviewButtonClick; 60 | } 61 | 62 | optionsForm.FormClosed += (sender, args) => 63 | { 64 | if (optionsForm.DialogResult == DialogResult.OK) 65 | optionsPanel.SaveOptions(); 66 | 67 | if (TemplateEditorForm.Instance != null) 68 | { 69 | TemplateEditorForm.Instance.PreviewButtonClick -= optionsPanel.HandleTemplateEditorPreviewButtonClick; 70 | TemplateEditorForm.Instance.Closed -= optionsPanel.HandleTemplateEditorPreviewButtonClick; 71 | } 72 | }; 73 | } 74 | 75 | private void LoadOptions() 76 | { 77 | hotKeyTextBox.HotKey = _options.HotKey; 78 | autoSyncWin10ThemeCheckBox.Checked = _options.AutoSyncWithWin10Theme; 79 | LoadKeeThemeTemplates(); 80 | } 81 | 82 | private void LoadKeeThemeTemplates() 83 | { 84 | var templates = TemplateReader.GetTemplatesFromResources(); 85 | var fileTemplates = TemplateReader.GetTemplatesFromPluginsDir(); 86 | templates.AddRange(fileTemplates); 87 | 88 | var selectedTemplate = templates.Find(x => x.Path == _options.Template); 89 | if (selectedTemplate == null) 90 | { 91 | var templateName = TemplateReader.GetTemplateName(_options.Template); 92 | if (templateName != null) 93 | { 94 | var templateFile = new TemplateFile(); 95 | templateFile.Name = templateName; 96 | templateFile.Path = _options.Template; 97 | templates.Add(templateFile); 98 | selectedTemplate = templateFile; 99 | } 100 | } 101 | 102 | themeTemplateComboBox.Items.Clear(); 103 | foreach (var template in templates) 104 | { 105 | themeTemplateComboBox.Items.Add(template); 106 | } 107 | 108 | themeTemplateComboBox.SelectedItem = selectedTemplate ?? templates 109 | .First(x => x.Path == TemplateReader.DefaultTemplatePath); 110 | } 111 | 112 | private void SaveOptions() 113 | { 114 | _options.HotKey = hotKeyTextBox.HotKey; 115 | _options.AutoSyncWithWin10Theme = autoSyncWin10ThemeCheckBox.Checked; 116 | 117 | var template = (TemplateFile) themeTemplateComboBox.SelectedItem; 118 | _options.Template = template.Path; 119 | } 120 | 121 | private void HandleEditTemplateButtonClick(object sender, EventArgs e) 122 | { 123 | if (TemplateEditorForm.Instance == null) 124 | { 125 | var templateEditorForm = TemplateEditorForm.Create(_options); 126 | templateEditorForm.PreviewButtonClick += HandleTemplateEditorPreviewButtonClick; 127 | templateEditorForm.Closed += HandleTemplateEditorFormClosed; 128 | templateEditorForm.Show(); 129 | templateEditorForm.Activate(); 130 | } 131 | } 132 | 133 | private void HandleTemplateEditorFormClosed(object sender, EventArgs e) 134 | { 135 | LoadKeeThemeTemplates(); 136 | } 137 | 138 | private void HandleTemplateEditorPreviewButtonClick(object sender, EventArgs e) 139 | { 140 | LoadKeeThemeTemplates(); 141 | } 142 | } 143 | } -------------------------------------------------------------------------------- /KeeTheme/Options/OptionsPanel.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /KeeTheme/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("KeeTheme")] 8 | [assembly: AssemblyDescription("Plugin changes the appearance of KeePass, to make it look better at night. \n\nYou can enable it using hotkey `CTRL+T` or using the menu `Tools -> DarkTheme`.")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Krzysztof Łaputa")] 11 | [assembly: AssemblyProduct("KeePass Plugin")] 12 | [assembly: AssemblyCopyright("Copyright © 2019 Krzysztof Łaputa")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("b82cd066-1bb1-42db-b75a-f5489ef4a32d")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("0.10.7.0")] 35 | [assembly: AssemblyFileVersion("0.10.7.0")] 36 | -------------------------------------------------------------------------------- /KeeTheme/Properties/Resource.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // 5 | // Changes to this file may cause incorrect behavior and will be lost if 6 | // the code is regenerated. 7 | // 8 | //------------------------------------------------------------------------------ 9 | 10 | namespace KeeTheme.Properties { 11 | using System; 12 | 13 | 14 | /// 15 | /// A strongly-typed resource class, for looking up localized strings, etc. 16 | /// 17 | // This class was auto-generated by the StronglyTypedResourceBuilder 18 | // class via a tool like ResGen or Visual Studio. 19 | // To add or remove a member, edit your .ResX file then rerun ResGen 20 | // with the /str option, or rebuild your VS project. 21 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 22 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 23 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 24 | internal class Resource { 25 | 26 | private static global::System.Resources.ResourceManager resourceMan; 27 | 28 | private static global::System.Globalization.CultureInfo resourceCulture; 29 | 30 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 31 | internal Resource() { 32 | } 33 | 34 | /// 35 | /// Returns the cached ResourceManager instance used by this class. 36 | /// 37 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 38 | internal static global::System.Resources.ResourceManager ResourceManager { 39 | get { 40 | if (object.ReferenceEquals(resourceMan, null)) { 41 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("KeeTheme.Properties.Resource", typeof(Resource).Assembly); 42 | resourceMan = temp; 43 | } 44 | return resourceMan; 45 | } 46 | } 47 | 48 | /// 49 | /// Overrides the current thread's CurrentUICulture property for all 50 | /// resource lookups using this strongly typed resource class. 51 | /// 52 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 53 | internal static global::System.Globalization.CultureInfo Culture { 54 | get { 55 | return resourceCulture; 56 | } 57 | set { 58 | resourceCulture = value; 59 | } 60 | } 61 | 62 | /// 63 | /// Looks up a localized string similar to [KeeTheme] 64 | ///Name=Dark Theme 65 | /// 66 | ///[Palette] 67 | ///Control = (51, 51, 51) 68 | ///ControlText = (227, 227, 227) 69 | ///Window = (69, 73, 74) 70 | ///LightWindow = (74, 78, 79) 71 | ///WindowText = (220, 220, 220) 72 | ///Border = (104, 151, 187) 73 | ///LightBorder = (81, 81, 81) 74 | ///Header = (57, 60, 62) 75 | ///ColumnBorder = (97, 100, 101) 76 | ///Group = (148, 184, 220) 77 | ///GroupHighlight = (65, 82, 96) 78 | ///Link = (110, 179, 248) 79 | ///ToolStrip = (64, 64, 64) 80 | ///ToolStripHighlight = (114, 161, 197) 81 | ///ToolStripBorder = (0, 0, 0) 82 | ///Error = (207, 102, 121) 83 | ///TreeViewHighlight = (55, 86, [rest of string was truncated]";. 84 | /// 85 | internal static string DarkTheme { 86 | get { 87 | return ResourceManager.GetString("DarkTheme", resourceCulture); 88 | } 89 | } 90 | 91 | /// 92 | /// Looks up a localized string similar to [KeeTheme] 93 | ///Name=Dark Theme Win11 94 | /// 95 | ///[Palette] 96 | ///Control = (25, 25, 25) 97 | ///ControlText = (255, 255, 255) 98 | ///Window = (69, 73, 74) 99 | ///LightWindow = (74, 78, 79) 100 | ///WindowText = (220, 220, 220) 101 | ///Border = (104, 151, 187) 102 | ///LightBorder = (81, 81, 81) 103 | ///Header = (57, 60, 62) 104 | ///ColumnBorder = (97, 100, 101) 105 | ///Group = (148, 184, 220) 106 | ///GroupHighlight = (65, 82, 96) 107 | ///Link = (110, 179, 248) 108 | ///ToolStrip = (64, 64, 64) 109 | ///ToolStripHighlight = (114, 161, 197) 110 | ///ToolStripBorder = (0, 0, 0) 111 | ///Error = (207, 102, 121) 112 | ///TreeViewHighlight = (5 [rest of string was truncated]";. 113 | /// 114 | internal static string DarkThemeWin11 { 115 | get { 116 | return ResourceManager.GetString("DarkThemeWin11", resourceCulture); 117 | } 118 | } 119 | 120 | /// 121 | /// Looks up a localized resource of type System.Drawing.Bitmap. 122 | /// 123 | internal static System.Drawing.Bitmap PluginIcon { 124 | get { 125 | object obj = ResourceManager.GetObject("PluginIcon", resourceCulture); 126 | return ((System.Drawing.Bitmap)(obj)); 127 | } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /KeeTheme/Properties/Resource.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\DarkTheme.ini;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 123 | 124 | 125 | ..\Resources\PluginIcon.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 126 | 127 | 128 | ..\Resources\DarkThemeWin11.ini;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 129 | 130 | -------------------------------------------------------------------------------- /KeeTheme/Resources/DarkTheme.ini: -------------------------------------------------------------------------------- 1 | [KeeTheme] 2 | Name=Dark Theme 3 | 4 | [Palette] 5 | Control = (51, 51, 51) 6 | ControlText = (227, 227, 227) 7 | Window = (69, 73, 74) 8 | LightWindow = (74, 78, 79) 9 | WindowText = (220, 220, 220) 10 | Border = (104, 151, 187) 11 | LightBorder = (81, 81, 81) 12 | Header = (57, 60, 62) 13 | ColumnBorder = (97, 100, 101) 14 | Group = (148, 184, 220) 15 | GroupHighlight = (65, 82, 96) 16 | Link = (110, 179, 248) 17 | ToolStrip = (64, 64, 64) 18 | ToolStripHighlight = (114, 161, 197) 19 | ToolStripBorder = (0, 0, 0) 20 | Error = (207, 102, 121) 21 | TreeViewHighlight = (55, 86, 109) 22 | 23 | [Other] 24 | ControlNormalColor = Window 25 | ControlDisabledColor = Control 26 | ColorEditError = Error 27 | 28 | [Control] 29 | BackColor = Control 30 | ForeColor = ControlText 31 | 32 | [Form] 33 | BackColor = Control 34 | ForeColor = ControlText 35 | 36 | [Button] 37 | BackColor = Control 38 | ForeColor = ControlText 39 | BorderColor = Border 40 | FlatStyle = Flat 41 | 42 | [TreeView] 43 | BackColor = Window 44 | ForeColor = ControlText 45 | SelectionColor = ControlText 46 | SelectionBackColor = TreeViewHighlight 47 | BorderStyle = FixedSingle 48 | 49 | [RichTextBox] 50 | BackColor = Control 51 | ForeColor = ControlText 52 | BorderStyle = FixedSingle 53 | SelectionColor = ControlText 54 | 55 | [LinkLabel] 56 | BackColor = Control 57 | ForeColor = ControlText 58 | LinkColor = Link 59 | 60 | [ListView] 61 | BackColor = Window 62 | ForeColor = ControlText 63 | BorderStyle = FixedSingle 64 | OddRowColor = LightWindow 65 | EvenRowColor = Window 66 | ColumnBorderColor = ColumnBorder 67 | HeaderBackColor = Header 68 | HeaderForeColor = WindowText 69 | HeaderColumnBorderColor = LightBorder 70 | BackgroundImageAlignment = 71 | BackgroundImage = 72 | GroupForeColor = Group 73 | GroupBackColor = Window 74 | GroupHighlightColor = GroupHighlight 75 | 76 | [SecureTextBox] 77 | BackColor = Control 78 | ForeColor = ControlText 79 | 80 | [CheckBox] 81 | BackColor = 82 | ForeColor = 83 | FlatStyle = 84 | BorderColor = 85 | CheckedBackColor = 86 | MouseDownBackColor = 87 | MouseOverBackColor = 88 | 89 | [CheckBoxButton] 90 | BackColor = Border 91 | ForeColor = 92 | FlatStyle = Flat 93 | BorderColor = Border 94 | CheckedBackColor = Control 95 | MouseDownBackColor = LightBorder 96 | MouseOverBackColor = Window 97 | 98 | [MenuItem] 99 | BackColor = ToolStrip 100 | ForeColor = ControlText 101 | HighlightColor = Control 102 | 103 | [ToolStrip] 104 | ButtonSelectedHighlight = 105 | ButtonSelectedHighlightBorder = ToolStripHighlight 106 | ButtonPressedHighlight = 107 | ButtonPressedHighlightBorder = 108 | ButtonCheckedHighlight = 109 | ButtonCheckedHighlightBorder = 110 | ButtonPressedBorder = ToolStrip 111 | ButtonSelectedBorder = ToolStrip 112 | ButtonCheckedGradientBegin = 113 | ButtonCheckedGradientMiddle = 114 | ButtonCheckedGradientEnd = 115 | ButtonSelectedGradientBegin = ToolStripHighlight 116 | ButtonSelectedGradientMiddle = ToolStripHighlight 117 | ButtonSelectedGradientEnd = ToolStripHighlight 118 | ButtonPressedGradientBegin = ToolStripHighlight 119 | ButtonPressedGradientMiddle = ToolStripHighlight 120 | ButtonPressedGradientEnd = ToolStripHighlight 121 | CheckBackground = ToolStripHighlight 122 | CheckSelectedBackground = ToolStripHighlight 123 | CheckPressedBackground = ToolStripHighlight 124 | GripDark = 125 | GripLight = 126 | ImageMarginGradientBegin = ToolStrip 127 | ImageMarginGradientMiddle = ToolStrip 128 | ImageMarginGradientEnd = ToolStrip 129 | ImageMarginRevealedGradientBegin = 130 | ImageMarginRevealedGradientMiddle = 131 | ImageMarginRevealedGradientEnd = 132 | MenuStripGradientBegin = 133 | MenuStripGradientEnd = 134 | MenuItemSelected = ToolStripHighlight 135 | MenuItemBorder = ToolStripHighlight 136 | MenuBorder = ToolStripHighlight 137 | MenuItemSelectedGradientBegin = ToolStripHighlight 138 | MenuItemSelectedGradientEnd = ToolStripHighlight 139 | MenuItemPressedGradientBegin = ToolStripHighlight 140 | MenuItemPressedGradientMiddle = ToolStripHighlight 141 | MenuItemPressedGradientEnd = ToolStripHighlight 142 | RaftingContainerGradientBegin = 143 | RaftingContainerGradientEnd = 144 | SeparatorDark = 145 | SeparatorLight = 146 | StatusStripGradientBegin = 147 | StatusStripGradientEnd = 148 | ToolStripBorder = ToolStripBorder 149 | ToolStripDropDownBackground = ToolStrip 150 | ToolStripGradientBegin = ToolStrip 151 | ToolStripGradientMiddle = ToolStrip 152 | ToolStripGradientEnd = ToolStrip 153 | ToolStripContentPanelGradientBegin = 154 | ToolStripContentPanelGradientEnd = 155 | ToolStripPanelGradientBegin = 156 | ToolStripPanelGradientEnd = 157 | OverflowButtonGradientBegin = ToolStrip 158 | OverflowButtonGradientMiddle = ToolStrip 159 | OverflowButtonGradientEnd = ToolStrip 160 | 161 | [PropertyGrid] 162 | CategoryForeColor = ControlText -------------------------------------------------------------------------------- /KeeTheme/Resources/DarkThemeWin11.ini: -------------------------------------------------------------------------------- 1 | [KeeTheme] 2 | Name=Dark Theme Win11 3 | 4 | [Palette] 5 | Control = (25, 25, 25) 6 | ControlText = (255, 255, 255) 7 | Window = (25, 25, 25) 8 | LightWindow = (33, 33, 33) 9 | WindowText = (255, 255, 255) 10 | Border = (43, 43, 43) 11 | LightBorder = (53, 53, 53) 12 | Header = (25, 25, 25) 13 | ColumnBorder = (59, 59, 59) 14 | Group = (255, 255, 255) 15 | GroupHighlight = (77, 77, 77) 16 | Link = (67, 172, 226) 17 | ToolStrip = (44, 44, 44) 18 | ToolStripHighlight = (56, 56, 56) 19 | ToolStripBorder = (0, 0, 0) 20 | Error = (227, 36, 27) 21 | TreeViewHighlight = (77, 77, 77) 22 | 23 | [Other] 24 | ControlNormalColor = Window 25 | ControlDisabledColor = Control 26 | ColorEditError = Error 27 | 28 | [Control] 29 | BackColor = Control 30 | ForeColor = ControlText 31 | 32 | [Form] 33 | BackColor = Control 34 | ForeColor = ControlText 35 | 36 | [Button] 37 | BackColor = Control 38 | ForeColor = ControlText 39 | BorderColor = Border 40 | FlatStyle = Flat 41 | 42 | [TreeView] 43 | BackColor = Window 44 | ForeColor = ControlText 45 | SelectionColor = ControlText 46 | SelectionBackColor = TreeViewHighlight 47 | BorderStyle = FixedSingle 48 | 49 | [RichTextBox] 50 | BackColor = Control 51 | ForeColor = ControlText 52 | BorderStyle = FixedSingle 53 | SelectionColor = ControlText 54 | 55 | [LinkLabel] 56 | BackColor = Control 57 | ForeColor = ControlText 58 | LinkColor = Link 59 | 60 | [ListView] 61 | BackColor = Window 62 | ForeColor = ControlText 63 | BorderStyle = FixedSingle 64 | OddRowColor = LightWindow 65 | EvenRowColor = Window 66 | ColumnBorderColor = ColumnBorder 67 | HeaderBackColor = Header 68 | HeaderForeColor = WindowText 69 | HeaderColumnBorderColor = ColumnBorder 70 | BackgroundImageAlignment = 71 | BackgroundImage = 72 | GroupForeColor = Group 73 | GroupBackColor = Window 74 | GroupHighlightColor = GroupHighlight 75 | 76 | [SecureTextBox] 77 | BackColor = Control 78 | ForeColor = ControlText 79 | 80 | [CheckBox] 81 | BackColor = 82 | ForeColor = 83 | FlatStyle = 84 | BorderColor = 85 | CheckedBackColor = 86 | MouseDownBackColor = 87 | MouseOverBackColor = 88 | 89 | [CheckBoxButton] 90 | BackColor = Border 91 | ForeColor = 92 | FlatStyle = Flat 93 | BorderColor = Border 94 | CheckedBackColor = Control 95 | MouseDownBackColor = LightBorder 96 | MouseOverBackColor = Window 97 | 98 | [MenuItem] 99 | BackColor = ToolStrip 100 | ForeColor = ControlText 101 | HighlightColor = ControlText 102 | 103 | [ToolStrip] 104 | ButtonSelectedHighlight = 105 | ButtonSelectedHighlightBorder = ToolStripHighlight 106 | ButtonPressedHighlight = 107 | ButtonPressedHighlightBorder = 108 | ButtonCheckedHighlight = 109 | ButtonCheckedHighlightBorder = 110 | ButtonPressedBorder = ToolStrip 111 | ButtonSelectedBorder = ToolStrip 112 | ButtonCheckedGradientBegin = 113 | ButtonCheckedGradientMiddle = 114 | ButtonCheckedGradientEnd = 115 | ButtonSelectedGradientBegin = ToolStripHighlight 116 | ButtonSelectedGradientMiddle = ToolStripHighlight 117 | ButtonSelectedGradientEnd = ToolStripHighlight 118 | ButtonPressedGradientBegin = ToolStripHighlight 119 | ButtonPressedGradientMiddle = ToolStripHighlight 120 | ButtonPressedGradientEnd = ToolStripHighlight 121 | CheckBackground = ControlText 122 | CheckSelectedBackground = ControlText 123 | CheckPressedBackground = ControlText 124 | GripDark = 125 | GripLight = 126 | ImageMarginGradientBegin = ToolStrip 127 | ImageMarginGradientMiddle = ToolStrip 128 | ImageMarginGradientEnd = ToolStrip 129 | ImageMarginRevealedGradientBegin = 130 | ImageMarginRevealedGradientMiddle = 131 | ImageMarginRevealedGradientEnd = 132 | MenuStripGradientBegin = 133 | MenuStripGradientEnd = 134 | MenuItemSelected = ToolStripHighlight 135 | MenuItemBorder = ToolStripHighlight 136 | MenuBorder = ToolStripHighlight 137 | MenuItemSelectedGradientBegin = ToolStripHighlight 138 | MenuItemSelectedGradientEnd = ToolStripHighlight 139 | MenuItemPressedGradientBegin = ToolStripHighlight 140 | MenuItemPressedGradientMiddle = ToolStripHighlight 141 | MenuItemPressedGradientEnd = ToolStripHighlight 142 | RaftingContainerGradientBegin = 143 | RaftingContainerGradientEnd = 144 | SeparatorDark = 145 | SeparatorLight = 146 | StatusStripGradientBegin = 147 | StatusStripGradientEnd = 148 | ToolStripBorder = ToolStripBorder 149 | ToolStripDropDownBackground = ToolStrip 150 | ToolStripGradientBegin = ToolStrip 151 | ToolStripGradientMiddle = ToolStrip 152 | ToolStripGradientEnd = ToolStrip 153 | ToolStripContentPanelGradientBegin = 154 | ToolStripContentPanelGradientEnd = 155 | ToolStripPanelGradientBegin = 156 | ToolStripPanelGradientEnd = 157 | OverflowButtonGradientBegin = ToolStrip 158 | OverflowButtonGradientMiddle = ToolStrip 159 | OverflowButtonGradientEnd = ToolStrip 160 | 161 | [PropertyGrid] 162 | CategoryForeColor = ControlText -------------------------------------------------------------------------------- /KeeTheme/Resources/PluginIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xatupal/KeeTheme/5f2534d5ca7847411e6911b4298a6405cbe44362/KeeTheme/Resources/PluginIcon.png -------------------------------------------------------------------------------- /KeeTheme/TemplateFile.cs: -------------------------------------------------------------------------------- 1 | namespace KeeTheme 2 | { 3 | public class TemplateFile 4 | { 5 | public string Name { get; set; } 6 | public string Path { get; set; } 7 | 8 | public override string ToString() 9 | { 10 | return Name; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /KeeTheme/TemplateReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using KeePass; 6 | using KeePass.App; 7 | using KeeTheme.Theme; 8 | 9 | namespace KeeTheme 10 | { 11 | public static class TemplateReader 12 | { 13 | public const string DefaultTemplatePath = "KeeTheme.Resources.DarkTheme.ini"; 14 | 15 | internal static IniFile GetDefaultTemplate() 16 | { 17 | return GetFromResources(DefaultTemplatePath); 18 | } 19 | 20 | internal static List GetTemplatesFromResources() 21 | { 22 | var result = new List(); 23 | var resourceNames = typeof(TemplateReader).Assembly.GetManifestResourceNames(); 24 | foreach (var resourceName in resourceNames.Where(x => x.EndsWith(".ini"))) 25 | { 26 | var resourceStream = typeof(TemplateReader).Assembly.GetManifestResourceStream(resourceName); 27 | using (var sr = new StreamReader(resourceStream)) 28 | { 29 | var templateName = GetTemplateName(sr); 30 | if (templateName == null) 31 | continue; 32 | 33 | var template = new TemplateFile(); 34 | template.Name = templateName; 35 | template.Path = resourceName; 36 | result.Add(template); 37 | } 38 | } 39 | 40 | return result; 41 | } 42 | 43 | private static string GetTemplateName(StreamReader streamReader) 44 | { 45 | try 46 | { 47 | var iniFile = new IniFile(streamReader); 48 | var themeSection = iniFile.GetSection("KeeTheme"); 49 | return themeSection.ContainsKey("Name") ? themeSection["Name"] : null; 50 | } 51 | catch (Exception) 52 | { 53 | return null; 54 | } 55 | } 56 | 57 | internal static List GetTemplatesFromPluginsDir() 58 | { 59 | var result = new List(); 60 | var files = Directory.GetFiles(GetTemplatesDir(), "*.ini"); 61 | foreach (var file in files) 62 | { 63 | using (var sr = File.OpenText(file)) 64 | { 65 | var templateName = GetTemplateName(sr); 66 | if (templateName == null) 67 | continue; 68 | 69 | var template = new TemplateFile(); 70 | template.Name = templateName; 71 | template.Path = "file:" + Path.GetFileName(file); 72 | result.Add(template); 73 | } 74 | } 75 | 76 | return result; 77 | } 78 | 79 | public static string GetTemplatesDir() 80 | { 81 | var exeLocation = Path.GetDirectoryName(typeof(Program).Assembly.Location); 82 | return Path.Combine(exeLocation, AppDefs.PluginsDir); 83 | } 84 | 85 | private static IniFile GetFromFile(string fileName) 86 | { 87 | var filePath = fileName; 88 | if (!Path.IsPathRooted(filePath)) 89 | { 90 | filePath = Path.Combine(GetTemplatesDir(), fileName); 91 | } 92 | 93 | if (!File.Exists(filePath)) 94 | return null; 95 | 96 | try 97 | { 98 | using (var sr = File.OpenText(filePath)) 99 | return new IniFile(sr); 100 | } 101 | catch (Exception) 102 | { 103 | return null; 104 | } 105 | } 106 | 107 | private static IniFile GetFromResources(string resourceName) 108 | { 109 | try 110 | { 111 | var stream = typeof(TemplateReader).Assembly.GetManifestResourceStream(resourceName); 112 | using (var sr = new StreamReader(stream)) 113 | { 114 | return new IniFile(sr); 115 | } 116 | } 117 | catch (Exception e) 118 | { 119 | return null; 120 | } 121 | } 122 | 123 | internal static IniFile Get(string templatePath) 124 | { 125 | return templatePath.StartsWith("file:") 126 | ? GetFromFile(templatePath.Substring("file:".Length)) 127 | : GetFromResources(templatePath); 128 | } 129 | 130 | internal static string GetTemplateName(string templatePath) 131 | { 132 | var iniFile = Get(templatePath); 133 | if (iniFile == null) 134 | return null; 135 | 136 | var themeSection = iniFile.GetSection("KeeTheme"); 137 | return themeSection["Name"]; 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/ButtonLook.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | using KeeTheme.Editor; 5 | 6 | namespace KeeTheme.Theme 7 | { 8 | [TypeConverter(typeof(ButtonLookTypeConverter))] 9 | class ButtonLook : ControlLook 10 | { 11 | public Color BorderColor { get; set; } 12 | public FlatStyle FlatStyle { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/CheckBoxButtonLook.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using KeeTheme.Editor; 3 | 4 | namespace KeeTheme.Theme 5 | { 6 | [TypeConverter(typeof(CheckBoxButtonLookTypeConverter))] 7 | class CheckBoxButtonLook : CheckBoxLook 8 | { 9 | } 10 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/CheckBoxLook.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | using KeeTheme.Editor; 5 | 6 | namespace KeeTheme.Theme 7 | { 8 | [TypeConverter(typeof(CheckBoxLookTypeConverter))] 9 | class CheckBoxLook : ControlLook 10 | { 11 | public Color BorderColor { get; set; } 12 | public FlatStyle FlatStyle { get; set; } 13 | public Color CheckedBackColor { get; set; } 14 | public Color MouseDownBackColor { get; set; } 15 | public Color MouseOverBackColor { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/ControlLook.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using KeeTheme.Editor; 4 | 5 | namespace KeeTheme.Theme 6 | { 7 | [TypeConverter(typeof(ControlLookTypeConverter))] 8 | class ControlLook 9 | { 10 | public Color BackColor { get; set; } 11 | public Color ForeColor { get; set; } 12 | 13 | public override string ToString() 14 | { 15 | return GetType().Name; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /KeeTheme/Theme/CustomColorTable.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | 5 | namespace KeeTheme.Theme 6 | { 7 | class CustomColorTable : ProfessionalColorTable 8 | { 9 | private readonly Dictionary _customColors = new Dictionary(); 10 | 11 | public override Color ButtonSelectedHighlight { get { return _customColors.ContainsKey("ButtonSelectedHighlight") ? _customColors["ButtonSelectedHighlight"] : base.ButtonSelectedHighlight; } } 12 | public override Color ButtonSelectedHighlightBorder { get { return _customColors.ContainsKey("ButtonSelectedHighlightBorder") ? _customColors["ButtonSelectedHighlightBorder"] : base.ButtonSelectedHighlightBorder; } } 13 | public override Color ButtonPressedHighlight { get { return _customColors.ContainsKey("ButtonPressedHighlight") ? _customColors["ButtonPressedHighlight"] : base.ButtonPressedHighlight; } } 14 | public override Color ButtonPressedHighlightBorder { get { return _customColors.ContainsKey("ButtonPressedHighlightBorder") ? _customColors["ButtonPressedHighlightBorder"] : base.ButtonPressedHighlightBorder; } } 15 | public override Color ButtonCheckedHighlight { get { return _customColors.ContainsKey("ButtonCheckedHighlight") ? _customColors["ButtonCheckedHighlight"] : base.ButtonCheckedHighlight; } } 16 | public override Color ButtonCheckedHighlightBorder { get { return _customColors.ContainsKey("ButtonCheckedHighlightBorder") ? _customColors["ButtonCheckedHighlightBorder"] : base.ButtonCheckedHighlightBorder; } } 17 | public override Color ButtonPressedBorder { get { return _customColors.ContainsKey("ButtonPressedBorder") ? _customColors["ButtonPressedBorder"] : base.ButtonPressedBorder; } } 18 | public override Color ButtonSelectedBorder { get { return _customColors.ContainsKey("ButtonSelectedBorder") ? _customColors["ButtonSelectedBorder"] : base.ButtonSelectedBorder; } } 19 | public override Color ButtonCheckedGradientBegin { get { return _customColors.ContainsKey("ButtonCheckedGradientBegin") ? _customColors["ButtonCheckedGradientBegin"] : base.ButtonCheckedGradientBegin; } } 20 | public override Color ButtonCheckedGradientMiddle { get { return _customColors.ContainsKey("ButtonCheckedGradientMiddle") ? _customColors["ButtonCheckedGradientMiddle"] : base.ButtonCheckedGradientMiddle; } } 21 | public override Color ButtonCheckedGradientEnd { get { return _customColors.ContainsKey("ButtonCheckedGradientEnd") ? _customColors["ButtonCheckedGradientEnd"] : base.ButtonCheckedGradientEnd; } } 22 | public override Color ButtonSelectedGradientBegin { get { return _customColors.ContainsKey("ButtonSelectedGradientBegin") ? _customColors["ButtonSelectedGradientBegin"] : base.ButtonSelectedGradientBegin; } } 23 | public override Color ButtonSelectedGradientMiddle { get { return _customColors.ContainsKey("ButtonSelectedGradientMiddle") ? _customColors["ButtonSelectedGradientMiddle"] : base.ButtonSelectedGradientMiddle; } } 24 | public override Color ButtonSelectedGradientEnd { get { return _customColors.ContainsKey("ButtonSelectedGradientEnd") ? _customColors["ButtonSelectedGradientEnd"] : base.ButtonSelectedGradientEnd; } } 25 | public override Color ButtonPressedGradientBegin { get { return _customColors.ContainsKey("ButtonPressedGradientBegin") ? _customColors["ButtonPressedGradientBegin"] : base.ButtonPressedGradientBegin; } } 26 | public override Color ButtonPressedGradientMiddle { get { return _customColors.ContainsKey("ButtonPressedGradientMiddle") ? _customColors["ButtonPressedGradientMiddle"] : base.ButtonPressedGradientMiddle; } } 27 | public override Color ButtonPressedGradientEnd { get { return _customColors.ContainsKey("ButtonPressedGradientEnd") ? _customColors["ButtonPressedGradientEnd"] : base.ButtonPressedGradientEnd; } } 28 | public override Color CheckBackground { get { return _customColors.ContainsKey("CheckBackground") ? _customColors["CheckBackground"] : base.CheckBackground; } } 29 | public override Color CheckSelectedBackground { get { return _customColors.ContainsKey("CheckSelectedBackground") ? _customColors["CheckSelectedBackground"] : base.CheckSelectedBackground; } } 30 | public override Color CheckPressedBackground { get { return _customColors.ContainsKey("CheckPressedBackground") ? _customColors["CheckPressedBackground"] : base.CheckPressedBackground; } } 31 | public override Color GripDark { get { return _customColors.ContainsKey("GripDark") ? _customColors["GripDark"] : base.GripDark; } } 32 | public override Color GripLight { get { return _customColors.ContainsKey("GripLight") ? _customColors["GripLight"] : base.GripLight; } } 33 | public override Color ImageMarginGradientBegin { get { return _customColors.ContainsKey("ImageMarginGradientBegin") ? _customColors["ImageMarginGradientBegin"] : base.ImageMarginGradientBegin; } } 34 | public override Color ImageMarginGradientMiddle { get { return _customColors.ContainsKey("ImageMarginGradientMiddle") ? _customColors["ImageMarginGradientMiddle"] : base.ImageMarginGradientMiddle; } } 35 | public override Color ImageMarginGradientEnd { get { return _customColors.ContainsKey("ImageMarginGradientEnd") ? _customColors["ImageMarginGradientEnd"] : base.ImageMarginGradientEnd; } } 36 | public override Color ImageMarginRevealedGradientBegin { get { return _customColors.ContainsKey("ImageMarginRevealedGradientBegin") ? _customColors["ImageMarginRevealedGradientBegin"] : base.ImageMarginRevealedGradientBegin; } } 37 | public override Color ImageMarginRevealedGradientMiddle { get { return _customColors.ContainsKey("ImageMarginRevealedGradientMiddle") ? _customColors["ImageMarginRevealedGradientMiddle"] : base.ImageMarginRevealedGradientMiddle; } } 38 | public override Color ImageMarginRevealedGradientEnd { get { return _customColors.ContainsKey("ImageMarginRevealedGradientEnd") ? _customColors["ImageMarginRevealedGradientEnd"] : base.ImageMarginRevealedGradientEnd; } } 39 | public override Color MenuStripGradientBegin { get { return _customColors.ContainsKey("MenuStripGradientBegin") ? _customColors["MenuStripGradientBegin"] : base.MenuStripGradientBegin; } } 40 | public override Color MenuStripGradientEnd { get { return _customColors.ContainsKey("MenuStripGradientEnd") ? _customColors["MenuStripGradientEnd"] : base.MenuStripGradientEnd; } } 41 | public override Color MenuItemSelected { get { return _customColors.ContainsKey("MenuItemSelected") ? _customColors["MenuItemSelected"] : base.MenuItemSelected; } } 42 | public override Color MenuItemBorder { get { return _customColors.ContainsKey("MenuItemBorder") ? _customColors["MenuItemBorder"] : base.MenuItemBorder; } } 43 | public override Color MenuBorder { get { return _customColors.ContainsKey("MenuBorder") ? _customColors["MenuBorder"] : base.MenuBorder; } } 44 | public override Color MenuItemSelectedGradientBegin { get { return _customColors.ContainsKey("MenuItemSelectedGradientBegin") ? _customColors["MenuItemSelectedGradientBegin"] : base.MenuItemSelectedGradientBegin; } } 45 | public override Color MenuItemSelectedGradientEnd { get { return _customColors.ContainsKey("MenuItemSelectedGradientEnd") ? _customColors["MenuItemSelectedGradientEnd"] : base.MenuItemSelectedGradientEnd; } } 46 | public override Color MenuItemPressedGradientBegin { get { return _customColors.ContainsKey("MenuItemPressedGradientBegin") ? _customColors["MenuItemPressedGradientBegin"] : base.MenuItemPressedGradientBegin; } } 47 | public override Color MenuItemPressedGradientMiddle { get { return _customColors.ContainsKey("MenuItemPressedGradientMiddle") ? _customColors["MenuItemPressedGradientMiddle"] : base.MenuItemPressedGradientMiddle; } } 48 | public override Color MenuItemPressedGradientEnd { get { return _customColors.ContainsKey("MenuItemPressedGradientEnd") ? _customColors["MenuItemPressedGradientEnd"] : base.MenuItemPressedGradientEnd; } } 49 | public override Color RaftingContainerGradientBegin { get { return _customColors.ContainsKey("RaftingContainerGradientBegin") ? _customColors["RaftingContainerGradientBegin"] : base.RaftingContainerGradientBegin; } } 50 | public override Color RaftingContainerGradientEnd { get { return _customColors.ContainsKey("RaftingContainerGradientEnd") ? _customColors["RaftingContainerGradientEnd"] : base.RaftingContainerGradientEnd; } } 51 | public override Color SeparatorDark { get { return _customColors.ContainsKey("SeparatorDark") ? _customColors["SeparatorDark"] : base.SeparatorDark; } } 52 | public override Color SeparatorLight { get { return _customColors.ContainsKey("SeparatorLight") ? _customColors["SeparatorLight"] : base.SeparatorLight; } } 53 | public override Color StatusStripGradientBegin { get { return _customColors.ContainsKey("StatusStripGradientBegin") ? _customColors["StatusStripGradientBegin"] : base.StatusStripGradientBegin; } } 54 | public override Color StatusStripGradientEnd { get { return _customColors.ContainsKey("StatusStripGradientEnd") ? _customColors["StatusStripGradientEnd"] : base.StatusStripGradientEnd; } } 55 | public override Color ToolStripBorder { get { return _customColors.ContainsKey("ToolStripBorder") ? _customColors["ToolStripBorder"] : base.ToolStripBorder; } } 56 | public override Color ToolStripDropDownBackground { get { return _customColors.ContainsKey("ToolStripDropDownBackground") ? _customColors["ToolStripDropDownBackground"] : base.ToolStripDropDownBackground; } } 57 | public override Color ToolStripGradientBegin { get { return _customColors.ContainsKey("ToolStripGradientBegin") ? _customColors["ToolStripGradientBegin"] : base.ToolStripGradientBegin; } } 58 | public override Color ToolStripGradientMiddle { get { return _customColors.ContainsKey("ToolStripGradientMiddle") ? _customColors["ToolStripGradientMiddle"] : base.ToolStripGradientMiddle; } } 59 | public override Color ToolStripGradientEnd { get { return _customColors.ContainsKey("ToolStripGradientEnd") ? _customColors["ToolStripGradientEnd"] : base.ToolStripGradientEnd; } } 60 | public override Color ToolStripContentPanelGradientBegin { get { return _customColors.ContainsKey("ToolStripContentPanelGradientBegin") ? _customColors["ToolStripContentPanelGradientBegin"] : base.ToolStripContentPanelGradientBegin; } } 61 | public override Color ToolStripContentPanelGradientEnd { get { return _customColors.ContainsKey("ToolStripContentPanelGradientEnd") ? _customColors["ToolStripContentPanelGradientEnd"] : base.ToolStripContentPanelGradientEnd; } } 62 | public override Color ToolStripPanelGradientBegin { get { return _customColors.ContainsKey("ToolStripPanelGradientBegin") ? _customColors["ToolStripPanelGradientBegin"] : base.ToolStripPanelGradientBegin; } } 63 | public override Color ToolStripPanelGradientEnd { get { return _customColors.ContainsKey("ToolStripPanelGradientEnd") ? _customColors["ToolStripPanelGradientEnd"] : base.ToolStripPanelGradientEnd; } } 64 | public override Color OverflowButtonGradientBegin { get { return _customColors.ContainsKey("OverflowButtonGradientBegin") ? _customColors["OverflowButtonGradientBegin"] : base.OverflowButtonGradientBegin; } } 65 | public override Color OverflowButtonGradientMiddle { get { return _customColors.ContainsKey("OverflowButtonGradientMiddle") ? _customColors["OverflowButtonGradientMiddle"] : base.OverflowButtonGradientMiddle; } } 66 | public override Color OverflowButtonGradientEnd { get { return _customColors.ContainsKey("OverflowButtonGradientEnd") ? _customColors["OverflowButtonGradientEnd"] : base.OverflowButtonGradientEnd; } } 67 | 68 | public CustomColorTable(Dictionary customColors) 69 | { 70 | foreach (var customColor in customColors) 71 | { 72 | if (customColor.Value != Color.Empty) 73 | _customColors.Add(customColor.Key, customColor.Value); 74 | } 75 | } 76 | 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /KeeTheme/Theme/CustomTheme.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Drawing; 3 | using System.IO; 4 | using System.Windows.Forms; 5 | using KeePass.App; 6 | 7 | namespace KeeTheme.Theme 8 | { 9 | internal class CustomTheme : ITheme 10 | { 11 | public string Name { get; protected set; } 12 | 13 | public TreeViewDrawMode TreeViewDrawMode { get; protected set; } 14 | public Image ListViewBackground { get; protected set; } 15 | public bool ListViewBackgroundTiled { get; protected set; } 16 | public ToolStripRenderer ToolStripRenderer { get; protected set; } 17 | 18 | public OtherLook Other { get; private set; } 19 | public ControlLook Control { get; private set; } 20 | public ControlLook Form { get; private set; } 21 | public ButtonLook Button { get; private set; } 22 | public TreeViewLook TreeView { get; private set; } 23 | public RichTextBoxLook RichTextBox { get; private set; } 24 | public LinkLabelLook LinkLabel { get; private set; } 25 | public ListViewLook ListView { get; private set; } 26 | public ControlLook SecureTextBox { get; private set; } 27 | public CheckBoxLook CheckBox { get; private set; } 28 | public CheckBoxButtonLook CheckBoxButton { get; private set; } 29 | public MenuLook MenuItem { get; private set; } 30 | public PropertyGridLook PropertyGrid { get; private set; } 31 | 32 | public CustomTheme() 33 | { 34 | Name = "Dark Theme"; 35 | Other = new OtherLook(); 36 | Control = new ControlLook(); 37 | Form = new ControlLook(); 38 | Button = new ButtonLook(); 39 | TreeView = new TreeViewLook(); 40 | RichTextBox = new RichTextBoxLook(); 41 | LinkLabel = new LinkLabelLook(); 42 | ListView = new ListViewLook(); 43 | SecureTextBox = new ControlLook(); 44 | CheckBox = new CheckBoxLook(); 45 | CheckBoxButton = new CheckBoxButtonLook(); 46 | MenuItem = new MenuLook(); 47 | PropertyGrid = new PropertyGridLook(); 48 | } 49 | 50 | public CustomTheme(CustomThemeTemplate themeTemplate) : this() 51 | { 52 | Name = themeTemplate.Name; 53 | Other = themeTemplate.Other; 54 | Control = themeTemplate.Control; 55 | Form = themeTemplate.Form; 56 | Button = themeTemplate.Button; 57 | TreeView = themeTemplate.TreeView; 58 | RichTextBox = themeTemplate.RichTextBox; 59 | LinkLabel = themeTemplate.LinkLabel; 60 | ListView = themeTemplate.ListView; 61 | SecureTextBox = themeTemplate.SecureTextBox; 62 | CheckBox = themeTemplate.CheckBox; 63 | CheckBoxButton = themeTemplate.CheckBoxButton; 64 | MenuItem = themeTemplate.MenuItem; 65 | PropertyGrid = themeTemplate.PropertyGrid; 66 | 67 | ToolStripRenderer = GetToolStripRenderer(themeTemplate.ToolStrip); 68 | TreeViewDrawMode = TreeViewDrawMode.OwnerDrawText; 69 | 70 | if (!string.IsNullOrEmpty(ListView.BackgroundImage)) 71 | { 72 | var imagePath = Path.Combine(TemplateReader.GetTemplatesDir(), ListView.BackgroundImage); 73 | 74 | if (File.Exists(imagePath)) 75 | ListViewBackground = Image.FromFile(imagePath); 76 | } 77 | 78 | if (ListView.BackColor != Color.Empty && ListViewBackground == null) 79 | { 80 | ListViewBackgroundTiled = true; 81 | 82 | var bitmap = new Bitmap(1, 1); 83 | bitmap.SetPixel(0, 0, ListView.BackColor); 84 | ListViewBackground = bitmap; 85 | } 86 | } 87 | 88 | private ToolStripRenderer GetToolStripRenderer(ToolStripLook toolStripLook) 89 | { 90 | var toolStripLookProperties = typeof(ToolStripLook).GetProperties(); 91 | var customColors = new Dictionary(); 92 | foreach (var toolStripLookProperty in toolStripLookProperties) 93 | { 94 | customColors.Add(toolStripLookProperty.Name, (Color) toolStripLookProperty.GetValue(toolStripLook, null)); 95 | } 96 | var colorTable = new CustomColorTable(customColors); 97 | return new CustomToolStripRenderer(this, colorTable); 98 | } 99 | 100 | public static CustomTheme GetDefaultTheme() 101 | { 102 | var emptyTheme = new CustomTheme(); 103 | emptyTheme.Other.ControlNormalColor = SystemColors.Window; 104 | emptyTheme.Other.ControlDisabledColor = SystemColors.Control; 105 | emptyTheme.Other.ColorEditError = AppDefs.ColorEditError; 106 | emptyTheme.Button.FlatStyle = FlatStyle.Standard; 107 | emptyTheme.TreeView.BorderStyle = BorderStyle.Fixed3D; 108 | emptyTheme.RichTextBox.BorderStyle = BorderStyle.Fixed3D; 109 | emptyTheme.ListView.BorderStyle = BorderStyle.Fixed3D; 110 | emptyTheme.CheckBox.FlatStyle = FlatStyle.Standard; 111 | emptyTheme.CheckBoxButton.FlatStyle = FlatStyle.Standard; 112 | emptyTheme.ToolStripRenderer = ToolStripManager.Renderer; 113 | return emptyTheme; 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/CustomThemeTemplate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Windows.Forms; 6 | 7 | namespace KeeTheme.Theme 8 | { 9 | internal class CustomThemeTemplate 10 | { 11 | [Category("Theme")] 12 | public string Name { get; set; } 13 | [Browsable(false)] 14 | public Palette Palette { get; private set; } 15 | 16 | [Category("Appearance")] 17 | public OtherLook Other { get; private set; } 18 | [Category("Appearance")] 19 | public ControlLook Control { get; private set; } 20 | [Category("Appearance")] 21 | public ControlLook Form { get; private set; } 22 | [Category("Appearance")] 23 | public ButtonLook Button { get; private set; } 24 | [Category("Appearance")] 25 | public TreeViewLook TreeView { get; private set; } 26 | [Category("Appearance")] 27 | public RichTextBoxLook RichTextBox { get; private set; } 28 | [Category("Appearance")] 29 | public LinkLabelLook LinkLabel { get; private set; } 30 | [Category("Appearance")] 31 | public ListViewLook ListView { get; private set; } 32 | [Category("Appearance")] 33 | public ControlLook SecureTextBox { get; private set; } 34 | [Category("Appearance")] 35 | public CheckBoxLook CheckBox { get; private set; } 36 | [Category("Appearance")] 37 | public CheckBoxButtonLook CheckBoxButton { get; private set; } 38 | [Category("Appearance")] 39 | public MenuLook MenuItem { get; private set; } 40 | [Category("Appearance")] 41 | public ToolStripLook ToolStrip { get; private set; } 42 | [Category("Appearance")] 43 | public PropertyGridLook PropertyGrid { get; private set; } 44 | 45 | private CustomThemeTemplate() 46 | { 47 | Name = "Dark Theme"; 48 | Palette = new Palette(); 49 | Other = new OtherLook(); 50 | Control = new ControlLook(); 51 | Form = new ControlLook(); 52 | Button = new ButtonLook(); 53 | TreeView = new TreeViewLook(); 54 | RichTextBox = new RichTextBoxLook(); 55 | LinkLabel = new LinkLabelLook(); 56 | ListView = new ListViewLook(); 57 | SecureTextBox = new ControlLook(); 58 | CheckBox = new CheckBoxLook(); 59 | CheckBoxButton = new CheckBoxButtonLook(); 60 | MenuItem = new MenuLook(); 61 | ToolStrip = new ToolStripLook(); 62 | PropertyGrid = new PropertyGridLook(); 63 | } 64 | 65 | public CustomThemeTemplate(IniFile iniFile) : this() 66 | { 67 | var themeSection = iniFile.GetSection("KeeTheme"); 68 | if (themeSection.ContainsKey("Name")) 69 | Name = themeSection["Name"]; 70 | 71 | var paletteSection = iniFile.GetSection("Palette"); 72 | Palette = new Palette(paletteSection); 73 | 74 | var otherSection = iniFile.GetSection("Other"); 75 | LoadLook(otherSection, Palette, Other); 76 | 77 | var controlSection = iniFile.GetSection("Control"); 78 | LoadLook(controlSection, Palette, Control); 79 | 80 | var formSection = iniFile.GetSection("Form"); 81 | LoadLook(formSection, Palette, Form); 82 | 83 | var buttonSection = iniFile.GetSection("Button"); 84 | LoadLook(buttonSection, Palette, Button); 85 | 86 | var treeViewSection = iniFile.GetSection("TreeView"); 87 | LoadLook(treeViewSection, Palette, TreeView); 88 | 89 | var richTextBoxSection = iniFile.GetSection("RichTextBox"); 90 | LoadLook(richTextBoxSection, Palette, RichTextBox); 91 | 92 | var linkLabelSection = iniFile.GetSection("LinkLabel"); 93 | LoadLook(linkLabelSection, Palette, LinkLabel); 94 | 95 | var listViewSection = iniFile.GetSection("ListView"); 96 | LoadLook(listViewSection, Palette, ListView); 97 | 98 | var secureTextBoxSection = iniFile.GetSection("SecureTextBox"); 99 | LoadLook(secureTextBoxSection, Palette, SecureTextBox); 100 | 101 | var checkBoxSection = iniFile.GetSection("CheckBox"); 102 | LoadLook(checkBoxSection, Palette, CheckBox); 103 | 104 | var checkBoxButtonSection = iniFile.GetSection("CheckBoxButton"); 105 | LoadLook(checkBoxButtonSection, Palette, CheckBoxButton); 106 | 107 | var menuItemSection = iniFile.GetSection("MenuItem"); 108 | LoadLook(menuItemSection, Palette, MenuItem); 109 | 110 | var toolStripSection = iniFile.GetSection("ToolStrip"); 111 | LoadLook(toolStripSection, Palette, ToolStrip); 112 | 113 | var propertyGridSection = iniFile.GetSection("PropertyGrid"); 114 | LoadLook(propertyGridSection, Palette, PropertyGrid); 115 | } 116 | 117 | private static void LoadLook(Dictionary controlSection, Palette palette, T look) 118 | { 119 | var properties = look.GetType().GetProperties(); 120 | foreach (var property in properties) 121 | { 122 | string value; 123 | if (!controlSection.TryGetValue(property.Name, out value)) 124 | continue; 125 | 126 | if (string.IsNullOrEmpty(value)) 127 | continue; 128 | 129 | if (property.PropertyType == typeof(Color)) 130 | property.SetValue(look, palette.GetColor(controlSection[property.Name]), null); 131 | 132 | if (property.PropertyType == typeof(FlatStyle)) 133 | property.SetValue(look, Enum.Parse(typeof(FlatStyle), value, true), null); 134 | 135 | if (property.PropertyType == typeof(BorderStyle)) 136 | property.SetValue(look, Enum.Parse(typeof(BorderStyle), value, true), null); 137 | 138 | if (property.PropertyType == typeof(ContentAlignment)) 139 | property.SetValue(look, Enum.Parse(typeof(ContentAlignment), value, true), null); 140 | 141 | if (property.PropertyType == typeof(string)) 142 | property.SetValue(look, value, null); 143 | } 144 | } 145 | 146 | public IniFile GetIniFile() 147 | { 148 | var iniFile = new IniFile(); 149 | 150 | var section = iniFile.AddSection("KeeTheme"); 151 | section.Add("Name", Name); 152 | 153 | SavePalette(iniFile, Palette); 154 | SaveLook(iniFile, "Other", Other); 155 | SaveLook(iniFile, "Control", Control); 156 | SaveLook(iniFile, "Form", Form); 157 | SaveLook(iniFile, "Button", Button); 158 | SaveLook(iniFile, "TreeView", TreeView); 159 | SaveLook(iniFile, "RichTextBox", RichTextBox); 160 | SaveLook(iniFile, "LinkLabel", LinkLabel); 161 | SaveLook(iniFile, "ListView", ListView); 162 | SaveLook(iniFile, "SecureTextBox", SecureTextBox); 163 | SaveLook(iniFile, "CheckBox", CheckBox); 164 | SaveLook(iniFile, "CheckBoxButton", CheckBoxButton); 165 | SaveLook(iniFile, "MenuItem", MenuItem); 166 | SaveLook(iniFile, "ToolStrip", ToolStrip); 167 | SaveLook(iniFile, "PropertyGrid", PropertyGrid); 168 | 169 | return iniFile; 170 | } 171 | 172 | private void SavePalette(IniFile iniFile, Palette palette) 173 | { 174 | var section = iniFile.AddSection("Palette"); 175 | var colors = palette.GetColors(); 176 | for (int i = 0; i < colors.Length; i++) 177 | { 178 | section.Add("Color" + i, GetColorTextValue(colors[i])); 179 | } 180 | } 181 | 182 | private void SaveLook(IniFile iniFile, string sectionName, T look) 183 | { 184 | var properties = look.GetType().GetProperties(); 185 | var section = iniFile.AddSection(sectionName); 186 | foreach (var property in properties) 187 | { 188 | var value = property.GetValue(look, null) ?? string.Empty; 189 | var textValue = value.ToString(); 190 | if (property.PropertyType == typeof(Color)) 191 | textValue = GetColorTextValue((Color) value); 192 | 193 | section.Add(property.Name, textValue); 194 | } 195 | } 196 | 197 | private string GetColorTextValue(Color value) 198 | { 199 | return value == Color.Empty ? "" : string.Format("({0}, {1}, {2})", value.R, value.G, value.B); 200 | } 201 | } 202 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/CustomToolStripRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Windows.Forms; 3 | using KeePass.UI.ToolStripRendering; 4 | 5 | namespace KeeTheme.Theme 6 | { 7 | class CustomToolStripRenderer : ProExtTsr 8 | { 9 | private readonly CustomTheme _customTheme; 10 | 11 | protected override bool EnsureTextContrast 12 | { 13 | get { return false; } 14 | } 15 | 16 | public CustomToolStripRenderer(CustomTheme customTheme, ProfessionalColorTable ct) : base(ct) 17 | { 18 | _customTheme = customTheme; 19 | } 20 | 21 | protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e) 22 | { 23 | if (e.Item.Pressed || e.Item.Selected) 24 | { 25 | e.TextColor = _customTheme.MenuItem.HighlightColor; 26 | } 27 | 28 | base.OnRenderItemText(e); 29 | } 30 | 31 | protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e) 32 | { 33 | var ms = e.ToolStrip as MenuStrip; 34 | if (ms != null) 35 | { 36 | using (var menuBackgroundBrush = new SolidBrush(_customTheme.MenuItem.BackColor)) 37 | { 38 | e.Graphics.FillRectangle(menuBackgroundBrush, e.AffectedBounds); 39 | } 40 | } 41 | else 42 | { 43 | base.OnRenderToolStripBackground(e); 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /KeeTheme/Theme/ITheme.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Windows.Forms; 3 | 4 | namespace KeeTheme.Theme 5 | { 6 | internal interface ITheme 7 | { 8 | string Name { get; } 9 | 10 | TreeViewDrawMode TreeViewDrawMode { get; } 11 | Image ListViewBackground { get; } 12 | bool ListViewBackgroundTiled { get; } 13 | ToolStripRenderer ToolStripRenderer { get; } 14 | 15 | OtherLook Other { get; } 16 | ControlLook Control { get; } 17 | ControlLook Form { get; } 18 | ButtonLook Button { get; } 19 | TreeViewLook TreeView { get; } 20 | RichTextBoxLook RichTextBox { get; } 21 | LinkLabelLook LinkLabel { get; } 22 | ListViewLook ListView { get; } 23 | ControlLook SecureTextBox { get; } 24 | CheckBoxLook CheckBox { get; } 25 | CheckBoxButtonLook CheckBoxButton { get; } 26 | MenuLook MenuItem { get; } 27 | PropertyGridLook PropertyGrid { get; } 28 | } 29 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/IniFile.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Text; 4 | 5 | namespace KeeTheme.Theme 6 | { 7 | class IniFile 8 | { 9 | readonly Dictionary> _sections = new Dictionary>(); 10 | 11 | public Dictionary GetSection(string name) 12 | { 13 | if (_sections.ContainsKey(name)) 14 | return new Dictionary(_sections[name]); 15 | 16 | return new Dictionary(); 17 | } 18 | 19 | public Dictionary AddSection(string name) 20 | { 21 | Dictionary section; 22 | if (_sections.TryGetValue(name, out section)) 23 | return section; 24 | 25 | section = new Dictionary(); 26 | _sections.Add(name, section); 27 | return section; 28 | } 29 | 30 | public IniFile() 31 | { 32 | } 33 | 34 | public IniFile(TextReader tr) 35 | { 36 | string currentSection = null; 37 | 38 | string line; 39 | while ((line = tr.ReadLine()) != null) 40 | { 41 | line = line.Trim(); 42 | 43 | if (string.IsNullOrEmpty(line) || line.StartsWith(";")) 44 | continue; 45 | 46 | if (line.StartsWith("[") && line.EndsWith("]")) 47 | { 48 | var sectionName = line.Substring(1, line.Length - 2); 49 | if (!_sections.ContainsKey(sectionName)) 50 | _sections.Add(sectionName, new Dictionary()); 51 | 52 | currentSection = sectionName; 53 | continue; 54 | } 55 | 56 | if (currentSection == null) 57 | throw new InvalidDataException("Section is missing!"); 58 | 59 | var keyValuePair = line.Split(new[] { '=' }, 2); 60 | if (keyValuePair.Length == 1) 61 | throw new InvalidDataException("Line should have format 'key = value'!"); 62 | 63 | _sections[currentSection][keyValuePair[0].Trim()] = keyValuePair[1].Trim(); 64 | } 65 | } 66 | 67 | public void SaveFile(string path) 68 | { 69 | var sb = new StringBuilder(); 70 | foreach (var section in _sections) 71 | { 72 | sb.AppendLine(string.Format("[{0}]", section.Key)); 73 | foreach (var item in section.Value) 74 | { 75 | sb.AppendLine(string.Format("{0} = {1}", item.Key, item.Value)); 76 | } 77 | 78 | sb.AppendLine(); 79 | } 80 | File.WriteAllText(path, sb.ToString()); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /KeeTheme/Theme/LinkLabelLook.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using KeeTheme.Editor; 4 | 5 | namespace KeeTheme.Theme 6 | { 7 | [TypeConverter(typeof(LinkLabelLookTypeConverter))] 8 | class LinkLabelLook : ControlLook 9 | { 10 | public Color LinkColor { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/ListViewLook.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using System.Drawing.Design; 4 | using System.Windows.Forms; 5 | using System.Windows.Forms.Design; 6 | using KeeTheme.Editor; 7 | 8 | namespace KeeTheme.Theme 9 | { 10 | [TypeConverter(typeof(ListViewLookTypeConverter))] 11 | class ListViewLook : ControlLook 12 | { 13 | public BorderStyle BorderStyle { get; set; } 14 | public Color OddRowColor { get; set; } 15 | public Color EvenRowColor { get; set; } 16 | public Color ColumnBorderColor { get; set; } 17 | public Color HeaderBackColor { get; set; } 18 | public Color HeaderForeColor { get; set; } 19 | public Color HeaderColumnBorderColor { get; set; } 20 | public Color GroupBackColor { get; set; } 21 | public Color GroupForeColor { get; set; } 22 | public Color GroupHighlightColor { get; set; } 23 | [DefaultValue(ContentAlignment.TopLeft)] 24 | public ContentAlignment BackgroundImageAlignment { get; set; } 25 | [DefaultValue("")] 26 | [Editor(typeof(FileNameEditor), typeof(UITypeEditor))] 27 | public string BackgroundImage { get; set; } 28 | } 29 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/MenuLook.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using KeeTheme.Editor; 4 | 5 | namespace KeeTheme.Theme 6 | { 7 | [TypeConverter(typeof(MenuLookTypeConverter))] 8 | class MenuLook : ControlLook 9 | { 10 | public Color HighlightColor { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/OtherLook.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using KeeTheme.Editor; 4 | 5 | namespace KeeTheme.Theme 6 | { 7 | [TypeConverter(typeof(OtherLookTypeConverter))] 8 | class OtherLook 9 | { 10 | public Color ControlNormalColor { get; set; } 11 | public Color ControlDisabledColor { get; set; } 12 | public Color ColorEditError { get; set; } 13 | 14 | public override string ToString() 15 | { 16 | return GetType().Name; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/Palette.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Globalization; 5 | using System.IO; 6 | using System.Linq; 7 | 8 | namespace KeeTheme.Theme 9 | { 10 | class Palette 11 | { 12 | private readonly Dictionary _colorsByName = new Dictionary(); 13 | 14 | public Palette() 15 | { 16 | } 17 | 18 | public Palette(Dictionary colors) 19 | { 20 | foreach (var colorName in colors.Keys) 21 | { 22 | _colorsByName[colorName] = ParseColor(colors[colorName]); 23 | } 24 | } 25 | 26 | public Color[] GetColors() 27 | { 28 | return _colorsByName.Values.ToArray(); 29 | } 30 | 31 | public Color GetColor(string color) 32 | { 33 | return _colorsByName.ContainsKey(color) ? _colorsByName[color] : ParseColor(color); 34 | } 35 | 36 | public static Color ParseColor(string color) 37 | { 38 | if (string.IsNullOrEmpty(color)) 39 | return Color.Empty; 40 | 41 | // Format: #aabbcc 42 | if (color.StartsWith("#") && color.Length == 7) 43 | return Color.FromArgb(int.Parse("FF" + color.Substring(1), NumberStyles.AllowHexSpecifier)); 44 | 45 | // Format: #abc 46 | if (color.StartsWith("#") && color.Length == 4) 47 | return Color.FromArgb(int.Parse("FF" + color[1] + color[1] + color[2] + color[2] + color[3] + color[3], 48 | NumberStyles.AllowHexSpecifier)); 49 | 50 | // Format: (64,64,64) 51 | if (color.StartsWith("(") && color.EndsWith(")")) 52 | { 53 | var rgb = color.Substring(1, color.Length - 2).Split(','); 54 | return Color.FromArgb(int.Parse(rgb[0]), int.Parse(rgb[1]), int.Parse(rgb[2])); 55 | } 56 | 57 | throw new InvalidDataException("Unknown color '" + color + "'!"); 58 | } 59 | 60 | public void FromBgrArray(int[] colors) 61 | { 62 | _colorsByName.Clear(); 63 | for (int i = 0; i < colors.Length; i++) 64 | { 65 | var colorBgr = BitConverter.GetBytes(colors[i]); 66 | var colorRgb = Color.FromArgb(colorBgr[2], colorBgr[1], colorBgr[0]); 67 | _colorsByName.Add("Color" + i, colorRgb); 68 | } 69 | } 70 | 71 | public int[] ToBgrArray() 72 | { 73 | var colors = new List(); 74 | foreach (var color in _colorsByName.Values) 75 | { 76 | var bgrColor = (color.B << 16) + (color.G << 8) + color.R; 77 | colors.Add(bgrColor); 78 | } 79 | 80 | return colors.ToArray(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /KeeTheme/Theme/PropertyGridLook.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using KeeTheme.Editor; 4 | 5 | namespace KeeTheme.Theme 6 | { 7 | [TypeConverter(typeof(PropertyGridLookTypeConverter))] 8 | class PropertyGridLook : ControlLook 9 | { 10 | public Color LineColor { get; set; } 11 | public Color CategoryForeColor{ get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/RichTextBoxLook.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | using KeeTheme.Editor; 5 | 6 | namespace KeeTheme.Theme 7 | { 8 | [TypeConverter(typeof(RichTextBoxLookTypeConverter))] 9 | class RichTextBoxLook : ControlLook 10 | { 11 | public BorderStyle BorderStyle { get; set; } 12 | public Color SelectionColor { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/ToolStripLook.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using KeeTheme.Editor; 4 | 5 | namespace KeeTheme.Theme 6 | { 7 | [TypeConverter(typeof(ToolStripLookTypeConverter))] 8 | class ToolStripLook 9 | { 10 | public Color ButtonSelectedHighlight { get; set; } 11 | public Color ButtonSelectedHighlightBorder { get; set; } 12 | public Color ButtonPressedHighlight { get; set; } 13 | public Color ButtonPressedHighlightBorder { get; set; } 14 | public Color ButtonCheckedHighlight { get; set; } 15 | public Color ButtonCheckedHighlightBorder { get; set; } 16 | public Color ButtonPressedBorder { get; set; } 17 | public Color ButtonSelectedBorder { get; set; } 18 | public Color ButtonCheckedGradientBegin { get; set; } 19 | public Color ButtonCheckedGradientMiddle { get; set; } 20 | public Color ButtonCheckedGradientEnd { get; set; } 21 | public Color ButtonSelectedGradientBegin { get; set; } 22 | public Color ButtonSelectedGradientMiddle { get; set; } 23 | public Color ButtonSelectedGradientEnd { get; set; } 24 | public Color ButtonPressedGradientBegin { get; set; } 25 | public Color ButtonPressedGradientMiddle { get; set; } 26 | public Color ButtonPressedGradientEnd { get; set; } 27 | public Color CheckBackground { get; set; } 28 | public Color CheckSelectedBackground { get; set; } 29 | public Color CheckPressedBackground { get; set; } 30 | public Color GripDark { get; set; } 31 | public Color GripLight { get; set; } 32 | public Color ImageMarginGradientBegin { get; set; } 33 | public Color ImageMarginGradientMiddle { get; set; } 34 | public Color ImageMarginGradientEnd { get; set; } 35 | public Color ImageMarginRevealedGradientBegin { get; set; } 36 | public Color ImageMarginRevealedGradientMiddle { get; set; } 37 | public Color ImageMarginRevealedGradientEnd { get; set; } 38 | public Color MenuStripGradientBegin { get; set; } 39 | public Color MenuStripGradientEnd { get; set; } 40 | public Color MenuItemSelected { get; set; } 41 | public Color MenuItemBorder { get; set; } 42 | public Color MenuBorder { get; set; } 43 | public Color MenuItemSelectedGradientBegin { get; set; } 44 | public Color MenuItemSelectedGradientEnd { get; set; } 45 | public Color MenuItemPressedGradientBegin { get; set; } 46 | public Color MenuItemPressedGradientMiddle { get; set; } 47 | public Color MenuItemPressedGradientEnd { get; set; } 48 | public Color RaftingContainerGradientBegin { get; set; } 49 | public Color RaftingContainerGradientEnd { get; set; } 50 | public Color SeparatorDark { get; set; } 51 | public Color SeparatorLight { get; set; } 52 | public Color StatusStripGradientBegin { get; set; } 53 | public Color StatusStripGradientEnd { get; set; } 54 | public Color ToolStripBorder { get; set; } 55 | public Color ToolStripDropDownBackground { get; set; } 56 | public Color ToolStripGradientBegin { get; set; } 57 | public Color ToolStripGradientMiddle { get; set; } 58 | public Color ToolStripGradientEnd { get; set; } 59 | public Color ToolStripContentPanelGradientBegin { get; set; } 60 | public Color ToolStripContentPanelGradientEnd { get; set; } 61 | public Color ToolStripPanelGradientBegin { get; set; } 62 | public Color ToolStripPanelGradientEnd { get; set; } 63 | public Color OverflowButtonGradientBegin { get; set; } 64 | public Color OverflowButtonGradientMiddle { get; set; } 65 | public Color OverflowButtonGradientEnd { get; set; } 66 | 67 | public override string ToString() 68 | { 69 | return GetType().Name; 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /KeeTheme/Theme/TreeViewLook.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | using KeeTheme.Editor; 5 | 6 | namespace KeeTheme.Theme 7 | { 8 | [TypeConverter(typeof(TreeViewLookTypeConverter))] 9 | class TreeViewLook : ControlLook 10 | { 11 | public Color SelectionColor { get; set; } 12 | public Color SelectionBackColor { get; set; } 13 | public BorderStyle BorderStyle { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /KeeTheme/Win10ThemeMonitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Windows.Forms; 4 | using KeePass.Util; 5 | using KeeTheme.Options; 6 | using Microsoft.Win32; 7 | 8 | namespace KeeTheme 9 | { 10 | internal class Win10ThemeMonitor 11 | { 12 | [DllImport("dwmapi.dll")] 13 | private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize); 14 | 15 | private const int DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19; 16 | private const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20; 17 | 18 | private readonly KeeThemeOptions _options; 19 | 20 | public Win10ThemeMonitor(KeeThemeOptions options) 21 | { 22 | _options = options; 23 | } 24 | 25 | public void Initialize() 26 | { 27 | if (WinUtil.IsAtLeastWindows10) 28 | { 29 | if (_options.AutoSyncWithWin10Theme) 30 | { 31 | _options.Enabled = IsDarkThemeEnabled(); 32 | } 33 | _options.AutoSyncWithWin10ThemeChanged += HandleAutoSyncWithWin10ThemeChanged; 34 | SystemEvents.UserPreferenceChanged += HandleUserPreferenceChanged; 35 | } 36 | } 37 | 38 | private void HandleAutoSyncWithWin10ThemeChanged(bool value) 39 | { 40 | ApplyTheme(); 41 | } 42 | 43 | private void HandleUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) 44 | { 45 | ApplyTheme(); 46 | } 47 | 48 | private void ApplyTheme() 49 | { 50 | if (_options.AutoSyncWithWin10Theme) 51 | _options.Enabled = IsDarkThemeEnabled(); 52 | } 53 | 54 | private bool IsDarkThemeEnabled() 55 | { 56 | var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"); 57 | return key != null && (int) key.GetValue("AppsUseLightTheme", 1) != 1; 58 | } 59 | 60 | public static void UseImmersiveDarkMode(Form form, bool enabled) 61 | { 62 | if (form.IsHandleCreated) 63 | { 64 | if (UseImmersiveDarkMode(form.Handle, enabled)) 65 | { 66 | // Hack: I have found no other way to redraw title bar 67 | var borderStyle = form.FormBorderStyle; 68 | form.FormBorderStyle = FormBorderStyle.None; 69 | form.FormBorderStyle = borderStyle; 70 | } 71 | } 72 | else 73 | { 74 | form.HandleCreated += (o, args) => UseImmersiveDarkMode(form.Handle, enabled); 75 | } 76 | } 77 | 78 | private static bool UseImmersiveDarkMode(IntPtr handle, bool enabled) 79 | { 80 | if (IsWindows10OrGreater(17763)) 81 | { 82 | var attribute = DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1; 83 | if (IsWindows10OrGreater(18985)) 84 | { 85 | attribute = DWMWA_USE_IMMERSIVE_DARK_MODE; 86 | } 87 | 88 | int useImmersiveDarkMode = enabled ? 1 : 0; 89 | return DwmSetWindowAttribute(handle, attribute, ref useImmersiveDarkMode, sizeof(int)) == 0; 90 | } 91 | 92 | return false; 93 | } 94 | 95 | private static bool IsWindows10OrGreater(int build) 96 | { 97 | if (!WinUtil.IsAtLeastWindows10) 98 | return false; 99 | 100 | try 101 | { 102 | var registryKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", false); 103 | if (registryKey != null) 104 | { 105 | uint result; 106 | if (uint.TryParse(registryKey.GetValue("CurrentBuildNumber", string.Empty).ToString(), out result)) 107 | return result >= build; 108 | } 109 | } 110 | catch (Exception) 111 | { 112 | // ignored 113 | } 114 | 115 | return false; 116 | } 117 | 118 | } 119 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Krzysztof Łaputa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KeeTheme 2 | 3 | [![Version](https://img.shields.io/github/release/xatupal/KeeTheme)](https://github.com/xatupal/KeeTheme/releases/latest) 4 | [![Releasedate](https://img.shields.io/github/release-date/xatupal/KeeTheme)](https://github.com/xatupal/KeeTheme/releases/latest) 5 | [![Downloads](https://img.shields.io/github/downloads/xatupal/KeeTheme/total)](https://github.com/xatupal/KeeTheme/releases/latest/download/KeeTheme.plgx) 6 | 7 | KeePass Plugin 8 | 9 | Plugin changes the appearance of KeePass, to make it look better at night. 10 | 11 | You can enable it using hotkey `CTRL+T` or using the menu `Tools -> DarkTheme`. 12 | 13 | ### Options 14 | 15 | In [options](docs/KeePassDarkThemeCustomOptions.png) `Tools -> Options... -> KeeTheme` you can: 16 | * Select a theme 17 | * Create your own theme 18 | * Change the default hotkey 19 | * Auto-sync with Windows 10 theme 20 | 21 | ### Customizations 22 | 23 | You can use built-in theme editor to create your own theme. 24 | Custom themes should be saved in the plugins folder. 25 | 26 | ![Theme editor](docs/KeePassDarkThemeEditor.png) 27 | 28 | 29 | ### Installation 30 | 31 | Copy [KeeTheme.dll](https://github.com/xatupal/KeeTheme/releases/latest/download/KeeTheme.dll) or [KeeTheme.plgx](https://github.com/xatupal/KeeTheme/releases/latest/download/KeeTheme.plgx) to the KeePass Plugins directory or install via [Chocolatey](https://chocolatey.org): 32 | 33 | ``` 34 | choco install keepass-plugin-keetheme 35 | ``` 36 | 37 | ### Note 38 | 39 | KeePass was created using standard Windows controls, which unfortunately were not designed for easy customization. They are extremely resistant to any attempts to change their appearance, especially from a plugin which has no control over their creation. 40 | 41 | Therefore the plugin is not perfect and will never be, but is good enough to use it. 42 | 43 | ### Screenshots 44 | #### DarkTheme 45 | 46 | ![Main form](docs/KeePassDarkTheme.png) 47 | 48 | ![Open database](docs/KeePassDarkThemeOpenDatabase.png) 49 | 50 | ![Options](docs/KeePassDarkThemeOptions.png) 51 | 52 | #### DarkThemeWin11 53 | 54 | ![Main form](docs/KeePassDarkThemeWin11.png) 55 | 56 | ![Open database](docs/KeePassDarkThemeWin11OpenDatabase.png) 57 | 58 | ![Options](docs/KeePassDarkThemeWin11Options.png) 59 | -------------------------------------------------------------------------------- /build/build.cmd: -------------------------------------------------------------------------------- 1 | rem Build dll 2 | set msbuild_path=msbuild 3 | if not "%JetBrains Rider%"=="" ( 4 | echo Loading JetBrains Rider Tools 5 | set msbuild_path="%JetBrains Rider:;=%\..\tools\MSBuild\Current\Bin\MSBuild.exe" 6 | ) else ( 7 | echo Loading Visual Studio Tools 8 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat" 9 | ) 10 | 11 | echo Compiling Dll 12 | %msbuild_path% ..\KeeTheme.sln /p:Configuration=Release /p:LangVersion=3 13 | 14 | echo Releasing Dll 15 | copy ..\KeeTheme\bin\Release\KeeTheme.dll .\KeeTheme.dll 16 | 17 | rem Build plgx 18 | echo Deleting existing PlgX folder 19 | rmdir /s /q "PlgX" 20 | 21 | echo Creating PlgX folder 22 | mkdir "PlgX" 23 | 24 | echo Copying files 25 | xcopy "..\KeeTheme\*" "PlgX" /s /e /exclude:PlgXExclude.txt 26 | 27 | echo Compiling PlgX 28 | "C:\Program Files\KeePass Password Safe 2\KeePass.exe" /plgx-create "%cd%\PlgX" --debug --plgx-prereq-net:3.5 29 | 30 | echo Releasing PlgX 31 | move /y "PlgX.plgx" "KeeTheme.plgx" 32 | 33 | echo Cleaning up 34 | rmdir /s /q "PlgX" 35 | 36 | pause -------------------------------------------------------------------------------- /build/plgxexclude.txt: -------------------------------------------------------------------------------- 1 | bin\ 2 | obj\ 3 | .idea\ 4 | .vs 5 | .git 6 | .user 7 | .sln 8 | .suo 9 | .pdb 10 | build.cmd 11 | plgxexclude.txt 12 | KeeTheme.dll 13 | KeeTheme.plgx -------------------------------------------------------------------------------- /choco/keetheme.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | keepass-plugin-keetheme 5 | KeePass Plugin KeeTheme 6 | 0.10.6 7 | Krzysztof Łaputa 8 | xatupal 9 | Plugin changes the appearance of KeePass, to make it look better at night 10 | 11 | You can enable it using hotkey `CTRL+T` or using the menu `Tools -> DarkTheme`. 12 | The plugin allows you to create your own theme. 13 | 14 | [Announcement](https://sourceforge.net/p/keepass/discussion/329220/thread/fcd9700f30/) 15 | 16 | https://github.com/xatupal/KeeTheme/tree/master/choco 17 | https://github.com/xatupal/KeeTheme 18 | https://github.com/xatupal/KeeTheme 19 | https://github.com/xatupal/KeeTheme/issues 20 | https://cdn.statically.io/gh/xatupal/KeeTheme/c7ff30ad7f600d80f490b2186b11061c95012f78/KeeTheme/Resources/PluginIcon.png 21 | keepass plugin custom customization theme dark 22 | © 2019 Krzysztof Łaputa 23 | https://github.com/xatupal/KeeTheme/blob/master/LICENSE 24 | false 25 | 26 | #### Program 27 | * [Changelog](https://github.com/xatupal/KeeTheme/releases) 28 | 29 | #### Package 30 | * Automatically built and uploaded by [xatupal](https://chocolatey.org/profiles/xatupal) 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /choco/publish.ps1: -------------------------------------------------------------------------------- 1 | param ( 2 | [string]$apiKey = "" 3 | ) 4 | 5 | If ($apiKey -eq "") 6 | { 7 | Write-Host "Choco API key was not provided. Trying to read from choco.key file." 8 | $apiKey = Get-Content choco.key 9 | } 10 | 11 | If ($apiKey -eq "") 12 | { 13 | Write-Host "Choco API key not found!" 14 | Break 15 | } 16 | 17 | Write-Host "Getting latest KeeTheme version..." 18 | $AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12' 19 | [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols 20 | 21 | $latestUrl = "https://github.com/xatupal/KeeTheme/releases/latest" 22 | $request = [System.Net.WebRequest]::Create($latestUrl) 23 | $request.AllowAutoRedirect=$false 24 | $response=$request.GetResponse() 25 | 26 | If ($response.StatusCode -ne "Found") 27 | { 28 | Write-Host "Unable to find latest version!" 29 | Break 30 | } 31 | 32 | $latestTagUrl = $response.GetResponseHeader("Location") 33 | $latestTag = $latestTagUrl -Split "/" | Select-Object -Last 1 34 | $version = $latestTag.TrimStart("v") 35 | Write-Host "Latest version: " $version 36 | 37 | Write-Host "Downloading KeeTheme.plgx..." 38 | $downloadUrl = "https://github.com/xatupal/KeeTheme/releases/download/$latestTag/KeeTheme.plgx" 39 | Invoke-WebRequest -Uri $downloadUrl -OutFile "KeeTheme.plgx" 40 | Write-Host "KeeTheme plugin downloaded" 41 | 42 | Write-Host "Updating Choco files..." 43 | $content = Get-Content -path "keetheme.nuspec" 44 | $content -Replace '\(.+)\', "$version" | Out-File -Encoding "UTF8" "keetheme.nuspec" 45 | 46 | $content = Get-Content -path "tools\common.ps1" 47 | $content -Replace '\$url = ''(.+)''', "`$url = '$downloadUrl'" | Out-File -Encoding "UTF8" "tools\common.ps1" 48 | 49 | $checksum = (Get-FileHash -algorithm sha256 "KeeTheme.plgx").Hash 50 | $content = Get-Content -path "tools\common.ps1" 51 | $content -Replace '\$checksum = ''(.+)''', "`$checksum = '$checksum'" | Out-File -Encoding "UTF8" "tools\common.ps1" 52 | Write-Host "Choco files updated" 53 | 54 | Write-Host "Creating Choco package..." 55 | choco pack 56 | Write-Host "Choco package keepass-plugin-keetheme.$version.nupkg created!" 57 | 58 | $reply = Read-Host -Prompt "Ready to push?[y/n]" 59 | If ($reply -match "[yY]") 60 | { 61 | Write-Host "Pushing Choco package..." 62 | choco push keepass-plugin-keetheme.$version.nupkg -s https://chocolatey.org --api-key=$apiKey 63 | Write-Host "Choco package pushed!" 64 | } 65 | pause 66 | -------------------------------------------------------------------------------- /choco/tools/chocolateyinstall.ps1: -------------------------------------------------------------------------------- 1 | $toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" 2 | 3 | function Install-Plugin { 4 | $pluginPath = Get-KeePassPluginsPath 5 | $pluginFile = Join-Path $toolsDir $fileName 6 | 7 | Write-Verbose "Downloading into tools dir." 8 | Get-ChocolateyWebFile -PackageName "$packageName" -FileFullPath "$pluginFile" ` 9 | -Url "$url" ` 10 | -Checksum "$checksum" ` 11 | -ChecksumType "$checksumType" 12 | 13 | # rename PLGX file so it is clear which plugins are managed via choco 14 | $pluginChocoFile = Join-Path $pluginPath "$($packageName).plgx" 15 | Move-Item -Path $pluginFile -Destination $pluginChocoFile -Force 16 | Write-Verbose "Moving to plugins directory." 17 | 18 | if ( Get-Process -Name "KeePass" -ErrorAction SilentlyContinue ) { 19 | Write-Warning "$($packageSearch) is currently running. Plugin will be available at next restart of $($packageSearch)." 20 | } else { 21 | Write-Host "$($packageName) will be loaded the next time KeePass is started." 22 | } 23 | } 24 | 25 | . "${toolsDir}\common.ps1" 26 | Install-Plugin 27 | -------------------------------------------------------------------------------- /choco/tools/chocolateyuninstall.ps1: -------------------------------------------------------------------------------- 1 | function Uninstall-Plugin { 2 | Write-Verbose "Checking KeePass is not running..." 3 | if (Get-Process -Name "KeePass" -ErrorAction SilentlyContinue) { 4 | Write-Warning "$($packageSearch) is running. Please save any opened databases and close $($packageSearch) before attempting to uninstall KeePass plugins." 5 | exit 1 6 | } 7 | 8 | $pluginPath = Get-KeePassPluginsPath 9 | $pluginFile = Join-Path $pluginPath $fileName 10 | $pluginChocoFile = Join-Path $pluginPath "$($packageName).plgx" 11 | if (Test-Path $pluginFile) { 12 | Write-Warning "$(fileName) was found but it is not managed by Chocolatey." 13 | Write-Warning "If you intend to remove it anyway, please do it manually." 14 | } 15 | if (Test-Path $pluginChocoFile) { 16 | Remove-Item -Path $pluginChocoFile -Force -ErrorAction Continue 17 | } else { 18 | Write-Warning "The plugin has not been found!" 19 | } 20 | } 21 | 22 | $toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" 23 | . "${toolsDir}\common.ps1" 24 | Uninstall-Plugin 25 | -------------------------------------------------------------------------------- /choco/tools/common.ps1: -------------------------------------------------------------------------------- 1 | # powershell v2 compatibility 2 | $psVer = $PSVersionTable.PSVersion.Major 3 | if ($psver -ge 3) { 4 | function Get-ChildItemDir {Get-ChildItem -Directory $args} 5 | } else { 6 | function Get-ChildItemDir {Get-ChildItem $args} 7 | } 8 | 9 | $packageName = 'keepass-plugin-keetheme' 10 | $fileName = 'KeeTheme.plgx' 11 | $packageSearch = 'KeePass Password Safe' 12 | $url = 'https://github.com/xatupal/KeeTheme/releases/download/v0.10.6/KeeTheme.plgx' 13 | $checksum = 'BF2CB60B23CB38AAC32988F18F17643BAE9C9B6FF7755D675BD6D837E65388A8' 14 | $checksumType = 'sha256' 15 | 16 | function Get-KeePassPluginsPath { 17 | Write-Verbose "Searching registry for installed KeePass..." 18 | $regPath = Get-ItemProperty -Path ` 19 | @('HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*', 20 | 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*', 21 | 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*') ` 22 | -ErrorAction:SilentlyContinue ` 23 | | Where-Object { ` 24 | $_.DisplayName -like "$packageSearch*" ` 25 | -and $_.DisplayVersion -ge 2.0 ` 26 | -and $_.DisplayVersion -lt 3.0 ` 27 | } ` 28 | | ForEach-Object {$_.InstallLocation} 29 | 30 | $installPath = $regPath 31 | 32 | if (! $installPath) { 33 | $toolsLocation = Get-ToolsLocation 34 | Write-Verbose "Searching $toolsLocation for portable install..." 35 | $portPath = Join-Path $toolsLocation "keepass" 36 | $installPath = Get-ChildItemDir $portPath* -ErrorAction SilentlyContinue 37 | } 38 | 39 | if (! $installPath) { 40 | Write-Verbose "Searching $env:Path for unregistered install..." 41 | $installFullName = (Get-Command keepass -ErrorAction SilentlyContinue).Path 42 | if ($installFullName) { 43 | $installPath = [io.path]::GetDirectoryName($installFullName) 44 | } 45 | } 46 | 47 | if (! $installPath) { 48 | Write-Warning "$($packageSearch) not found." 49 | throw 50 | } 51 | 52 | Write-Verbose "`t...found." 53 | 54 | Write-Verbose "Searching for plugin directory..." 55 | $pluginPath = (Get-ChildItemDir $installPath\Plugin*).FullName 56 | if ($pluginPath.Count -eq 0) { 57 | $pluginPath = Join-Path $installPath "Plugins" 58 | [System.IO.Directory]::CreateDirectory($pluginPath) 59 | } 60 | return $pluginPath 61 | } 62 | -------------------------------------------------------------------------------- /docs/KeePassDarkTheme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xatupal/KeeTheme/5f2534d5ca7847411e6911b4298a6405cbe44362/docs/KeePassDarkTheme.png -------------------------------------------------------------------------------- /docs/KeePassDarkThemeCustomOptions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xatupal/KeeTheme/5f2534d5ca7847411e6911b4298a6405cbe44362/docs/KeePassDarkThemeCustomOptions.png -------------------------------------------------------------------------------- /docs/KeePassDarkThemeEditor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xatupal/KeeTheme/5f2534d5ca7847411e6911b4298a6405cbe44362/docs/KeePassDarkThemeEditor.png -------------------------------------------------------------------------------- /docs/KeePassDarkThemeOpenDatabase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xatupal/KeeTheme/5f2534d5ca7847411e6911b4298a6405cbe44362/docs/KeePassDarkThemeOpenDatabase.png -------------------------------------------------------------------------------- /docs/KeePassDarkThemeOptions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xatupal/KeeTheme/5f2534d5ca7847411e6911b4298a6405cbe44362/docs/KeePassDarkThemeOptions.png -------------------------------------------------------------------------------- /docs/KeePassDarkThemeWin11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xatupal/KeeTheme/5f2534d5ca7847411e6911b4298a6405cbe44362/docs/KeePassDarkThemeWin11.png -------------------------------------------------------------------------------- /docs/KeePassDarkThemeWin11OpenDatabase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xatupal/KeeTheme/5f2534d5ca7847411e6911b4298a6405cbe44362/docs/KeePassDarkThemeWin11OpenDatabase.png -------------------------------------------------------------------------------- /docs/KeePassDarkThemeWin11Options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xatupal/KeeTheme/5f2534d5ca7847411e6911b4298a6405cbe44362/docs/KeePassDarkThemeWin11Options.png -------------------------------------------------------------------------------- /themes/DarkTheme.ini: -------------------------------------------------------------------------------- 1 | [KeeTheme] 2 | Name=Dark Theme 3 | 4 | [Palette] 5 | Control = (51, 51, 51) 6 | ControlText = (227, 227, 227) 7 | Window = (69, 73, 74) 8 | LightWindow = (74, 78, 79) 9 | WindowText = (220, 220, 220) 10 | Border = (104, 151, 187) 11 | LightBorder = (81, 81, 81) 12 | Header = (57, 60, 62) 13 | ColumnBorder = (97, 100, 101) 14 | Group = (148, 184, 220) 15 | GroupHighlight = (65, 82, 96) 16 | Link = (110, 179, 248) 17 | ToolStrip = (64, 64, 64) 18 | ToolStripHighlight = (114, 161, 197) 19 | ToolStripBorder = (0, 0, 0) 20 | Error = (207, 102, 121) 21 | TreeViewHighlight = (55, 86, 109) 22 | 23 | [Other] 24 | ControlNormalColor = Window 25 | ControlDisabledColor = Control 26 | ColorEditError = Error 27 | 28 | [Control] 29 | BackColor = Control 30 | ForeColor = ControlText 31 | 32 | [Form] 33 | BackColor = Control 34 | ForeColor = ControlText 35 | 36 | [Button] 37 | BackColor = Control 38 | ForeColor = ControlText 39 | BorderColor = Border 40 | FlatStyle = Flat 41 | 42 | [TreeView] 43 | BackColor = Window 44 | ForeColor = ControlText 45 | SelectionColor = ControlText 46 | SelectionBackColor = TreeViewHighlight 47 | BorderStyle = FixedSingle 48 | 49 | [RichTextBox] 50 | BackColor = Control 51 | ForeColor = ControlText 52 | BorderStyle = FixedSingle 53 | SelectionColor = ControlText 54 | 55 | [LinkLabel] 56 | BackColor = Control 57 | ForeColor = ControlText 58 | LinkColor = Link 59 | 60 | [ListView] 61 | BackColor = Window 62 | ForeColor = ControlText 63 | BorderStyle = FixedSingle 64 | OddRowColor = LightWindow 65 | EvenRowColor = Window 66 | ColumnBorderColor = ColumnBorder 67 | HeaderBackColor = Header 68 | HeaderForeColor = WindowText 69 | HeaderColumnBorderColor = LightBorder 70 | BackgroundImageAlignment = 71 | BackgroundImage = 72 | GroupForeColor = Group 73 | GroupBackColor = Window 74 | GroupHighlightColor = GroupHighlight 75 | 76 | [SecureTextBox] 77 | BackColor = Control 78 | ForeColor = ControlText 79 | 80 | [CheckBox] 81 | BackColor = 82 | ForeColor = 83 | FlatStyle = 84 | BorderColor = 85 | CheckedBackColor = 86 | MouseDownBackColor = 87 | MouseOverBackColor = 88 | 89 | [CheckBoxButton] 90 | BackColor = Border 91 | ForeColor = 92 | FlatStyle = Flat 93 | BorderColor = Border 94 | CheckedBackColor = Control 95 | MouseDownBackColor = LightBorder 96 | MouseOverBackColor = Window 97 | 98 | [MenuItem] 99 | BackColor = ToolStrip 100 | ForeColor = ControlText 101 | HighlightColor = Control 102 | 103 | [ToolStrip] 104 | ButtonSelectedHighlight = 105 | ButtonSelectedHighlightBorder = ToolStripHighlight 106 | ButtonPressedHighlight = 107 | ButtonPressedHighlightBorder = 108 | ButtonCheckedHighlight = 109 | ButtonCheckedHighlightBorder = 110 | ButtonPressedBorder = ToolStrip 111 | ButtonSelectedBorder = ToolStrip 112 | ButtonCheckedGradientBegin = 113 | ButtonCheckedGradientMiddle = 114 | ButtonCheckedGradientEnd = 115 | ButtonSelectedGradientBegin = ToolStripHighlight 116 | ButtonSelectedGradientMiddle = ToolStripHighlight 117 | ButtonSelectedGradientEnd = ToolStripHighlight 118 | ButtonPressedGradientBegin = ToolStripHighlight 119 | ButtonPressedGradientMiddle = ToolStripHighlight 120 | ButtonPressedGradientEnd = ToolStripHighlight 121 | CheckBackground = ToolStripHighlight 122 | CheckSelectedBackground = ToolStripHighlight 123 | CheckPressedBackground = ToolStripHighlight 124 | GripDark = 125 | GripLight = 126 | ImageMarginGradientBegin = ToolStrip 127 | ImageMarginGradientMiddle = ToolStrip 128 | ImageMarginGradientEnd = ToolStrip 129 | ImageMarginRevealedGradientBegin = 130 | ImageMarginRevealedGradientMiddle = 131 | ImageMarginRevealedGradientEnd = 132 | MenuStripGradientBegin = 133 | MenuStripGradientEnd = 134 | MenuItemSelected = ToolStripHighlight 135 | MenuItemBorder = ToolStripHighlight 136 | MenuBorder = ToolStripHighlight 137 | MenuItemSelectedGradientBegin = ToolStripHighlight 138 | MenuItemSelectedGradientEnd = ToolStripHighlight 139 | MenuItemPressedGradientBegin = ToolStripHighlight 140 | MenuItemPressedGradientMiddle = ToolStripHighlight 141 | MenuItemPressedGradientEnd = ToolStripHighlight 142 | RaftingContainerGradientBegin = 143 | RaftingContainerGradientEnd = 144 | SeparatorDark = 145 | SeparatorLight = 146 | StatusStripGradientBegin = 147 | StatusStripGradientEnd = 148 | ToolStripBorder = ToolStripBorder 149 | ToolStripDropDownBackground = ToolStrip 150 | ToolStripGradientBegin = ToolStrip 151 | ToolStripGradientMiddle = ToolStrip 152 | ToolStripGradientEnd = ToolStrip 153 | ToolStripContentPanelGradientBegin = 154 | ToolStripContentPanelGradientEnd = 155 | ToolStripPanelGradientBegin = 156 | ToolStripPanelGradientEnd = 157 | OverflowButtonGradientBegin = ToolStrip 158 | OverflowButtonGradientMiddle = ToolStrip 159 | OverflowButtonGradientEnd = ToolStrip 160 | -------------------------------------------------------------------------------- /themes/KeeTheme.ini: -------------------------------------------------------------------------------- 1 | ; 2 | ; KeeTheme theme template 3 | ; 4 | ; You can assign individual color to each property 5 | ; or create and use color from the palette. 6 | ; 7 | ; Valid color formats: #rrggbb, #rgb, (128, 128, 128) 8 | ; 9 | ; Valid values for 10 | ; - BorderStyle: None, FixedSingle, Fixed3D 11 | ; - FlatStyle: Flat, Popup, Standard, System 12 | ; - BackgroundImageAlignment: TopLeft, TopCenter, TopRight, MiddleLeft, MiddleCenter, MiddleRight, BottomLeft, BottomCenter, BottomRight 13 | ; - BackgroundImage: 14 | ; 15 | 16 | [KeeTheme] 17 | Name=Custom theme 18 | 19 | [Palette] 20 | Red = #ff0000 21 | Green = #0f0 22 | Blue = (0, 0, 255) 23 | 24 | [Other] 25 | ControlNormalColor = 26 | ControlDisabledColor = 27 | ColorEditError = 28 | 29 | [Control] 30 | BackColor = 31 | ForeColor = 32 | 33 | [Form] 34 | BackColor = 35 | ForeColor = 36 | 37 | [Button] 38 | BackColor = 39 | ForeColor = 40 | BorderColor = 41 | FlatStyle = 42 | 43 | [TreeView] 44 | BackColor = 45 | ForeColor = 46 | SelectionColor = 47 | SelectionBackColor = 48 | BorderStyle = 49 | 50 | [RichTextBox] 51 | BackColor = 52 | ForeColor = 53 | BorderStyle = 54 | SelectionColor = 55 | 56 | [LinkLabel] 57 | BackColor = 58 | ForeColor = 59 | LinkColor = 60 | 61 | [ListView] 62 | BackColor = 63 | ForeColor = 64 | BorderStyle = 65 | OddRowColor = 66 | EvenRowColor = 67 | ColumnBorderColor = 68 | HeaderBackColor = 69 | HeaderForeColor = 70 | HeaderColumnBorderColor = 71 | BackgroundImageAlignment = 72 | BackgroundImage = 73 | GroupForeColor = 74 | GroupBackColor = 75 | GroupHighlightColor = 76 | 77 | [SecureTextBox] 78 | BackColor = 79 | ForeColor = 80 | 81 | [CheckBox] 82 | BackColor = 83 | ForeColor = 84 | FlatStyle = 85 | BorderColor = 86 | CheckedBackColor = 87 | MouseDownBackColor = 88 | MouseOverBackColor = 89 | 90 | [CheckBoxButton] 91 | BackColor = 92 | ForeColor = 93 | FlatStyle = 94 | BorderColor = 95 | CheckedBackColor = 96 | MouseDownBackColor = 97 | MouseOverBackColor = 98 | 99 | [MenuItem] 100 | BackColor = 101 | ForeColor = 102 | HighlightColor = 103 | 104 | [ToolStrip] 105 | ButtonSelectedHighlight = 106 | ButtonSelectedHighlightBorder = 107 | ButtonPressedHighlight = 108 | ButtonPressedHighlightBorder = 109 | ButtonCheckedHighlight = 110 | ButtonCheckedHighlightBorder = 111 | ButtonPressedBorder = 112 | ButtonSelectedBorder = 113 | ButtonCheckedGradientBegin = 114 | ButtonCheckedGradientMiddle = 115 | ButtonCheckedGradientEnd = 116 | ButtonSelectedGradientBegin = 117 | ButtonSelectedGradientMiddle = 118 | ButtonSelectedGradientEnd = 119 | ButtonPressedGradientBegin = 120 | ButtonPressedGradientMiddle = 121 | ButtonPressedGradientEnd = 122 | CheckBackground = 123 | CheckSelectedBackground = 124 | CheckPressedBackground = 125 | GripDark = 126 | GripLight = 127 | ImageMarginGradientBegin = 128 | ImageMarginGradientMiddle = 129 | ImageMarginGradientEnd = 130 | ImageMarginRevealedGradientBegin = 131 | ImageMarginRevealedGradientMiddle = 132 | ImageMarginRevealedGradientEnd = 133 | MenuStripGradientBegin = 134 | MenuStripGradientEnd = 135 | MenuItemSelected = 136 | MenuItemBorder = 137 | MenuBorder = 138 | MenuItemSelectedGradientBegin = 139 | MenuItemSelectedGradientEnd = 140 | MenuItemPressedGradientBegin = 141 | MenuItemPressedGradientMiddle = 142 | MenuItemPressedGradientEnd = 143 | RaftingContainerGradientBegin = 144 | RaftingContainerGradientEnd = 145 | SeparatorDark = 146 | SeparatorLight = 147 | StatusStripGradientBegin = 148 | StatusStripGradientEnd = 149 | ToolStripBorder = 150 | ToolStripDropDownBackground = 151 | ToolStripGradientBegin = 152 | ToolStripGradientMiddle = 153 | ToolStripGradientEnd = 154 | ToolStripContentPanelGradientBegin = 155 | ToolStripContentPanelGradientEnd = 156 | ToolStripPanelGradientBegin = 157 | ToolStripPanelGradientEnd = 158 | OverflowButtonGradientBegin = 159 | OverflowButtonGradientMiddle = 160 | OverflowButtonGradientEnd = 161 | --------------------------------------------------------------------------------