1 /* 2 KeePass Password Safe - The Open-Source Password Manager 3 Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 using System; 21 using System.Collections.Generic; 22 using System.Diagnostics; 23 using System.Drawing; 24 using System.Globalization; 25 using System.Text; 26 27 using KeePass.UI; 28 29 namespace KeePass.App 30 { 31 public enum AppIconType 32 { 33 None = 0, 34 Main, 35 QuadNormal, 36 QuadLocked 37 } 38 39 public static class AppIcons 40 { 41 private static Dictionary<string, Icon> g_dCache = new Dictionary<string, Icon>(); 42 private static readonly object g_oCacheSync = new object(); 43 44 // The average hue of the main icon is about 225 degrees 45 private static readonly Color g_clrMain = UIUtil.ColorFromHsv(225, 1, 1); 46 47 private static Color[] g_vColors = null; 48 internal static Color[] Colors 49 { 50 get 51 { 52 if(g_vColors == null) 53 { 54 List<Color> l = new List<Color>(); 55 56 for(int h = 0; h < 360; h += 15) 57 l.Add(UIUtil.ColorFromHsv((h + 225) % 360, 1, 1)); 58 59 g_vColors = l.ToArray(); 60 61 #if DEBUG 62 Color[] vInvariant = new Color[] { g_clrMain, 63 Color.Red, Color.Lime, Color.Blue, Color.Yellow }; 64 foreach(Color clr in vInvariant) 65 { 66 Debug.Assert(UIUtil.ColorsEqual(RoundColor(clr), clr)); 67 } 68 #endif 69 } 70 71 return g_vColors; 72 } 73 } 74 75 public static Icon Default 76 { 77 get { return Get(AppIconType.Main, Size.Empty, Color.Empty); } 78 } 79 Get(AppIconType t, Size sz, Color clr)80 public static Icon Get(AppIconType t, Size sz, Color clr) 81 { 82 int w = Math.Min(Math.Max(sz.Width, 0), 256); 83 int h = Math.Min(Math.Max(sz.Height, 0), 256); 84 if((w == 0) || (h == 0)) 85 { 86 Size szDefault = UIUtil.GetIconSize(); 87 w = szDefault.Width; 88 h = szDefault.Height; 89 } 90 91 Color c = clr; 92 if(!UIUtil.ColorsEqual(c, Color.Empty)) c = RoundColor(c); 93 94 NumberFormatInfo nf = NumberFormatInfo.InvariantInfo; 95 string strID = ((long)t).ToString(nf) + ":" + w.ToString(nf) + ":" + 96 h.ToString(nf) + ":" + c.ToArgb().ToString(nf); 97 98 Icon ico = null; 99 lock(g_oCacheSync) 100 { 101 if(g_dCache.TryGetValue(strID, out ico)) return ico; 102 } 103 104 if(t == AppIconType.Main) 105 ico = Properties.Resources.KeePass; 106 else if(t == AppIconType.QuadNormal) 107 ico = Properties.Resources.QuadNormal; 108 else if(t == AppIconType.QuadLocked) 109 { 110 ico = Properties.Resources.QuadLocked; 111 112 Debug.Assert(UIUtil.ColorsEqual(c, Color.Empty)); 113 c = Color.Empty; // This icon should not be recolored 114 } 115 else { Debug.Assert(false); } 116 117 if((ico != null) && !UIUtil.ColorsEqual(c, Color.Empty)) 118 ico = IconColorizer.Recolor(ico, c); 119 120 // Select requested resolution 121 if(ico != null) ico = new Icon(ico, w, h); // Preserves icon data 122 123 Debug.Assert(ico != null); 124 lock(g_oCacheSync) { g_dCache[strID] = ico; } 125 return ico; 126 } 127 ColorDist(Color c1, Color c2)128 private static int ColorDist(Color c1, Color c2) 129 { 130 int dR = (int)c1.R - (int)c2.R; 131 int dG = (int)c1.G - (int)c2.G; 132 int dB = (int)c1.B - (int)c2.B; 133 return ((dR * dR) + (dG * dG) + (dB * dB)); 134 } 135 136 /// <summary> 137 /// Round <paramref name="clr" /> to the nearest supported color. 138 /// </summary> RoundColor(Color clr)139 public static Color RoundColor(Color clr) 140 { 141 Debug.Assert(!UIUtil.ColorsEqual(clr, Color.Empty)); 142 if((clr.R == clr.B) && (clr.G == clr.B)) 143 return g_clrMain; // Gray => default 144 145 Color[] v = AppIcons.Colors; 146 147 int c = clr.ToArgb(); 148 for(int i = 0; i < v.Length; ++i) 149 { 150 if(v[i].ToArgb() == c) return clr; 151 } 152 153 int iMin = 0, dMin = int.MaxValue; 154 for(int i = 0; i < v.Length; ++i) 155 { 156 int d = ColorDist(clr, v[i]); 157 if(d < dMin) 158 { 159 iMin = i; 160 dMin = d; 161 } 162 } 163 return v[iMin]; 164 } 165 } 166 } 167