OSDN Git Service

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