OSDN Git Service

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