OSDN Git Service

補強増設以外のスロットが空の艦娘に印を付ける
[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             var empty = new ShipStatus();\r
96             for (var i = 0; i < _labels.Length; i++)\r
97             {\r
98                 var labels = _labels[i];\r
99                 var s = i < statuses.Length ? statuses[i] : empty;\r
100                 labels[0].SetHp(s);\r
101                 labels[1].SetCond(s);\r
102                 labels[2].SetLevel(s);\r
103                 labels[3].SetExpToNext(s);\r
104                 labels[4].SetName(s);\r
105             }\r
106         }\r
107 \r
108         public void CreateCombinedShipLabels(Control parent, EventHandler onClick)\r
109         {\r
110             parent.SuspendLayout();\r
111             const int top = 3, height = 12, lh = 16;\r
112             ShipLabel[] headings;\r
113             parent.Controls.AddRange(headings = new[]\r
114             {\r
115                 new ShipLabel {Location = new Point(68, top), Text = "HP", AutoSize = true},\r
116                 new ShipLabel {Location = new Point(86, top), Text = "cnd", AutoSize = true},\r
117                 new ShipLabel {Location = new Point(177, top), Text = "HP", AutoSize = true},\r
118                 new ShipLabel {Location = new Point(195, top), Text = "cnd", AutoSize = true},\r
119                 new ShipLabel {Location = new Point(0, 1), Size = new Size(parent.Width, lh - 1)}\r
120             });\r
121             foreach (var label in headings)\r
122             {\r
123                 label.Scale();\r
124                 label.BackColor = ColumnColors[1];\r
125             }\r
126             for (var i = 0; i < _combinedLabels.Length; i++)\r
127             {\r
128                 var x = (parent.Width / 2) * (i / ShipInfo.MemberCount);\r
129                 var y = top + lh * ((i % ShipInfo.MemberCount) + 1);\r
130                 parent.Controls.AddRange(_combinedLabels[i] = new[]\r
131                 {\r
132                     new ShipLabel {Location = new Point(x + 88, y), AutoSize = true, AnchorRight = true},\r
133                     new ShipLabel\r
134                     {\r
135                         Location = new Point(x + 86, y),\r
136                         Size = new Size(23, height),\r
137                         TextAlign = ContentAlignment.MiddleRight\r
138                     },\r
139                     new ShipLabel {Location = new Point(x + 2, y), AutoSize = true}, // 名前のZ-orderを下に\r
140                     new ShipLabel {Location = new Point(x, y - 2), Size = new Size(parent.Width / 2, lh - 1)}\r
141                 });\r
142                 foreach (var label in _combinedLabels[i])\r
143                 {\r
144                     label.Scale();\r
145                     label.PresetColor = label.BackColor = ColumnColors[i % 2];\r
146                     label.Tag = i;\r
147                     label.Click += onClick;\r
148                 }\r
149             }\r
150             parent.ResumeLayout();\r
151         }\r
152 \r
153         public void SetCombinedShipInfo(ShipStatus[] first, ShipStatus[] second)\r
154         {\r
155             var empty = new ShipStatus();\r
156             for (var i = 0; i < _combinedLabels.Length; i++)\r
157             {\r
158                 var idx = i % ShipInfo.MemberCount;\r
159                 var statuses = i < ShipInfo.MemberCount ? first : second;\r
160                 var labels = _combinedLabels[i];\r
161                 var s = idx < statuses.Length ? statuses[idx] : empty;\r
162                 labels[0].SetHp(s);\r
163                 labels[1].SetCond(s);\r
164                 labels[2].SetName(s);\r
165             }\r
166         }\r
167 \r
168         public void CreateAkashiTimers(Control parent)\r
169         {\r
170             parent.SuspendLayout();\r
171             for (var i = 0; i < _akashiTimers.Length; i++)\r
172             {\r
173                 const int x = 51;\r
174                 var y = 3 + 16 * (i + 1);\r
175                 ShipLabel label;\r
176                 parent.Controls.Add(\r
177                     label = _akashiTimers[i] =\r
178                         new ShipLabel\r
179                         {\r
180                             Location = new Point(x, y),\r
181                             Size = new Size(34, 12),\r
182                             TextAlign = ContentAlignment.TopRight\r
183                         });\r
184                 label.BackColor = ColumnColors[i % 2];\r
185             }\r
186             foreach (var label in _akashiTimers)\r
187                 label.Scale();\r
188             parent.ResumeLayout();\r
189         }\r
190 \r
191         public void SetAkashiTimer(ShipStatus[] statuses, AkashiTimer.RepairSpan[] timers)\r
192         {\r
193             var shortest = -1;\r
194             for (var i = 0; i < timers.Length; i++)\r
195             {\r
196                 if (timers[i].Span <= TimeSpan.Zero)\r
197                     continue;\r
198                 if (shortest == -1 || timers[i].Span < timers[shortest].Span)\r
199                     shortest = i;\r
200             }\r
201             for (var i = 0; i < _akashiTimers.Length; i++)\r
202             {\r
203                 var label = _akashiTimers[i];\r
204                 var labelHp = _labels[i][0];\r
205                 if (i >= timers.Length || timers[i].Span == TimeSpan.MinValue)\r
206                 {\r
207                     label.Visible = false;\r
208                     labelHp.ForeColor = Control.DefaultForeColor;\r
209                     continue;\r
210                 }\r
211                 var timer = timers[i];\r
212                 var stat = statuses[i];\r
213                 label.Visible = true;\r
214                 label.Text = timer.Span.ToString(@"mm\:ss");\r
215                 label.ForeColor = Control.DefaultForeColor;\r
216                 if (timer.Diff == 0)\r
217                 {\r
218                     labelHp.ForeColor = Control.DefaultForeColor;\r
219                     continue;\r
220                 }\r
221                 if (i == shortest)\r
222                     label.ForeColor = Color.Red;\r
223                 labelHp.ForeColor = Color.DimGray;\r
224                 labelHp.SetHp(stat.NowHp + timer.Diff, stat.MaxHp);\r
225             }\r
226         }\r
227 \r
228         public void CreateDamagedShipList(Control parent, EventHandler onClick)\r
229         {\r
230             parent.SuspendLayout();\r
231             for (var i = 0; i < _damagedShipList.Length; i++)\r
232             {\r
233                 var y = 3 + i * 16;\r
234                 const int height = 12;\r
235                 parent.Controls.AddRange(_damagedShipList[i] = new[]\r
236                 {\r
237                     new ShipLabel {Location = new Point(0, y), Size = new Size(11, height)},\r
238                     new ShipLabel {Location = new Point(119, y), Size = new Size(4, height - 1)},\r
239                     new ShipLabel {Location = new Point(75, y), AutoSize = true},\r
240                     new ShipLabel {Location = new Point(9, y), AutoSize = true},\r
241                     new ShipLabel {Location = new Point(0, y - 2), Size = new Size(parent.Width, height + 3)}\r
242                 });\r
243                 foreach (var label in _damagedShipList[i])\r
244                 {\r
245                     label.Scale();\r
246                     label.PresetColor = label.BackColor = ColumnColors[(i + 1) % 2];\r
247                     label.Click += onClick;\r
248                 }\r
249             }\r
250             _panelDamagedShipList = parent;\r
251             parent.ResumeLayout();\r
252         }\r
253 \r
254         public void SetDamagedShipList(ShipStatus[] list)\r
255         {\r
256             const int fleet = 0, name = 3, time = 2, damage = 1;\r
257             var parent = _panelDamagedShipList;\r
258             var num = Min(list.Length, _damagedShipList.Length);\r
259             if (num == 0)\r
260             {\r
261                 parent.Size = new Size(parent.Width, (int)Round(ShipLabel.ScaleFactor.Height * 19));\r
262                 var labels = _damagedShipList[0];\r
263                 labels[fleet].Text = "";\r
264                 labels[name].SetName("なし");\r
265                 labels[time].Text = "";\r
266                 labels[damage].BackColor = labels[damage].PresetColor;\r
267                 return;\r
268             }\r
269             parent.Size = new Size(parent.Width, (int)Round(ShipLabel.ScaleFactor.Height * (num * 16 + 3)));\r
270             var colors = new[] {Color.FromArgb(255, 225, 225, 21), Color.Orange, Color.Red};\r
271             for (var i = 0; i < num; i++)\r
272             {\r
273                 var s = list[i];\r
274                 var labels = _damagedShipList[i];\r
275                 labels[fleet].SetFleet(s);\r
276                 labels[name].SetName(s);\r
277                 labels[time].SetRepairTime(s);\r
278                 labels[damage].BackColor = (int)s.DamageLevel == 0\r
279                     ? labels[damage].PresetColor\r
280                     : colors[(int)s.DamageLevel - 1];\r
281             }\r
282         }\r
283 \r
284         public void CreateNDockLabels(Control parent, EventHandler onClick)\r
285         {\r
286             for (var i = 0; i < _ndockLabels.Length; i++)\r
287             {\r
288                 var y = 3 + i * 15;\r
289                 parent.Controls.AddRange(\r
290                     _ndockLabels[i] = new[]\r
291                     {\r
292                         new ShipLabel\r
293                         {\r
294                             Location = new Point(93, y),\r
295                             AutoSize = true,\r
296                             AnchorRight = true,\r
297                             Text = "00:00:00"\r
298                         },\r
299                         new ShipLabel {Location = new Point(29, y), AutoSize = true} // 名前のZ-orderを下に\r
300                     });\r
301                 foreach (var label in _ndockLabels[i])\r
302                 {\r
303                     label.Scale();\r
304                     label.Click += onClick;\r
305                 }\r
306             }\r
307             parent.Click += onClick;\r
308         }\r
309 \r
310         public void SetNDockLabels(NameAndTimer[] ndock)\r
311         {\r
312             for (var i = 0; i < _ndockLabels.Length; i++)\r
313                 _ndockLabels[i][1].SetName(ndock[i].Name);\r
314         }\r
315 \r
316         public void SetNDockTimer(int dock, RingTimer timer, bool finishTime)\r
317         {\r
318             var label = _ndockLabels[dock][0];\r
319             label.ForeColor = timer.IsFinished ? Color.Red : Color.Black;\r
320             if (finishTime)\r
321                 label.SetRepairFinishTime(timer.EndTime);\r
322             else\r
323                 label.SetRepairTime(timer.Rest);\r
324         }\r
325     }\r
326 \r
327     [System.ComponentModel.DesignerCategory("Code")]\r
328     public class ShipLabel : Label\r
329     {\r
330         public static SizeF ScaleFactor { get; set; }\r
331         public Color PresetColor { get; set; }\r
332         public bool AnchorRight { get; set; }\r
333         private int _right = int.MinValue;\r
334         private int _left;\r
335 \r
336         public void SetName(ShipStatus status)\r
337         {\r
338             var empty = status.Id != -1 && status.Slot.All(e => e.Id == -1) ? "▫" : "";\r
339             var dc = status.PreparedDamageControl;\r
340             var dcname = dc == 42 ? "[ダ]" : dc == 43 ? "[メ]" : "";\r
341             SetName((status.Escaped ? "[避]" : dcname) + status.Name + empty);\r
342         }\r
343 \r
344         public void SetName(string name)\r
345         {\r
346             var lu = name != null && new Regex(@"^\p{Lu}").IsMatch(name);\r
347             var shift = (int)Round(ScaleFactor.Height);\r
348             if (lu && Font.Equals(Parent.Font))\r
349             {\r
350                 Location += new Size(0, -shift);\r
351                 Font = new Font("Tahoma", 8f);\r
352             }\r
353             else if (!lu && !Font.Equals(Parent.Font))\r
354             {\r
355                 Location += new Size(0, shift);\r
356                 Font = Parent.Font;\r
357             }\r
358             Text = name;\r
359         }\r
360 \r
361         public void SetHp(ShipStatus status)\r
362         {\r
363             SetHp(status.NowHp, status.MaxHp);\r
364         }\r
365 \r
366         public void SetHp(int now, int max)\r
367         {\r
368             var colors = new[] {PresetColor, Color.FromArgb(255, 240, 240, 100), Color.Orange, Color.Red};\r
369             Text = $"{now:D}/{max:D}";\r
370             BackColor = colors[(int)ShipStatus.CalcDamage(now, max)];\r
371         }\r
372 \r
373         public void SetCond(ShipStatus status)\r
374         {\r
375             if (status.Level == 0)\r
376             {\r
377                 Text = "0";\r
378                 BackColor = PresetColor;\r
379                 return;\r
380             }\r
381             var cond = status.Cond;\r
382             Text = cond.ToString("D");\r
383             BackColor = cond >= 50\r
384                 ? Color.Yellow\r
385                 : cond >= 30\r
386                     ? PresetColor\r
387                     : cond >= 20 ? Color.Orange : Color.Red;\r
388         }\r
389 \r
390         public void SetLevel(ShipStatus status)\r
391         {\r
392             Text = status.Level.ToString("D");\r
393         }\r
394 \r
395         public void SetExpToNext(ShipStatus status)\r
396         {\r
397             Text = status.ExpToNext.ToString("D");\r
398         }\r
399 \r
400         public void SetRepairTime(ShipStatus status)\r
401         {\r
402             SetRepairTime(status.RepairTime);\r
403         }\r
404 \r
405         public void SetRepairTime(TimeSpan span)\r
406         {\r
407             Text = $@"{(int)span.TotalHours:d2}:{span:mm\:ss}";\r
408         }\r
409 \r
410         public void SetRepairFinishTime(DateTime time)\r
411         {\r
412             Text = time == DateTime.MinValue ? "-------" : time.ToString(@"dd\ HH\:mm");\r
413         }\r
414 \r
415         public void SetFleet(ShipStatus status)\r
416         {\r
417             Text = new[] {"", "1", "2", "3", "4"}[status.Fleet + 1];\r
418         }\r
419 \r
420         protected override void OnLayout(LayoutEventArgs levent)\r
421         {\r
422             base.OnLayout(levent);\r
423             if (!AnchorRight)\r
424                 return;\r
425             if (_right == int.MinValue || _left != Left)\r
426             {\r
427                 _right = Right;\r
428                 _left = Left;\r
429                 return;\r
430             }\r
431             if (_right == Right)\r
432                 return;\r
433             _left -= Right - _right;\r
434             Location = new Point(_left, Top);\r
435         }\r
436 \r
437         public void Scale()\r
438         {\r
439             Scale(ScaleFactor);\r
440         }\r
441     }\r
442 }