OSDN Git Service

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