OSDN Git Service

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