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