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