OSDN Git Service

基地空襲戦の制空値がメインウィンドウに表示されないのを直す
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / View / MainShipLabels.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 \r
21 namespace KancolleSniffer.View\r
22 {\r
23     public class MainShipPanels\r
24     {\r
25         public Control PanelShipInfo { get; set; }\r
26         public Control Panel7Ships { get; set; }\r
27         public Control PanelCombinedFleet { get; set; }\r
28     }\r
29 \r
30     public class MainShipLabels\r
31     {\r
32         private readonly ShipLabelLines _shipLines;\r
33         private readonly ShipLabelLines _shipLines7;\r
34         private readonly CombinedShipLines _combinedLines = new CombinedShipLines();\r
35         private readonly HpDisplay _hpDisplay = new HpDisplay();\r
36 \r
37         public bool ShowHpInPercent => _hpDisplay.InPercent;\r
38 \r
39         public MainShipLabels()\r
40         {\r
41             _shipLines = new ShipLabelLines(ShipInfo.MemberCount, 16);\r
42             _shipLines7 = new ShipLabelLines(7, 14);\r
43         }\r
44 \r
45         public void CreateAllShipLabels(MainShipPanels panels, EventHandler onClick)\r
46         {\r
47             _shipLines.Create(panels.PanelShipInfo, _hpDisplay, onClick);\r
48             _shipLines7.Create(panels.Panel7Ships, _hpDisplay, onClick);\r
49             _combinedLines.Create(panels.PanelCombinedFleet, _hpDisplay, onClick);\r
50         }\r
51 \r
52         public void ToggleHpPercent()\r
53         {\r
54             _hpDisplay.ToggleHpPercent();\r
55         }\r
56 \r
57         private class HpDisplay\r
58         {\r
59             private readonly List<ShipLabel.Hp> _labels = new List<ShipLabel.Hp>();\r
60             public bool InPercent { get; private set; }\r
61 \r
62             public void SetClickHandler(Control label)\r
63             {\r
64                 label.Click += LabelClickHandler;\r
65             }\r
66 \r
67             public void AddHpLabel(ShipLabel.Hp label)\r
68             {\r
69                 _labels.Add(label);\r
70                 label.DoubleClick += LabelClickHandler;\r
71             }\r
72 \r
73             private void LabelClickHandler(object sender, EventArgs ev)\r
74             {\r
75                 ToggleHpPercent();\r
76             }\r
77 \r
78             public void ToggleHpPercent()\r
79             {\r
80                 InPercent = !InPercent;\r
81                 foreach (var label in _labels)\r
82                     label.ToggleHpPercent();\r
83             }\r
84         }\r
85 \r
86         public void SetShipLabels(IReadOnlyList<ShipStatus> ships)\r
87         {\r
88             (ships.Count == 7 ? _shipLines7 : _shipLines).Set(ships);\r
89         }\r
90 \r
91         public void SetCombinedShipLabels(IReadOnlyList<ShipStatus> first, IReadOnlyList<ShipStatus> second)\r
92         {\r
93             _combinedLines.Set(first, second);\r
94         }\r
95 \r
96         public void SetAkashiTimer(IReadOnlyList<ShipStatus> ships, AkashiTimer.RepairSpan[] timers)\r
97         {\r
98             (ships.Count == 7 ? _shipLines7 : _shipLines).SetAkashiTimer(ships, timers);\r
99         }\r
100 \r
101         private class ShipLabelLines\r
102         {\r
103             private readonly int _lineHeight;\r
104             private readonly ShipLabels[] _shipLines;\r
105             private readonly AkashiTimerLabels _akashiTimerLabels;\r
106 \r
107             private const int Top = 1;\r
108             private const int LabelHeight = 12;\r
109 \r
110             public ShipLabelLines(int lines, int lineHeight)\r
111             {\r
112                 _shipLines = new ShipLabels[lines];\r
113                 _akashiTimerLabels = new AkashiTimerLabels(lineHeight, _shipLines);\r
114                 _lineHeight = lineHeight;\r
115             }\r
116 \r
117             public void Create(Control parent, HpDisplay hpDisplay, EventHandler onClick)\r
118             {\r
119                 parent.SuspendLayout();\r
120                 _akashiTimerLabels.Create(parent);\r
121                 CreateHeader(parent, hpDisplay);\r
122                 for (var i = 0; i < _shipLines.Length; i++)\r
123                 {\r
124 \r
125                     var y = Top + _lineHeight * (i + 1);\r
126                     var labels = _shipLines[i] = new ShipLabels\r
127                     {\r
128                         Name = new ShipLabel.Name(new Point(2, y + 2), ShipNameWidth.MainPanel),\r
129                         Hp = new ShipLabel.Hp(new Point(129, y), _lineHeight),\r
130                         Cond = new ShipLabel.Cond(new Point(131, y), _lineHeight),\r
131                         Level = new ShipLabel.Level(new Point(155, y + 2), LabelHeight),\r
132                         Exp = new ShipLabel.Exp(new Point(176, y + 2), LabelHeight),\r
133                         BackGround = new Label {Location = new Point(0, y), Size = new Size(parent.Width, _lineHeight)}\r
134                     };\r
135                     labels.Arrange(parent, CustomColors.ColumnColors.DarkFirst(i));\r
136                     labels.SetClickHandler(onClick);\r
137                     labels.SetTag(i);\r
138                     hpDisplay.AddHpLabel(labels.Hp);\r
139                 }\r
140                 parent.ResumeLayout();\r
141             }\r
142 \r
143             private void CreateHeader(Control parent, HpDisplay hpDisplay)\r
144             {\r
145                 var headings = new Control[]\r
146                 {\r
147                     new Label {Location = new Point(109, Top), Text = "HP", AutoSize = true},\r
148                     new Label {Location = new Point(128, Top), Text = "cond", AutoSize = true},\r
149                     new Label {Location = new Point(162, Top), Text = "Lv", AutoSize = true},\r
150                     new Label {Location = new Point(194, Top), Text = "Exp", AutoSize = true},\r
151                     new Label {Location = new Point(0, 1), Size = new Size(parent.Width, _lineHeight - 1)}\r
152                 };\r
153                 parent.Controls.AddRange(headings);\r
154                 foreach (var control in headings)\r
155                 {\r
156                     Scaler.Scale(control);\r
157                     control.BackColor = CustomColors.ColumnColors.Bright;\r
158                 }\r
159                 headings[0].Cursor = Cursors.Hand;\r
160                 hpDisplay.SetClickHandler(headings[0]);\r
161             }\r
162 \r
163             public void Set(IReadOnlyList<ShipStatus> ships)\r
164             {\r
165                 for (var i = 0; i < _shipLines.Length; i++)\r
166                 {\r
167                     var labels = _shipLines[i];\r
168                     if (i >= ships.Count)\r
169                     {\r
170                         labels.Reset();\r
171                         continue;\r
172                     }\r
173                     labels.Set(ships[i]);\r
174                 }\r
175             }\r
176 \r
177             public void SetAkashiTimer(IReadOnlyList<ShipStatus> ships, AkashiTimer.RepairSpan[] timers) =>\r
178                 _akashiTimerLabels.SetAkashiTimer(ships, timers);\r
179         }\r
180 \r
181         private class AkashiTimerLabels\r
182         {\r
183             private readonly ShipLabels[] _shipLines;\r
184             private readonly Label[] _timerLabels = new Label[ShipInfo.MemberCount];\r
185             private readonly int _lineHeight;\r
186             private int _originalLeft;\r
187 \r
188             public AkashiTimerLabels(int lineHeight, ShipLabels[] shipLabels)\r
189             {\r
190                 _shipLines = shipLabels;\r
191                 _lineHeight = lineHeight;\r
192             }\r
193 \r
194             public void Create(Control parent)\r
195             {\r
196                 const int x = 55;\r
197                 for (var i = 0; i < _timerLabels.Length; i++)\r
198                 {\r
199                     var y = 3 + _lineHeight * (i + 1);\r
200                     Label label;\r
201                     parent.Controls.Add(\r
202                         label = _timerLabels[i] =\r
203                             new Label\r
204                             {\r
205                                 Location = new Point(x, y),\r
206                                 AutoSize = true,\r
207                                 TextAlign = ContentAlignment.TopRight\r
208                             });\r
209                     label.BackColor = CustomColors.ColumnColors.DarkFirst(i);\r
210                 }\r
211                 foreach (var label in _timerLabels)\r
212                     Scaler.Scale(label);\r
213             }\r
214 \r
215             public void SetAkashiTimer(IReadOnlyList<ShipStatus> ships, AkashiTimer.RepairSpan[] timers)\r
216             {\r
217                 var shortest = ShortestSpanIndex(timers);\r
218                 for (var i = 0; i < _timerLabels.Length; i++)\r
219                 {\r
220                     var label = _timerLabels[i];\r
221                     var shipLabels = _shipLines[i];\r
222                     if (i >= timers.Length || timers[i].Span == TimeSpan.MinValue)\r
223                     {\r
224                         label.Visible = false;\r
225                         shipLabels.Hp.ForeColor = Control.DefaultForeColor;\r
226                         continue;\r
227                     }\r
228                     var timer = timers[i];\r
229                     var ship = ships[i];\r
230                     label.Visible = true;\r
231                     label.Text = timer.Span.ToString(@"mm\:ss");\r
232                     label.ForeColor = Control.DefaultForeColor;\r
233                     shipLabels.Name.SetName(ship, ShipNameWidth.AkashiTimer);\r
234                     if (timer.Diff == 0)\r
235                     {\r
236                         shipLabels.Hp.ForeColor = Control.DefaultForeColor;\r
237                     }\r
238                     else\r
239                     {\r
240                         if (i == shortest)\r
241                             label.ForeColor = CUDColors.Red;\r
242                         shipLabels.Hp.SetHp(ship.NowHp + timer.Diff, ship.MaxHp);\r
243                         shipLabels.Hp.ForeColor = Color.DimGray;\r
244                     }\r
245                     AdjustAkashiTimer(label, shipLabels.Hp);\r
246                 }\r
247             }\r
248 \r
249             private void AdjustAkashiTimer(Control timer, Control hp)\r
250             {\r
251                 if (_originalLeft == 0)\r
252                     _originalLeft = timer.Left;\r
253                 const int labelMargin = 3;\r
254                 var overlap = timer.Right - hp.Left - labelMargin;\r
255                 timer.Left = overlap < 0 ? _originalLeft : timer.Left - overlap;\r
256             }\r
257 \r
258             private static int ShortestSpanIndex(AkashiTimer.RepairSpan[] timers)\r
259             {\r
260                 var index = -1; // Spanが全部MinValueかZeroなら-1\r
261                 for (var i = 0; i < timers.Length; i++)\r
262                 {\r
263                     if (timers[i].Span <= TimeSpan.Zero)\r
264                         continue;\r
265                     if (index == -1 || timers[i].Span < timers[index].Span)\r
266                         index = i;\r
267                 }\r
268                 return index;\r
269             }\r
270         }\r
271 \r
272         private class CombinedShipLines\r
273         {\r
274             private readonly ShipLabels[] _combinedLines = new ShipLabels[ShipInfo.MemberCount * 2];\r
275 \r
276             private const int Top = 1;\r
277             private const int LineHeight = 16;\r
278             private const int ParentWidth = 220; // parent.Widthを使うとDPIスケーリング時に計算がくるうので\r
279 \r
280             public void Create(Control parent, HpDisplay hpDisplay, EventHandler onClick)\r
281             {\r
282                 parent.SuspendLayout();\r
283                 CreateHeader(parent, hpDisplay);\r
284                 for (var i = 0; i < _combinedLines.Length; i++)\r
285                 {\r
286                     var x = ParentWidth / 2 * (i / ShipInfo.MemberCount);\r
287                     var y = Top + LineHeight * (i % ShipInfo.MemberCount + 1);\r
288                     var labels = _combinedLines[i] = new ShipLabels\r
289                     {\r
290                         Name = new ShipLabel.Name(new Point(x + 2, y + 2), ShipNameWidth.Combined),\r
291                         Hp = new ShipLabel.Hp(new Point(x + 88, y), LineHeight),\r
292                         Cond = new ShipLabel.Cond(new Point(x + 85, y), LineHeight),\r
293                         BackGround = new Label {Location = new Point(x, y), Size = new Size(ParentWidth / 2, LineHeight)}\r
294                     };\r
295                     labels.Arrange(parent, CustomColors.ColumnColors.DarkFirst(i));\r
296                     labels.SetClickHandler(onClick);\r
297                     labels.SetTag(i);\r
298                     var hpLabel = _combinedLines[i].Hp;\r
299                     hpDisplay.AddHpLabel(hpLabel);\r
300                 }\r
301                 parent.ResumeLayout();\r
302             }\r
303 \r
304             private void CreateHeader(Control parent, HpDisplay hpDisplay)\r
305             {\r
306                 var headings = new Control[]\r
307                 {\r
308                     new Label {Location = new Point(68, Top), Text = "HP", AutoSize = true},\r
309                     new Label {Location = new Point(86, Top), Text = "cnd", AutoSize = true},\r
310                     new Label {Location = new Point(177, Top), Text = "HP", AutoSize = true},\r
311                     new Label {Location = new Point(195, Top), Text = "cnd", AutoSize = true},\r
312                     new Label {Location = new Point(0, 1), Size = new Size(ParentWidth, LineHeight - 1)}\r
313                 };\r
314                 parent.Controls.AddRange(headings);\r
315                 foreach (var control in headings)\r
316                 {\r
317                     Scaler.Scale(control);\r
318                     control.BackColor = CustomColors.ColumnColors.Bright;\r
319                 }\r
320                 headings[0].Cursor = headings[2].Cursor = Cursors.Hand;\r
321                 hpDisplay.SetClickHandler(headings[0]);\r
322                 hpDisplay.SetClickHandler(headings[2]);\r
323             }\r
324 \r
325             public void Set(IReadOnlyList<ShipStatus> first, IReadOnlyList<ShipStatus> second)\r
326             {\r
327                 for (var i = 0; i < _combinedLines.Length; i++)\r
328                 {\r
329                     var idx = i % ShipInfo.MemberCount;\r
330                     var ships = i < ShipInfo.MemberCount ? first : second;\r
331                     var labels = _combinedLines[i];\r
332                     if (idx >= ships.Count)\r
333                     {\r
334                         labels.Reset();\r
335                         continue;\r
336                     }\r
337                     labels.Set(ships[idx]);\r
338                 }\r
339             }\r
340         }\r
341     }\r
342 }