OSDN Git Service

戦況で支援が来るのをわかるようにする
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / View / MainFormLabels.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.Windows.Forms;\r
19 using KancolleSniffer.Model;\r
20 using static System.Math;\r
21 \r
22 namespace KancolleSniffer.View\r
23 {\r
24     /// <summary>\r
25     /// 艦娘名の横幅\r
26     /// 艦娘名のラベルのZ-orderは最下なので名前が長すぎると右隣のラベルの下に隠れるが、\r
27     /// 空装備マークはラベルの右端に表示するので右端が見えるように縮める必要がある。\r
28     /// </summary>\r
29     public enum ShipNameWidth\r
30     {\r
31         MainPanel = 92, // 左端2 HP右端129幅35 129-2-35=92\r
32         AkashiTimer = 53, // 左端2 タイマー左端55 55-2=53 漢字4文字\r
33         NDock = 65, // 左端29 終了時刻右端138幅47 138-47-29=62 空装備マークなし漢字5文字65\r
34         RepairList = 65, // 左端9 時間左端75 75-9=66 漢字5文字65\r
35         RepairListFull = 73, // 左端10 HP右端118幅35 118-10-35=73\r
36         ShipList = 81, // 左端10 HP右端126幅35 126-10-35=81\r
37         GroupConfig = 80, // 左端10 レベル左端90 90-10=80\r
38         Combined = 53, // 左端2 HP右端88幅35 88-2-35=51 空装備マーク犠牲 漢字4文字53\r
39         BattleResult = 65, // 左端2 HP右端101幅35 101-1-35=65\r
40         CiShipName = 65, // 左端168幅236 236-168=68 漢字5文字65\r
41         Max = int.MaxValue\r
42     }\r
43 \r
44     public class MainFormLabels\r
45     {\r
46         private readonly ShipLabel[][] _shipLabels = new ShipLabel[ShipInfo.MemberCount][];\r
47         private readonly ShipLabel[][] _shipLabels7 = new ShipLabel[7][];\r
48         private readonly ShipLabel[][] _combinedLabels = new ShipLabel[ShipInfo.MemberCount * 2][];\r
49         private readonly ShipLabel[] _akashiTimers = new ShipLabel[ShipInfo.MemberCount];\r
50         private readonly ShipLabel[] _akashiTimers7 = new ShipLabel[ShipInfo.MemberCount];\r
51         private readonly ShipLabel[][] _ndockLabels = new ShipLabel[DockInfo.DockCount][];\r
52         private readonly List<ShipLabel> _hpLabels = new List<ShipLabel>();\r
53         public bool ShowHpInPercent { get; private set; }\r
54 \r
55         public void CreateShipLabels(Control parent, EventHandler onClick)\r
56         {\r
57             CreateShipLabels(parent, onClick, _shipLabels, 16);\r
58         }\r
59 \r
60         public void CreateShipLabels7(Control parent, EventHandler onClick)\r
61         {\r
62             CreateShipLabels(parent, onClick, _shipLabels7, 14);\r
63         }\r
64 \r
65         public void CreateShipLabels(Control parent, EventHandler onClick, ShipLabel[][] shipLabels, int lineHeight)\r
66         {\r
67             parent.SuspendLayout();\r
68             const int top = 1, height = 12;\r
69             ShipLabel[] headings;\r
70             parent.Controls.AddRange(headings = new[]\r
71             {\r
72                 new ShipLabel {Location = new Point(109, top), Text = "HP", AutoSize = true},\r
73                 new ShipLabel {Location = new Point(128, top), Text = "cond", AutoSize = true},\r
74                 new ShipLabel {Location = new Point(162, top), Text = "Lv", AutoSize = true},\r
75                 new ShipLabel {Location = new Point(194, top), Text = "Exp", AutoSize = true},\r
76                 new ShipLabel {Location = new Point(0, 1), Size = new Size(parent.Width, lineHeight - 1)}\r
77             });\r
78             foreach (var label in headings)\r
79             {\r
80                 label.Scale();\r
81                 label.BackColor = ShipLabel.ColumnColors[1];\r
82             }\r
83             for (var i = 0; i < shipLabels.Length; i++)\r
84             {\r
85                 var y = top + lineHeight * (i + 1);\r
86                 parent.Controls.AddRange(shipLabels[i] = new[]\r
87                 {\r
88                     new ShipLabel\r
89                     {\r
90                         Location = new Point(129, y),\r
91                         AutoSize = true,\r
92                         AnchorRight = true,\r
93                         MinimumSize = new Size(0, lineHeight),\r
94                         TextAlign = ContentAlignment.MiddleLeft,\r
95                         Cursor = Cursors.Hand\r
96                     },\r
97                     new ShipLabel\r
98                     {\r
99                         Location = new Point(131, y),\r
100                         Size = new Size(24, lineHeight),\r
101                         TextAlign = ContentAlignment.MiddleRight\r
102                     },\r
103                     new ShipLabel\r
104                     {\r
105                         Location = new Point(155, y + 2),\r
106                         Size = new Size(24, height),\r
107                         TextAlign = ContentAlignment.MiddleRight\r
108                     },\r
109                     new ShipLabel\r
110                     {\r
111                         Location = new Point(176, y + 2),\r
112                         Size = new Size(42, height),\r
113                         TextAlign = ContentAlignment.MiddleRight\r
114                     },\r
115                     new ShipLabel {Location = new Point(2, y + 2), AutoSize = true}, // 名前のZ-orderを下に\r
116                     new ShipLabel {Location = new Point(0, y), Size = new Size(parent.Width, lineHeight)}\r
117                 });\r
118                 foreach (var label in shipLabels[i])\r
119                 {\r
120                     label.Scale();\r
121                     label.PresetColor = label.BackColor = ShipLabel.ColumnColors[i % 2];\r
122                     label.Tag = i;\r
123                     label.Click += onClick;\r
124                 }\r
125                 var hpLabel = shipLabels[i][0];\r
126                 _hpLabels.Add(hpLabel);\r
127                 hpLabel.DoubleClick += HpLabelClickHandler;\r
128             }\r
129             headings[0].Cursor = Cursors.Hand;\r
130             headings[0].Click += HpLabelClickHandler;\r
131             parent.ResumeLayout();\r
132         }\r
133 \r
134         private void HpLabelClickHandler(object sender, EventArgs ev)\r
135         {\r
136             ToggleHpPercent();\r
137         }\r
138 \r
139         public void ToggleHpPercent()\r
140         {\r
141             ShowHpInPercent = !ShowHpInPercent;\r
142             foreach (var label in _hpLabels)\r
143                 label.ToggleHpPercent();\r
144         }\r
145 \r
146         public void SetShipLabels(IReadOnlyList<ShipStatus> ships)\r
147         {\r
148             SetShipLabels(ships, ships.Count == 7 ? _shipLabels7 : _shipLabels);\r
149         }\r
150 \r
151         public void SetShipLabels(IReadOnlyList<ShipStatus> ships, ShipLabel[][] shipLabels)\r
152         {\r
153             for (var i = 0; i < shipLabels.Length; i++)\r
154             {\r
155                 var labels = shipLabels[i];\r
156                 var ship = i < ships.Count ? ships[i] : null;\r
157                 labels[0].SetHp(ship);\r
158                 labels[1].SetCond(ship);\r
159                 labels[2].SetLevel(ship);\r
160                 labels[3].SetExpToNext(ship);\r
161                 labels[4].SetName(ship, ShipNameWidth.MainPanel);\r
162             }\r
163         }\r
164 \r
165         public void CreateCombinedShipLabels(Control parent, EventHandler onClick)\r
166         {\r
167             parent.SuspendLayout();\r
168             const int top = 1, lh = 16;\r
169             const int parentWidth = 220; // parent.Widthを使うとDPIスケーリング時に計算がくるうので\r
170             ShipLabel[] headings;\r
171             parent.Controls.AddRange(headings = new[]\r
172             {\r
173                 new ShipLabel {Location = new Point(68, top), Text = "HP", AutoSize = true},\r
174                 new ShipLabel {Location = new Point(86, top), Text = "cnd", AutoSize = true},\r
175                 new ShipLabel {Location = new Point(177, top), Text = "HP", AutoSize = true},\r
176                 new ShipLabel {Location = new Point(195, top), Text = "cnd", AutoSize = true},\r
177                 new ShipLabel {Location = new Point(0, 1), Size = new Size(parentWidth, lh - 1)}\r
178             });\r
179             foreach (var label in headings)\r
180             {\r
181                 label.Scale();\r
182                 label.BackColor = ShipLabel.ColumnColors[1];\r
183             }\r
184             for (var i = 0; i < _combinedLabels.Length; i++)\r
185             {\r
186                 var x = parentWidth / 2 * (i / ShipInfo.MemberCount);\r
187                 var y = top + lh * (i % ShipInfo.MemberCount + 1);\r
188                 parent.Controls.AddRange(_combinedLabels[i] = new[]\r
189                 {\r
190                     new ShipLabel\r
191                     {\r
192                         Location = new Point(x + 88, y),\r
193                         AutoSize = true,\r
194                         AnchorRight = true,\r
195                         MinimumSize = new Size(0, lh),\r
196                         TextAlign = ContentAlignment.MiddleLeft,\r
197                         Cursor = Cursors.Hand\r
198                     },\r
199                     new ShipLabel\r
200                     {\r
201                         Location = new Point(x + 85, y),\r
202                         Size = new Size(24, lh),\r
203                         TextAlign = ContentAlignment.MiddleRight\r
204                     },\r
205                     new ShipLabel {Location = new Point(x + 2, y + 2), AutoSize = true}, // 名前のZ-orderを下に\r
206                     new ShipLabel {Location = new Point(x, y), Size = new Size(parentWidth / 2, lh)}\r
207                 });\r
208                 foreach (var label in _combinedLabels[i])\r
209                 {\r
210                     label.Scale();\r
211                     label.PresetColor = label.BackColor = ShipLabel.ColumnColors[i % 2];\r
212                     label.Tag = i;\r
213                     label.Click += onClick;\r
214                 }\r
215                 var hpLabel = _combinedLabels[i][0];\r
216                 _hpLabels.Add(hpLabel);\r
217                 hpLabel.DoubleClick += HpLabelClickHandler;\r
218             }\r
219             headings[0].Cursor = headings[2].Cursor = Cursors.Hand;\r
220             headings[0].Click += HpLabelClickHandler;\r
221             headings[2].Click += HpLabelClickHandler;\r
222             parent.ResumeLayout();\r
223         }\r
224 \r
225         public void SetCombinedShipLabels(IReadOnlyList<ShipStatus> first, IReadOnlyList<ShipStatus> second)\r
226         {\r
227             for (var i = 0; i < _combinedLabels.Length; i++)\r
228             {\r
229                 var idx = i % ShipInfo.MemberCount;\r
230                 var ships = i < ShipInfo.MemberCount ? first : second;\r
231                 var labels = _combinedLabels[i];\r
232                 var s = idx < ships.Count ? ships[idx] : null;\r
233                 labels[0].SetHp(s);\r
234                 labels[1].SetCond(s);\r
235                 labels[2].SetName(s, ShipNameWidth.Combined);\r
236             }\r
237         }\r
238 \r
239         public void CreateAkashiTimers(Control parent)\r
240         {\r
241             CreateAkashiTimers(parent, _akashiTimers, 16);\r
242         }\r
243 \r
244         public void CreateAkashiTimers7(Control parent)\r
245         {\r
246             CreateAkashiTimers(parent, _akashiTimers7, 14);\r
247         }\r
248 \r
249         public void CreateAkashiTimers(Control parent, ShipLabel[] timerLabels, int lineHeight)\r
250         {\r
251             parent.SuspendLayout();\r
252             for (var i = 0; i < timerLabels.Length; i++)\r
253             {\r
254                 const int x = 55;\r
255                 var y = 3 + lineHeight * (i + 1);\r
256                 ShipLabel label;\r
257                 parent.Controls.Add(\r
258                     label = timerLabels[i] =\r
259                         new ShipLabel\r
260                         {\r
261                             Location = new Point(x, y),\r
262                             Size = new Size(31, 12),\r
263                             TextAlign = ContentAlignment.TopRight\r
264                         });\r
265                 label.BackColor = ShipLabel.ColumnColors[i % 2];\r
266             }\r
267             foreach (var label in timerLabels)\r
268                 label.Scale();\r
269             parent.ResumeLayout();\r
270         }\r
271 \r
272         public void AdjustAkashiTimers()\r
273         {\r
274             AdjustAkashiTimers(_akashiTimers, 16);\r
275             AdjustAkashiTimers(_akashiTimers7, 14);\r
276         }\r
277 \r
278         public void AdjustAkashiTimers(ShipLabel[] timers, int lineHeight)\r
279         {\r
280             var scale = ShipLabel.ScaleFactor;\r
281             if (scale.Height < 1.2)\r
282                 return;\r
283             for (var i = 0; i < timers.Length; i++)\r
284             {\r
285                 const int x = 55;\r
286                 var y = 3 + lineHeight * (i + 1);\r
287                 timers[i].Location = new Point((int)Round(x * scale.Width) - 3, (int)Round(y * scale.Height));\r
288                 timers[i].Size = new Size((int)Round(31 * scale.Width) + 1, (int)Round(12 * scale.Height));\r
289             }\r
290         }\r
291 \r
292         public void SetAkashiTimer(IReadOnlyList<ShipStatus> ships, AkashiTimer.RepairSpan[] timers)\r
293         {\r
294             if (ships.Count == 7)\r
295             {\r
296                 SetAkashiTimer(ships, timers, _akashiTimers7, _shipLabels7);\r
297             }\r
298             else\r
299             {\r
300                 SetAkashiTimer(ships, timers, _akashiTimers, _shipLabels);\r
301             }\r
302         }\r
303 \r
304         public void SetAkashiTimer(IReadOnlyList<ShipStatus> ships, AkashiTimer.RepairSpan[] timers, ShipLabel[] timerLabels,\r
305             ShipLabel[][] shipLabels)\r
306         {\r
307             var shortest = -1;\r
308             for (var i = 0; i < timers.Length; i++)\r
309             {\r
310                 if (timers[i].Span <= TimeSpan.Zero)\r
311                     continue;\r
312                 if (shortest == -1 || timers[i].Span < timers[shortest].Span)\r
313                     shortest = i;\r
314             }\r
315             for (var i = 0; i < timerLabels.Length; i++)\r
316             {\r
317                 var label = timerLabels[i];\r
318                 var labelHp = shipLabels[i][0];\r
319                 var labelName = shipLabels[i][4];\r
320                 if (i >= timers.Length || timers[i].Span == TimeSpan.MinValue)\r
321                 {\r
322                     label.Visible = false;\r
323                     labelHp.ForeColor = Control.DefaultForeColor;\r
324                     continue;\r
325                 }\r
326                 var timer = timers[i];\r
327                 var stat = ships[i];\r
328                 label.Visible = true;\r
329                 label.Text = timer.Span.ToString(@"mm\:ss");\r
330                 label.ForeColor = Control.DefaultForeColor;\r
331                 labelName.SetName(stat, ShipNameWidth.AkashiTimer);\r
332                 if (timer.Diff == 0)\r
333                 {\r
334                     labelHp.ForeColor = Control.DefaultForeColor;\r
335                     continue;\r
336                 }\r
337                 if (i == shortest)\r
338                     label.ForeColor = CUDColors.Red;\r
339                 labelHp.ForeColor = Color.DimGray;\r
340                 labelHp.SetHp(stat.NowHp + timer.Diff, stat.MaxHp);\r
341             }\r
342         }\r
343 \r
344         public void CreateNDockLabels(Control parent, EventHandler onClick)\r
345         {\r
346             const int lh = 15;\r
347             for (var i = 0; i < _ndockLabels.Length; i++)\r
348             {\r
349                 var y = i * lh;\r
350                 parent.Controls.AddRange(\r
351                     _ndockLabels[i] = new[]\r
352                     {\r
353                         new ShipLabel\r
354                         {\r
355                             Location = new Point(138, y + 2),\r
356                             AutoSize = true,\r
357                             AnchorRight = true,\r
358                             MinimumSize = new Size(0, lh),\r
359                             TextAlign = ContentAlignment.MiddleLeft,\r
360                             Cursor = Cursors.Hand\r
361                         },\r
362                         new ShipLabel {Location = new Point(29, y + 3), AutoSize = true} // 名前のZ-orderを下に\r
363                     });\r
364                 foreach (var label in _ndockLabels[i])\r
365                 {\r
366                     label.Scale();\r
367                     label.Click += onClick;\r
368                 }\r
369             }\r
370         }\r
371 \r
372         public void SetNDockLabels(NameAndTimer[] ndock)\r
373         {\r
374             for (var i = 0; i < _ndockLabels.Length; i++)\r
375                 _ndockLabels[i][1].SetName(ndock[i].Name, ShipNameWidth.NDock);\r
376         }\r
377 \r
378         public void SetNDockTimer(int dock, AlarmTimer timer, DateTime now, bool finishTime)\r
379         {\r
380             var label = _ndockLabels[dock][0];\r
381             label.ForeColor = timer.IsFinished(now) ? CUDColors.Red : Color.Black;\r
382             label.Text = timer.ToString(now, finishTime);\r
383         }\r
384     }\r
385 }