OSDN Git Service

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