OSDN Git Service

IUpdatableをIUpdateContextとIUpdateTimerに分離する
[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 abstract class ShipLabel : GrowLeftLabel\r
28     {\r
29         protected Color InitialBackColor;\r
30 \r
31         public override Color BackColor\r
32         {\r
33             get => base.BackColor;\r
34             set\r
35             {\r
36                 if (InitialBackColor == Color.Empty)\r
37                     InitialBackColor = value;\r
38                 base.BackColor = value;\r
39             }\r
40         }\r
41 \r
42         protected ShipLabel()\r
43         {\r
44             UseMnemonic = false;\r
45         }\r
46 \r
47         public abstract void Set(ShipStatus status);\r
48 \r
49         public abstract void Reset();\r
50 \r
51         public new sealed class Name : ShipLabel\r
52         {\r
53             private SlotStatus _slotStatus, _prevSlotStatus;\r
54             private readonly ShipNameWidth _defaultWidth;\r
55 \r
56             public static Font LatinFont { get; set; }\r
57             public static Font BaseFont { get; set; }\r
58 \r
59             public Name(Point location, ShipNameWidth defaultWidth)\r
60             {\r
61                 _defaultWidth = defaultWidth;\r
62                 Location = location;\r
63                 AutoSize = true;\r
64             }\r
65 \r
66             [Flags]\r
67             private enum SlotStatus\r
68             {\r
69                 Equipped = 0,\r
70                 SemiEquipped = 1,\r
71                 NormalEmpty = 2,\r
72                 ExtraEmpty = 4\r
73             }\r
74 \r
75             public override void Set(ShipStatus status)\r
76             {\r
77                 SetName(status, _defaultWidth);\r
78             }\r
79 \r
80             public override void Reset()\r
81             {\r
82                 SetName("");\r
83             }\r
84 \r
85             public void SetName(ShipStatus status, ShipNameWidth width)\r
86             {\r
87                 var slotStatus = GetSlotStatus(status);\r
88                 var dcName = DameConName(status);\r
89                 var sp = SpecialAttack(status);\r
90                 SetName((status.Escaped ? "[避]" : dcName) + sp, status.Name, slotStatus, width);\r
91             }\r
92 \r
93             private static SlotStatus GetSlotStatus(ShipStatus status)\r
94             {\r
95                 if (status.Empty)\r
96                     return SlotStatus.Equipped;\r
97                 var slots = status.Slot.Take(status.Spec.SlotNum).ToArray();\r
98                 var normal = slots.Any(item => item.Empty)\r
99                     ? slots.All(item => item.Empty) ? SlotStatus.NormalEmpty : SlotStatus.SemiEquipped\r
100                     : SlotStatus.Equipped;\r
101                 var extra = status.SlotEx.Empty ? SlotStatus.ExtraEmpty : SlotStatus.Equipped;\r
102                 return normal | extra;\r
103             }\r
104 \r
105             private string DameConName(ShipStatus status)\r
106             {\r
107                 switch (status.PreparedDamageControl)\r
108                 {\r
109                     case 42:\r
110                         return "[ダ]";\r
111                     case 43:\r
112                         return "[メ]";\r
113                     default:\r
114                         return "";\r
115                 }\r
116             }\r
117 \r
118             private string SpecialAttack(ShipStatus status)\r
119             {\r
120                 switch (status.SpecialAttack)\r
121                 {\r
122                     case ShipStatus.Attack.Fire:\r
123                         return "+";\r
124                     case ShipStatus.Attack.Fired:\r
125                         return "-";\r
126                     default:\r
127                         return "";\r
128                 }\r
129             }\r
130 \r
131             public void SetName(string name)\r
132             {\r
133                 SetName(name, _defaultWidth);\r
134             }\r
135 \r
136             public void SetName(string name, ShipNameWidth width)\r
137             {\r
138                 SetName("", name, SlotStatus.Equipped, width);\r
139             }\r
140 \r
141             private void SetName(string prefix, string name, SlotStatus slotStatus, ShipNameWidth width)\r
142             {\r
143                 _slotStatus = slotStatus;\r
144                 ChangeFont(name);\r
145                 var realWidth = width == ShipNameWidth.Max ? (int)width : Scaler.ScaleWidth((int)width);\r
146                 Text = prefix + StringTruncator.Truncate(name, "", realWidth, Font);\r
147                 if (_prevSlotStatus != _slotStatus)\r
148                     Invalidate(); // OnPaintを実行させるため\r
149                 _prevSlotStatus = _slotStatus;\r
150             }\r
151 \r
152             private void ChangeFont(string name)\r
153             {\r
154                 var lu = StartWithLetter(name);\r
155                 var shift = Scaler.ScaleHeight(1);\r
156                 if (lu && !Font.Equals(LatinFont))\r
157                 {\r
158                     Location += new Size(0, -shift);\r
159                     Font = LatinFont;\r
160                 }\r
161                 else if (!lu && Font.Equals(LatinFont))\r
162                 {\r
163                     Location += new Size(0, shift);\r
164                     Font = BaseFont;\r
165                 }\r
166             }\r
167 \r
168             public static bool StartWithLetter(string name)\r
169             {\r
170                 return Regex.IsMatch(name, @"^\p{Lu}");\r
171             }\r
172 \r
173             protected override void OnPaint(PaintEventArgs e)\r
174             {\r
175                 base.OnPaint(e);\r
176                 if ((_slotStatus & SlotStatus.NormalEmpty) != 0)\r
177                 {\r
178                     e.Graphics.DrawRectangle(Pens.Black,\r
179                         new Rectangle(Scaler.Move(ClientSize.Width, 0, -3, 0), Scaler.Scale(2, 5)));\r
180                 }\r
181                 else if ((_slotStatus & SlotStatus.SemiEquipped) != 0)\r
182                 {\r
183                     e.Graphics.DrawLine(Pens.Black,\r
184                         Scaler.Move(ClientSize.Width, 0, -1, 0),\r
185                         Scaler.Move(ClientSize.Width, 0, -1, 5));\r
186                 }\r
187                 if ((_slotStatus & SlotStatus.ExtraEmpty) != 0)\r
188                 {\r
189                     e.Graphics.DrawRectangle(Pens.Black,\r
190                         new Rectangle(Scaler.Move(ClientSize.Width, 0, -3, 8), Scaler.Scale(2, 3)));\r
191                 }\r
192             }\r
193         }\r
194 \r
195         public sealed class Hp : ShipLabel\r
196         {\r
197             private bool _hpPercent;\r
198             private ShipStatus _status;\r
199 \r
200             public Hp()\r
201             {\r
202             }\r
203 \r
204             public Hp(Point location, int height)\r
205             {\r
206                 Location = location;\r
207                 MinimumSize = new Size(0, height);\r
208                 TextAlign = ContentAlignment.MiddleLeft;\r
209                 GrowLeft = true;\r
210                 Cursor = Cursors.Hand;\r
211             }\r
212 \r
213             public override void Reset()\r
214             {\r
215                 _status = null;\r
216                 Text = "";\r
217                 BackColor = InitialBackColor;\r
218             }\r
219 \r
220             public override void Set(ShipStatus status)\r
221             {\r
222                 _status = status;\r
223                 Text = _hpPercent\r
224                     ? $"{(int)Floor(status.NowHp * 100.0 / status.MaxHp):D}%"\r
225                     : $"{status.NowHp:D}/{status.MaxHp:D}";\r
226                 BackColor = DamageColor(status);\r
227             }\r
228 \r
229             public void ToggleHpPercent()\r
230             {\r
231                 _hpPercent = !_hpPercent;\r
232                 if (_status != null)\r
233                     Set(_status);\r
234             }\r
235 \r
236             public void SetHp(int now, int max)\r
237             {\r
238                 Set(new ShipStatus {NowHp = now, MaxHp = max});\r
239             }\r
240 \r
241             private Color DamageColor(ShipStatus status)\r
242             {\r
243                 return status.DamageLevel switch\r
244                 {\r
245                     ShipStatus.Damage.Sunk => Color.CornflowerBlue,\r
246                     ShipStatus.Damage.Badly => status.Escaped ? CUDColors.LightGray : CUDColors.Red,\r
247                     ShipStatus.Damage.Half => CUDColors.Orange,\r
248                     ShipStatus.Damage.Small => Color.FromArgb(240, 240, 0),\r
249                     _ => InitialBackColor\r
250                 };\r
251             }\r
252 \r
253             public void SetColor(ShipStatus status)\r
254             {\r
255                 BackColor = DamageColor(status);\r
256             }\r
257         }\r
258 \r
259         public sealed class Cond : ShipLabel\r
260         {\r
261             public Cond(Point location, int height)\r
262             {\r
263                 Location = location;\r
264                 Size = new Size(24, height);\r
265                 TextAlign = ContentAlignment.MiddleRight;\r
266             }\r
267 \r
268             public override void Reset()\r
269             {\r
270                 Text = "";\r
271                 BackColor = InitialBackColor;\r
272             }\r
273 \r
274             public override void Set(ShipStatus status)\r
275             {\r
276                 var cond = status.Cond;\r
277                 Text = cond.ToString("D");\r
278                 BackColor = cond >= 50\r
279                     ? CUDColors.Yellow\r
280                     : cond >= 30\r
281                         ? InitialBackColor\r
282                         : cond >= 20\r
283                             ? CUDColors.Orange\r
284                             : CUDColors.Red;\r
285             }\r
286         }\r
287 \r
288         public sealed class Level : ShipLabel\r
289         {\r
290             public Level(Point location, int height)\r
291             {\r
292                 Location = location;\r
293                 Size = new Size(24, height);\r
294                 TextAlign = ContentAlignment.MiddleRight;\r
295             }\r
296 \r
297             public override void Reset()\r
298             {\r
299                 Text = "";\r
300             }\r
301 \r
302             public override void Set(ShipStatus status)\r
303             {\r
304                 Text = status.Level.ToString("D");\r
305             }\r
306         }\r
307 \r
308         public sealed class Exp : ShipLabel\r
309         {\r
310             public Exp(Point location, int height)\r
311             {\r
312                 Location = location;\r
313                 Size = new Size(42, height);\r
314                 TextAlign = ContentAlignment.MiddleRight;\r
315             }\r
316 \r
317             public override void Reset()\r
318             {\r
319                 Text = "";\r
320             }\r
321 \r
322             public override void Set(ShipStatus status)\r
323             {\r
324                 Text = status.ExpToNext.ToString("D");\r
325             }\r
326         }\r
327 \r
328         public sealed class Fleet : ShipLabel\r
329         {\r
330             public Fleet(Point location)\r
331             {\r
332                 Location = location;\r
333                 AutoSize = true;\r
334             }\r
335 \r
336             public override void Reset()\r
337             {\r
338                 Text = "";\r
339             }\r
340 \r
341             public override void Set(ShipStatus status)\r
342             {\r
343                 Text = status.Fleet == null ? "" : new[] {"1", "2", "3", "4"}[status.Fleet.Number];\r
344             }\r
345         }\r
346 \r
347         public sealed class RepairTime : ShipLabel\r
348         {\r
349             public RepairTime(Point location)\r
350             {\r
351                 Location = location;\r
352                 AutoSize = true;\r
353             }\r
354 \r
355             public override void Reset()\r
356             {\r
357                 Text = "";\r
358             }\r
359 \r
360             public override void Set(ShipStatus status)\r
361             {\r
362                 SetRepairTime(status.RepairTime);\r
363             }\r
364 \r
365             public void SetRepairTime(TimeSpan span)\r
366             {\r
367                 Text = $@"{(int)span.TotalHours:d2}:{span:mm\:ss}";\r
368             }\r
369         }\r
370     }\r
371 }