OSDN Git Service

ディスプレイ設定で拡大したときに戦況のHPがずれるのを直す
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / View / ShipLabel.cs
1 // Copyright (C) 2014, 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
2 //\r
3 // Licensed under the Apache License, Version 2.0 (the "License");\r
4 // you may not use this file except in compliance with the License.\r
5 // You may obtain a copy of the License at\r
6 //\r
7 //    http://www.apache.org/licenses/LICENSE-2.0\r
8 //\r
9 // Unless required by applicable law or agreed to in writing, software\r
10 // distributed under the License is distributed on an "AS IS" BASIS,\r
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
12 // See the License for the specific language governing permissions and\r
13 // limitations under the License.\r
14 \r
15 using System;\r
16 using System.ComponentModel;\r
17 using System.Drawing;\r
18 using System.Linq;\r
19 using System.Text.RegularExpressions;\r
20 using System.Windows.Forms;\r
21 using KancolleSniffer.Model;\r
22 using static System.Math;\r
23 \r
24 namespace KancolleSniffer.View\r
25 {\r
26     [DesignerCategory("Code")]\r
27     public class ShipLabel : Label\r
28     {\r
29         public static Color[] ColumnColors = {SystemColors.Control, Color.FromArgb(255, 250, 250, 250)};\r
30         public static SizeF ScaleFactor { get; set; }\r
31         public static Font LatinFont { get; set; } = new Font("Tahoma", 8f);\r
32         public Color PresetColor { get; set; }\r
33         public bool AnchorRight { get; set; }\r
34         private int _right = Int32.MinValue;\r
35         private int _left;\r
36         private SlotStatus _slotStatus;\r
37         private ShipStatus _status;\r
38         private bool _hpPercent;\r
39 \r
40         public override Color BackColor\r
41         {\r
42             get => base.BackColor;\r
43             set => base.BackColor = value == DefaultBackColor ? PresetColor : value;\r
44         }\r
45 \r
46         [Flags]\r
47         private enum SlotStatus\r
48         {\r
49             Equipped = 0,\r
50             NormalEmpty = 1,\r
51             ExtraEmpty = 2\r
52         }\r
53 \r
54         public ShipLabel()\r
55         {\r
56             UseMnemonic = false;\r
57         }\r
58 \r
59         public void SetName(ShipStatus status, ShipNameWidth width = ShipNameWidth.Max)\r
60         {\r
61             if (status == null)\r
62             {\r
63                 SetName("");\r
64                 return;\r
65             }\r
66             var empty = SlotStatus.Equipped;\r
67             if (!status.Empty)\r
68             {\r
69                 if (status.Slot.All(item => item.Empty))\r
70                     empty |= SlotStatus.NormalEmpty;\r
71                 if (status.SlotEx.Empty)\r
72                     empty |= SlotStatus.ExtraEmpty;\r
73             }\r
74             var dc = status.PreparedDamageControl;\r
75             var dcName = dc == 42 ? "[ダ]" :\r
76                 dc == 43 ? "[メ]" : "";\r
77             var sp = "";\r
78             switch (status.SpecialAttack)\r
79             {\r
80                 case ShipStatus.Attack.Fire:\r
81                     sp = "+";\r
82                     break;\r
83                 case ShipStatus.Attack.Fired:\r
84                     sp = "-";\r
85                     break;\r
86             }\r
87             SetName((status.Escaped ? "[避]" : dcName) + sp, status.Name, empty, width);\r
88         }\r
89 \r
90         public void SetName(string name)\r
91         {\r
92             SetName("", name, SlotStatus.Equipped);\r
93         }\r
94 \r
95         public void SetName(string name, ShipNameWidth width)\r
96         {\r
97             SetName("", name, SlotStatus.Equipped, width);\r
98         }\r
99 \r
100         private void SetName(string prefix, string name, SlotStatus slotStatus, ShipNameWidth width = ShipNameWidth.Max)\r
101         {\r
102             if (name == null)\r
103                 name = "";\r
104             _slotStatus = slotStatus;\r
105             var lu = new Regex(@"^\p{Lu}").IsMatch(name);\r
106             var shift = (int)Round(ScaleFactor.Height);\r
107             if (lu && Font.Equals(Parent.Font))\r
108             {\r
109                 Location += new Size(0, -shift);\r
110                 Font = LatinFont;\r
111             }\r
112             else if (!lu && !Font.Equals(Parent.Font))\r
113             {\r
114                 Location += new Size(0, shift);\r
115                 Font = Parent.Font;\r
116             }\r
117             var result = prefix + name;\r
118             var measured = TextRenderer.MeasureText(result, Font).Width;\r
119             if (measured <= (int)width)\r
120             {\r
121                 Text = result;\r
122                 Invalidate(); // 必ずOnPaintを実行させるため\r
123                 return;\r
124             }\r
125             var truncated = "";\r
126             foreach (var ch in name)\r
127             {\r
128                 var tmp = truncated + ch;\r
129                 if (TextRenderer.MeasureText(tmp, Font).Width > (int)width * ScaleFactor.Width)\r
130                     break;\r
131                 truncated = tmp;\r
132             }\r
133             Text = prefix + truncated.TrimEnd(' ');\r
134             Invalidate();\r
135         }\r
136 \r
137         public void SetHp(ShipStatus status)\r
138         {\r
139             _status = status;\r
140             if (status == null)\r
141             {\r
142                 Text = "";\r
143                 BackColor = PresetColor;\r
144                 return;\r
145             }\r
146             Text = _hpPercent\r
147                 ? $"{(int)Floor(status.NowHp * 100.0 / status.MaxHp):D}%"\r
148                 : $"{status.NowHp:D}/{status.MaxHp:D}";\r
149             BackColor = DamageColor(status, PresetColor);\r
150         }\r
151 \r
152         public void ToggleHpPercent()\r
153         {\r
154             _hpPercent = !_hpPercent;\r
155             SetHp(_status);\r
156         }\r
157 \r
158         public void SetHp(int now, int max)\r
159         {\r
160             SetHp(new ShipStatus {NowHp = now, MaxHp = max});\r
161         }\r
162 \r
163         public static Color DamageColor(ShipStatus status, Color backColor)\r
164         {\r
165             switch (status.DamageLevel)\r
166             {\r
167                 case ShipStatus.Damage.Sunk:\r
168                     return Color.CornflowerBlue;\r
169                 case ShipStatus.Damage.Badly:\r
170                     return CUDColors.Red;\r
171                 case ShipStatus.Damage.Half:\r
172                     return CUDColors.Orange;\r
173                 case ShipStatus.Damage.Small:\r
174                     return Color.FromArgb(240, 240, 0);\r
175                 default:\r
176                     return backColor;\r
177             }\r
178         }\r
179 \r
180         public void SetCond(ShipStatus status)\r
181         {\r
182             if (status == null)\r
183             {\r
184                 Text = "";\r
185                 BackColor = PresetColor;\r
186                 return;\r
187             }\r
188             var cond = status.Cond;\r
189             Text = cond.ToString("D");\r
190             BackColor = cond >= 50\r
191                 ? CUDColors.Yellow\r
192                 : cond >= 30\r
193                     ? PresetColor\r
194                     : cond >= 20\r
195                         ? CUDColors.Orange\r
196                         : CUDColors.Red;\r
197         }\r
198 \r
199         public void SetLevel(ShipStatus status)\r
200         {\r
201             Text = status?.Level.ToString("D");\r
202         }\r
203 \r
204         public void SetExpToNext(ShipStatus status)\r
205         {\r
206             Text = status?.ExpToNext.ToString("D");\r
207         }\r
208 \r
209         public void SetRepairTime(ShipStatus status)\r
210         {\r
211             if (status == null)\r
212             {\r
213                 Text = "";\r
214                 return;\r
215             }\r
216             SetRepairTime(status.RepairTime);\r
217         }\r
218 \r
219         public void SetRepairTime(TimeSpan span)\r
220         {\r
221             Text = $@"{(int)span.TotalHours:d2}:{span:mm\:ss}";\r
222         }\r
223 \r
224         public void SetFleet(ShipStatus status)\r
225         {\r
226             Text = status?.Fleet == null ? "" : new[] {"1", "2", "3", "4"}[status.Fleet.Number];\r
227         }\r
228 \r
229         protected override void OnSizeChanged(EventArgs args)\r
230         {\r
231             base.OnSizeChanged(args);\r
232             KeepAnchorRight();\r
233         }\r
234 \r
235         protected override void OnLayout(LayoutEventArgs args)\r
236         {\r
237             base.OnLayout(args);\r
238             KeepAnchorRight();\r
239         }\r
240 \r
241         private void KeepAnchorRight()\r
242         {\r
243             if (!AnchorRight)\r
244                 return;\r
245             if (_right == int.MinValue || _left != Left)\r
246             {\r
247                 _right = Right;\r
248                 _left = Left;\r
249                 return;\r
250             }\r
251             if (_right == Right)\r
252                 return;\r
253             _left -= Right - _right;\r
254             Location = new Point(_left, Top);\r
255         }\r
256 \r
257         protected override void OnPaint(PaintEventArgs e)\r
258         {\r
259             base.OnPaint(e);\r
260             if ((_slotStatus & SlotStatus.NormalEmpty) != 0)\r
261             {\r
262                 e.Graphics.DrawRectangle(\r
263                     Pens.Black,\r
264                     ClientSize.Width - 3 * ScaleFactor.Width, 1 * ScaleFactor.Height,\r
265                     2 * ScaleFactor.Width, 4 * ScaleFactor.Height);\r
266             }\r
267             if ((_slotStatus & SlotStatus.ExtraEmpty) != 0)\r
268             {\r
269                 e.Graphics.DrawRectangle(\r
270                     Pens.Black,\r
271                     ClientSize.Width - 3 * ScaleFactor.Width, 7 * ScaleFactor.Height,\r
272                     2 * ScaleFactor.Width, 3 * ScaleFactor.Height);\r
273             }\r
274         }\r
275 \r
276         public void Scale()\r
277         {\r
278             Scale(ScaleFactor);\r
279         }\r
280     }\r
281 }