OSDN Git Service

HPの背景色まわりのリファクタリング
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / ShipLabels.cs
1 // Copyright (C) 2014, 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
2 // \r
3 // This program is part of KancolleSniffer.\r
4 //\r
5 // KancolleSniffer is free software: you can redistribute it and/or modify\r
6 // it under the terms of the GNU General Public License as published by\r
7 // the Free Software Foundation, either version 3 of the License, or\r
8 // (at your option) any later version.\r
9 //\r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 //\r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 using System;\r
19 using System.Drawing;\r
20 using System.Linq;\r
21 using System.Text.RegularExpressions;\r
22 using System.Windows.Forms;\r
23 using static System.Math;\r
24 \r
25 namespace KancolleSniffer\r
26 {\r
27     public class ShipLabels\r
28     {\r
29         private readonly ShipLabel[][] _labels = new ShipLabel[ShipInfo.MemberCount][];\r
30         private readonly ShipLabel[][] _combinedLabels = new ShipLabel[ShipInfo.MemberCount * 2][];\r
31         private readonly ShipLabel[] _akashiTimers = new ShipLabel[ShipInfo.MemberCount];\r
32         private readonly ShipLabel[][] _damagedShipList = new ShipLabel[16][];\r
33         private Control _panelDamagedShipList;\r
34         private readonly ShipLabel[][] _ndockLabels = new ShipLabel[DockInfo.DockCount][];\r
35         public static Color[] ColumnColors = {SystemColors.Control, Color.FromArgb(255, 250, 250, 250)};\r
36 \r
37         public void CreateLabels(Control parent, EventHandler onClick)\r
38         {\r
39             parent.SuspendLayout();\r
40             const int top = 3, height = 12, lh = 16;\r
41             ShipLabel[] headings;\r
42             parent.Controls.AddRange(headings = new[]\r
43             {\r
44                 new ShipLabel {Location = new Point(109, top), Text = "HP", AutoSize = true},\r
45                 new ShipLabel {Location = new Point(128, top), Text = "cond", AutoSize = true},\r
46                 new ShipLabel {Location = new Point(163, top), Text = "Lv", AutoSize = true},\r
47                 new ShipLabel {Location = new Point(194, top), Text = "Exp", AutoSize = true},\r
48                 new ShipLabel {Location = new Point(0, 1), Size = new Size(parent.Width, lh - 1)}\r
49             });\r
50             foreach (var label in headings)\r
51             {\r
52                 label.Scale();\r
53                 label.BackColor = ColumnColors[1];\r
54             }\r
55             for (var i = 0; i < _labels.Length; i++)\r
56             {\r
57                 var y = top + lh * (i + 1);\r
58                 parent.Controls.AddRange(_labels[i] = new[]\r
59                 {\r
60                     new ShipLabel {Location = new Point(129, y), AutoSize = true, AnchorRight = true},\r
61                     new ShipLabel\r
62                     {\r
63                         Location = new Point(132, y),\r
64                         Size = new Size(23, height),\r
65                         TextAlign = ContentAlignment.MiddleRight\r
66                     },\r
67                     new ShipLabel\r
68                     {\r
69                         Location = new Point(157, y),\r
70                         Size = new Size(23, height),\r
71                         TextAlign = ContentAlignment.MiddleRight\r
72                     },\r
73                     new ShipLabel\r
74                     {\r
75                         Location = new Point(177, y),\r
76                         Size = new Size(41, height),\r
77                         TextAlign = ContentAlignment.MiddleRight\r
78                     },\r
79                     new ShipLabel {Location = new Point(2, y), AutoSize = true}, // 名前のZ-orderを下に\r
80                     new ShipLabel {Location = new Point(0, y - 2), Size = new Size(parent.Width, lh - 1)}\r
81                 });\r
82                 foreach (var label in _labels[i])\r
83                 {\r
84                     label.Scale();\r
85                     label.PresetColor = label.BackColor = ColumnColors[i % 2];\r
86                     label.Tag = i;\r
87                     label.Click += onClick;\r
88                 }\r
89             }\r
90             parent.ResumeLayout();\r
91         }\r
92 \r
93         public void SetShipInfo(ShipStatus[] statuses)\r
94         {\r
95             for (var i = 0; i < _labels.Length; i++)\r
96             {\r
97                 var labels = _labels[i];\r
98                 if (i < statuses.Length)\r
99                 {\r
100                     var s = statuses[i];\r
101                     labels[0].SetHp(s);\r
102                     labels[1].SetCond(s);\r
103                     labels[2].SetLevel(s);\r
104                     labels[3].SetExpToNext(s);\r
105                     labels[4].SetName(s);\r
106                 }\r
107                 else\r
108                 {\r
109                     labels[0].Text = labels[1].Text = labels[2].Text = labels[3].Text = "";\r
110                     labels[4].SetName("");\r
111                     labels[0].BackColor = labels[1].BackColor = labels[0].PresetColor;\r
112                 }\r
113             }\r
114         }\r
115 \r
116         public void CreateCombinedShipLabels(Control parent, EventHandler onClick)\r
117         {\r
118             parent.SuspendLayout();\r
119             const int top = 3, height = 12, lh = 16;\r
120             ShipLabel[] headings;\r
121             parent.Controls.AddRange(headings = new[]\r
122             {\r
123                 new ShipLabel {Location = new Point(68, top), Text = "HP", AutoSize = true},\r
124                 new ShipLabel {Location = new Point(86, top), Text = "cnd", AutoSize = true},\r
125                 new ShipLabel {Location = new Point(177, top), Text = "HP", AutoSize = true},\r
126                 new ShipLabel {Location = new Point(195, top), Text = "cnd", AutoSize = true},\r
127                 new ShipLabel {Location = new Point(0, 1), Size = new Size(parent.Width, lh - 1)}\r
128             });\r
129             foreach (var label in headings)\r
130             {\r
131                 label.Scale();\r
132                 label.BackColor = ColumnColors[1];\r
133             }\r
134             for (var i = 0; i < _combinedLabels.Length; i++)\r
135             {\r
136                 var x = (parent.Width / 2) * (i / ShipInfo.MemberCount);\r
137                 var y = top + lh * ((i % ShipInfo.MemberCount) + 1);\r
138                 parent.Controls.AddRange(_combinedLabels[i] = new[]\r
139                 {\r
140                     new ShipLabel {Location = new Point(x + 88, y), AutoSize = true, AnchorRight = true},\r
141                     new ShipLabel\r
142                     {\r
143                         Location = new Point(x + 86, y),\r
144                         Size = new Size(23, height),\r
145                         TextAlign = ContentAlignment.MiddleRight\r
146                     },\r
147                     new ShipLabel {Location = new Point(x + 2, y), AutoSize = true}, // 名前のZ-orderを下に\r
148                     new ShipLabel {Location = new Point(x, y - 2), Size = new Size(parent.Width / 2, lh - 1)}\r
149                 });\r
150                 foreach (var label in _combinedLabels[i])\r
151                 {\r
152                     label.Scale();\r
153                     label.PresetColor = label.BackColor = ColumnColors[i % 2];\r
154                     label.Tag = i;\r
155                     label.Click += onClick;\r
156                 }\r
157             }\r
158             parent.ResumeLayout();\r
159         }\r
160 \r
161         public void SetCombinedShipInfo(ShipStatus[] first, ShipStatus[] second)\r
162         {\r
163             for (var i = 0; i < _combinedLabels.Length; i++)\r
164             {\r
165                 var idx = i % ShipInfo.MemberCount;\r
166                 var statuses = i < ShipInfo.MemberCount ? first : second;\r
167                 var labels = _combinedLabels[i];\r
168                 if (idx < statuses.Length)\r
169                 {\r
170                     var s = statuses[idx];\r
171                     labels[0].SetHp(s);\r
172                     labels[1].SetCond(s);\r
173                     labels[2].SetName(s);\r
174                 }\r
175                 else\r
176                 {\r
177                     labels[0].Text = labels[1].Text = "";\r
178                     labels[2].SetName("");\r
179                     labels[0].BackColor = labels[1].BackColor = labels[0].PresetColor;\r
180                 }\r
181             }\r
182         }\r
183 \r
184         public void CreateAkashiTimers(Control parent)\r
185         {\r
186             parent.SuspendLayout();\r
187             for (var i = 0; i < _akashiTimers.Length; i++)\r
188             {\r
189                 const int x = 51;\r
190                 var y = 3 + 16 * (i + 1);\r
191                 ShipLabel label;\r
192                 parent.Controls.Add(\r
193                     label = _akashiTimers[i] =\r
194                         new ShipLabel\r
195                         {\r
196                             Location = new Point(x, y),\r
197                             Size = new Size(34, 12),\r
198                             TextAlign = ContentAlignment.TopRight\r
199                         });\r
200                 label.BackColor = ColumnColors[i % 2];\r
201             }\r
202             foreach (var label in _akashiTimers)\r
203                 label.Scale();\r
204             parent.ResumeLayout();\r
205         }\r
206 \r
207         public void SetAkashiTimer(ShipStatus[] statuses, AkashiTimer.RepairSpan[] timers)\r
208         {\r
209             var shortest = -1;\r
210             for (var i = 0; i < timers.Length; i++)\r
211             {\r
212                 if (timers[i].Span <= TimeSpan.Zero)\r
213                     continue;\r
214                 if (shortest == -1 || timers[i].Span < timers[shortest].Span)\r
215                     shortest = i;\r
216             }\r
217             for (var i = 0; i < _akashiTimers.Length; i++)\r
218             {\r
219                 var label = _akashiTimers[i];\r
220                 var labelHp = _labels[i][0];\r
221                 if (i >= timers.Length || timers[i].Span == TimeSpan.MinValue)\r
222                 {\r
223                     label.Visible = false;\r
224                     labelHp.ForeColor = Control.DefaultForeColor;\r
225                     continue;\r
226                 }\r
227                 var timer = timers[i];\r
228                 var stat = statuses[i];\r
229                 label.Visible = true;\r
230                 label.Text = timer.Span.ToString(@"mm\:ss");\r
231                 label.ForeColor = Control.DefaultForeColor;\r
232                 if (timer.Diff == 0)\r
233                 {\r
234                     labelHp.ForeColor = Control.DefaultForeColor;\r
235                     continue;\r
236                 }\r
237                 if (i == shortest)\r
238                     label.ForeColor = Color.Red;\r
239                 labelHp.ForeColor = Color.DimGray;\r
240                 labelHp.SetHp(stat.NowHp + timer.Diff, stat.MaxHp);\r
241             }\r
242         }\r
243 \r
244         public void CreateDamagedShipList(Control parent, EventHandler onClick)\r
245         {\r
246             parent.SuspendLayout();\r
247             for (var i = 0; i < _damagedShipList.Length; i++)\r
248             {\r
249                 var y = 3 + i * 16;\r
250                 const int height = 12;\r
251                 parent.Controls.AddRange(_damagedShipList[i] = new[]\r
252                 {\r
253                     new ShipLabel {Location = new Point(0, y), Size = new Size(11, height)},\r
254                     new ShipLabel {Location = new Point(119, y), Size = new Size(4, height - 1)},\r
255                     new ShipLabel {Location = new Point(75, y), AutoSize = true},\r
256                     new ShipLabel {Location = new Point(9, y), AutoSize = true},\r
257                     new ShipLabel {Location = new Point(0, y - 2), Size = new Size(parent.Width, height + 3)}\r
258                 });\r
259                 foreach (var label in _damagedShipList[i])\r
260                 {\r
261                     label.Scale();\r
262                     label.PresetColor = label.BackColor = ColumnColors[(i + 1) % 2];\r
263                     label.Click += onClick;\r
264                 }\r
265             }\r
266             _panelDamagedShipList = parent;\r
267             parent.ResumeLayout();\r
268         }\r
269 \r
270         public void SetDamagedShipList(ShipStatus[] list)\r
271         {\r
272             const int fleet = 0, name = 3, time = 2, damage = 1;\r
273             var parent = _panelDamagedShipList;\r
274             var num = Min(list.Length, _damagedShipList.Length);\r
275             if (num == 0)\r
276             {\r
277                 parent.Size = new Size(parent.Width, (int)Round(ShipLabel.ScaleFactor.Height * 19));\r
278                 var labels = _damagedShipList[0];\r
279                 labels[fleet].Text = "";\r
280                 labels[name].SetName("なし");\r
281                 labels[time].Text = "";\r
282                 labels[damage].BackColor = labels[damage].PresetColor;\r
283                 return;\r
284             }\r
285             parent.Size = new Size(parent.Width, (int)Round(ShipLabel.ScaleFactor.Height * (num * 16 + 3)));\r
286             for (var i = 0; i < num; i++)\r
287             {\r
288                 var s = list[i];\r
289                 var labels = _damagedShipList[i];\r
290                 labels[fleet].SetFleet(s);\r
291                 labels[name].SetName(s);\r
292                 labels[time].SetRepairTime(s);\r
293                 labels[damage].BackColor = ShipLabel.DamageColor(s, labels[damage].PresetColor);\r
294             }\r
295         }\r
296 \r
297         public void CreateNDockLabels(Control parent, EventHandler onClick)\r
298         {\r
299             for (var i = 0; i < _ndockLabels.Length; i++)\r
300             {\r
301                 var y = 3 + i * 15;\r
302                 parent.Controls.AddRange(\r
303                     _ndockLabels[i] = new[]\r
304                     {\r
305                         new ShipLabel\r
306                         {\r
307                             Location = new Point(138, y),\r
308                             AutoSize = true,\r
309                             AnchorRight = true\r
310                         },\r
311                         new ShipLabel {Location = new Point(29, y), AutoSize = true} // 名前のZ-orderを下に\r
312                     });\r
313                 foreach (var label in _ndockLabels[i])\r
314                 {\r
315                     label.Scale();\r
316                     label.Click += onClick;\r
317                 }\r
318             }\r
319             parent.Click += onClick;\r
320         }\r
321 \r
322         public void SetNDockLabels(NameAndTimer[] ndock)\r
323         {\r
324             for (var i = 0; i < _ndockLabels.Length; i++)\r
325                 _ndockLabels[i][1].SetName(ndock[i].Name);\r
326         }\r
327 \r
328         public void SetNDockTimer(int dock, RingTimer timer, bool finishTime)\r
329         {\r
330             var label = _ndockLabels[dock][0];\r
331             label.ForeColor = timer.IsFinished ? Color.Red : Color.Black;\r
332             if (timer.EndTime == DateTime.MinValue)\r
333             {\r
334                 label.Text = "";\r
335             }\r
336             else\r
337             {\r
338                 if (finishTime)\r
339                     label.Text = timer.EndTime.ToString(@"dd\ HH\:mm");\r
340                 else\r
341                     label.SetRepairTime(timer.Rest);\r
342             }\r
343         }\r
344     }\r
345 \r
346     [System.ComponentModel.DesignerCategory("Code")]\r
347     public class ShipLabel : Label\r
348     {\r
349         public static SizeF ScaleFactor { get; set; }\r
350         public Color PresetColor { get; set; }\r
351         public bool AnchorRight { get; set; }\r
352         private int _right = int.MinValue;\r
353         private int _left;\r
354 \r
355         public void SetName(ShipStatus status)\r
356         {\r
357             var empty = status.Id != -1 && status.Slot.All(e => e.Id == -1) ? "▫" : "";\r
358             var dc = status.PreparedDamageControl;\r
359             var dcname = dc == 42 ? "[ダ]" : dc == 43 ? "[メ]" : "";\r
360             SetName((status.Escaped ? "[避]" : dcname) + status.Name + empty);\r
361         }\r
362 \r
363         public void SetName(string name)\r
364         {\r
365             var lu = name != null && new Regex(@"^\p{Lu}").IsMatch(name);\r
366             var shift = (int)Round(ScaleFactor.Height);\r
367             if (lu && Font.Equals(Parent.Font))\r
368             {\r
369                 Location += new Size(0, -shift);\r
370                 Font = new Font("Tahoma", 8f);\r
371             }\r
372             else if (!lu && !Font.Equals(Parent.Font))\r
373             {\r
374                 Location += new Size(0, shift);\r
375                 Font = Parent.Font;\r
376             }\r
377             Text = name;\r
378         }\r
379 \r
380         public void SetHp(ShipStatus status)\r
381         {\r
382             Text = $"{status.NowHp:D}/{status.MaxHp:D}";\r
383             BackColor = DamageColor(status, PresetColor);\r
384         }\r
385 \r
386         public void SetHp(int now, int max)\r
387         {\r
388             SetHp(new ShipStatus {NowHp = now, MaxHp = max});\r
389         }\r
390 \r
391         public static Color DamageColor(ShipStatus status, Color backcolor)\r
392         {\r
393             switch (status.DamageLevel)\r
394             {\r
395                 case ShipStatus.Damage.Badly:\r
396                     return Color.Red;\r
397                 case ShipStatus.Damage.Half:\r
398                     return Color.Orange;\r
399                 case ShipStatus.Damage.Small:\r
400                     return Color.FromArgb(225, 225, 21);\r
401                 default:\r
402                     return backcolor;\r
403             }\r
404         }\r
405 \r
406         public void SetCond(ShipStatus status)\r
407         {\r
408             var cond = status.Cond;\r
409             Text = cond.ToString("D");\r
410             BackColor = cond >= 50\r
411                 ? Color.Yellow\r
412                 : cond >= 30\r
413                     ? PresetColor\r
414                     : cond >= 20 ? Color.Orange : Color.Red;\r
415         }\r
416 \r
417         public void SetLevel(ShipStatus status)\r
418         {\r
419             Text = status.Level.ToString("D");\r
420         }\r
421 \r
422         public void SetExpToNext(ShipStatus status)\r
423         {\r
424             Text = status.ExpToNext.ToString("D");\r
425         }\r
426 \r
427         public void SetRepairTime(ShipStatus status)\r
428         {\r
429             SetRepairTime(status.RepairTime);\r
430         }\r
431 \r
432         public void SetRepairTime(TimeSpan span)\r
433         {\r
434             Text = $@"{(int)span.TotalHours:d2}:{span:mm\:ss}";\r
435         }\r
436 \r
437         public void SetFleet(ShipStatus status)\r
438         {\r
439             Text = new[] {"", "1", "2", "3", "4"}[status.Fleet + 1];\r
440         }\r
441 \r
442         protected override void OnLayout(LayoutEventArgs levent)\r
443         {\r
444             base.OnLayout(levent);\r
445             if (!AnchorRight)\r
446                 return;\r
447             if (_right == int.MinValue || _left != Left)\r
448             {\r
449                 _right = Right;\r
450                 _left = Left;\r
451                 return;\r
452             }\r
453             if (_right == Right)\r
454                 return;\r
455             _left -= Right - _right;\r
456             Location = new Point(_left, Top);\r
457         }\r
458 \r
459         public void Scale()\r
460         {\r
461             Scale(ScaleFactor);\r
462         }\r
463     }\r
464 }