OSDN Git Service

艦隊ごとの装備一覧をShipListFormから分離する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / ShipListForm.cs
1 // Copyright (C) 2014, 2015 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\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.Collections.Generic;\r
20 using System.Drawing;\r
21 using System.Linq;\r
22 using System.Windows.Forms;\r
23 \r
24 namespace KancolleSniffer\r
25 {\r
26     public partial class ShipListForm : Form\r
27     {\r
28         private readonly Sniffer _sniffer;\r
29         private readonly Config _config;\r
30         private const int LabelHeight = 12;\r
31         private const int LineHeight = 16;\r
32         public const int PanelWidth = 217;\r
33         private ShipStatus[] _shipList;\r
34         private readonly List<ShipLabel[]> _labelList = new List<ShipLabel[]>();\r
35         private readonly List<Panel> _labelPanelList = new List<Panel>();\r
36         private readonly List<CheckBox[]> _checkBoxesList = new List<CheckBox[]>();\r
37         private readonly List<ShipLabel[]> _configLabelList = new List<ShipLabel[]>();\r
38         private readonly List<Panel> _checkBoxPanelList = new List<Panel>();\r
39         private readonly List<ShipLabel[]> _repairLabelList = new List<ShipLabel[]>();\r
40         private readonly List<Panel> _repairPanelList = new List<Panel>();\r
41         public const int GroupCount = 4;\r
42         private readonly HashSet<int>[] _groupSettings = new HashSet<int>[GroupCount];\r
43 \r
44         public ShipListForm(Sniffer sniffer, Config config)\r
45         {\r
46             InitializeComponent();\r
47             _sniffer = sniffer;\r
48             _config = config;\r
49         }\r
50 \r
51         public void UpdateList()\r
52         {\r
53             panelItemHeader.Visible = InItemList() || InEquip();\r
54             itemTreeView.Visible = InItemList();\r
55             equipPanel.Visible = InEquip();\r
56             if (InItemList())\r
57             {\r
58                 HideShipLabels();\r
59                 itemTreeView.SetNodes(_sniffer.ItemList);\r
60             }\r
61             else if (InEquip())\r
62             {\r
63                 HideShipLabels();\r
64                 equipPanel.UpdateEquip(_sniffer);\r
65             }\r
66             else\r
67             {\r
68                 CreateShipList();\r
69                 CreateListLabels();\r
70                 SetShipLabels();\r
71             }\r
72         }\r
73 \r
74         private void CreateShipList()\r
75         {\r
76             var ships = InRepairList() ? _sniffer.DamagedShipList : FilterByGroup(_sniffer.ShipList).ToArray();\r
77             if (!_config.ShipList.ShipType)\r
78             {\r
79                 _shipList = ships.OrderBy(s => s, new CompareShip(false, InRepairList())).ToArray();\r
80                 return;\r
81             }\r
82             var types = ships.Select(s => new {Id = s.Spec.ShipType, Name = s.Spec.ShipTypeName}).Distinct().\r
83                 Select(stype =>\r
84                     new ShipStatus\r
85                     {\r
86                         Spec = new ShipSpec {Name = stype.Name, ShipType = stype.Id},\r
87                         Level = 1000,\r
88                         NowHp = -1000\r
89                     });\r
90             _shipList = ships.Concat(types).OrderBy(s => s, new CompareShip(true, InRepairList())).ToArray();\r
91         }\r
92 \r
93         private IEnumerable<ShipStatus> FilterByGroup(IEnumerable<ShipStatus> ships)\r
94         {\r
95             var g = Array.FindIndex(new[] {"A", "B", "C", "D"}, x => x == comboBoxGroup.Text);\r
96             if (g == -1)\r
97                 return ships;\r
98             return from s in ships where _groupSettings[g].Contains(s.Id) select s;\r
99         }\r
100 \r
101         private class CompareShip : IComparer<ShipStatus>\r
102         {\r
103             private readonly bool _type;\r
104             private readonly bool _repair;\r
105 \r
106             public CompareShip(bool type, bool repair)\r
107             {\r
108                 _type = type;\r
109                 _repair = repair;\r
110             }\r
111 \r
112             public int Compare(ShipStatus a, ShipStatus b)\r
113             {\r
114                 if (_type && a.Spec.ShipType != b.Spec.ShipType)\r
115                     return a.Spec.ShipType - b.Spec.ShipType;\r
116                 if (_repair && a.RepairTime != b.RepairTime)\r
117                     return (int)(b.RepairTime - a.RepairTime).TotalSeconds;\r
118                 if (a.Level != b.Level)\r
119                     return b.Level - a.Level;\r
120                 if (a.ExpToNext != b.ExpToNext)\r
121                     return a.ExpToNext - b.ExpToNext;\r
122                 return a.Spec.Id - b.Spec.Id;\r
123             }\r
124         }\r
125 \r
126         private void CreateListLabels()\r
127         {\r
128             panelShipList.SuspendLayout();\r
129             for (var i = _labelList.Count; i < _shipList.Length; i++)\r
130             {\r
131                 CreateConfigComponents(i);\r
132                 CreateRepairLabels(i);\r
133                 CreateShipLabels(i);\r
134             }\r
135             panelShipList.ResumeLayout();\r
136         }\r
137 \r
138         private void CreateConfigComponents(int i)\r
139         {\r
140             var y = 3 + LineHeight * i;\r
141             var cfgp = new Panel\r
142             {\r
143                 Location = new Point(0, y - 2),\r
144                 Size = new Size(PanelWidth, LineHeight - 1),\r
145                 BackColor = ShipLabels.ColumnColors[(i + 1) % 2],\r
146                 Visible = false\r
147             };\r
148             cfgp.Scale(ShipLabel.ScaleFactor);\r
149             cfgp.Tag = cfgp.Location.Y;\r
150             var cfgl = new[]\r
151             {\r
152                 new ShipLabel\r
153                 {\r
154                     Location = new Point(91, 2),\r
155                     Size = new Size(23, LabelHeight),\r
156                     TextAlign = ContentAlignment.MiddleRight,\r
157                 },\r
158                 new ShipLabel {Location = new Point(10, 2), AutoSize = true},\r
159                 new ShipLabel {Location = new Point(1, 2), AutoSize = true}\r
160             };\r
161 \r
162             var cb = new CheckBox[GroupCount];\r
163             for (var j = 0; j < cb.Length; j++)\r
164             {\r
165                 cb[j] = new CheckBox\r
166                 {\r
167                     Location = new Point(125 + j * 24, 2),\r
168                     FlatStyle = FlatStyle.Flat,\r
169                     Size = new Size(12, 11),\r
170                     Tag = i * 10 + j\r
171                 };\r
172                 cb[j].Scale(ShipLabel.ScaleFactor);\r
173                 cb[j].CheckedChanged += checkboxGroup_CheckedChanged;\r
174             }\r
175             _configLabelList.Add(cfgl);\r
176             _checkBoxesList.Add(cb);\r
177             _checkBoxPanelList.Add(cfgp);\r
178             // ReSharper disable CoVariantArrayConversion\r
179             cfgp.Controls.AddRange(cfgl);\r
180             cfgp.Controls.AddRange(cb);\r
181             // ReSharper restore CoVariantArrayConversion\r
182             panelShipList.Controls.Add(cfgp);\r
183             foreach (var label in cfgl)\r
184             {\r
185                 label.Scale();\r
186                 label.PresetColor =\r
187                     label.BackColor = ShipLabels.ColumnColors[(i + 1) % 2];\r
188             }\r
189         }\r
190 \r
191         private void CreateRepairLabels(int i)\r
192         {\r
193             var y = 3 + LineHeight * i;\r
194             const int height = LabelHeight;\r
195             var rpp = new Panel\r
196             {\r
197                 Location = new Point(0, y - 2),\r
198                 Size = new Size(PanelWidth, LineHeight - 1),\r
199                 BackColor = ShipLabels.ColumnColors[(i + 1) % 2],\r
200                 Visible = false\r
201             };\r
202             rpp.Scale(ShipLabel.ScaleFactor);\r
203             rpp.Tag = rpp.Location.Y;\r
204             var rpl = new[]\r
205             {\r
206                 new ShipLabel {Location = new Point(118, 2), AutoSize = true, AnchorRight = true},\r
207                 new ShipLabel\r
208                 {\r
209                     Location = new Point(117, 2),\r
210                     Size = new Size(23, height),\r
211                     TextAlign = ContentAlignment.MiddleRight\r
212                 },\r
213                 new ShipLabel {Location = new Point(141, 2), AutoSize = true},\r
214                 new ShipLabel {Location = new Point(186, 2), AutoSize = true},\r
215                 new ShipLabel {Location = new Point(10, 2), AutoSize = true},\r
216                 new ShipLabel {Location = new Point(1, 2), AutoSize = true}\r
217             };\r
218             _repairLabelList.Add(rpl);\r
219             _repairPanelList.Add(rpp);\r
220 // ReSharper disable once CoVariantArrayConversion\r
221             rpp.Controls.AddRange(rpl);\r
222             panelShipList.Controls.Add(rpp);\r
223             foreach (var label in rpl)\r
224             {\r
225                 label.Scale();\r
226                 label.PresetColor =\r
227                     label.BackColor = ShipLabels.ColumnColors[(i + 1) % 2];\r
228             }\r
229         }\r
230 \r
231         private void CreateShipLabels(int i)\r
232         {\r
233             var y = 3 + LineHeight * i;\r
234             const int height = LabelHeight;\r
235             var lbp = new Panel\r
236             {\r
237                 Location = new Point(0, y - 2),\r
238                 Size = new Size(PanelWidth, LineHeight - 1),\r
239                 BackColor = ShipLabels.ColumnColors[(i + 1) % 2],\r
240                 Visible = false\r
241             };\r
242             lbp.Scale(ShipLabel.ScaleFactor);\r
243             lbp.Tag = lbp.Location.Y;\r
244             var labels = new[]\r
245             {\r
246                 new ShipLabel {Location = new Point(126, 2), AutoSize = true, AnchorRight = true},\r
247                 new ShipLabel\r
248                 {\r
249                     Location = new Point(129, 2),\r
250                     Size = new Size(23, height),\r
251                     TextAlign = ContentAlignment.MiddleRight\r
252                 },\r
253                 new ShipLabel\r
254                 {\r
255                     Location = new Point(155, 2),\r
256                     Size = new Size(23, height),\r
257                     TextAlign = ContentAlignment.MiddleRight\r
258                 },\r
259                 new ShipLabel\r
260                 {\r
261                     Location = new Point(176, 2),\r
262                     Size = new Size(41, height),\r
263                     TextAlign = ContentAlignment.MiddleRight\r
264                 },\r
265                 new ShipLabel {Location = new Point(10, 2), AutoSize = true},\r
266                 new ShipLabel {Location = new Point(1, 2), AutoSize = true}\r
267             };\r
268             _labelList.Add(labels);\r
269             _labelPanelList.Add(lbp);\r
270 // ReSharper disable once CoVariantArrayConversion\r
271             lbp.Controls.AddRange(labels);\r
272             panelShipList.Controls.Add(lbp);\r
273             foreach (var label in labels)\r
274             {\r
275                 label.Scale();\r
276                 label.PresetColor =\r
277                     label.BackColor = ShipLabels.ColumnColors[(i + 1) % 2];\r
278             }\r
279         }\r
280 \r
281         private void SetShipLabels()\r
282         {\r
283             panelGroupHeader.Visible = InGroupConfig();\r
284             panelRepairHeader.Visible = InRepairList();\r
285             panelShipList.SuspendLayout();\r
286             for (var i = 0; i < _shipList.Length; i++)\r
287             {\r
288                 if (!InShipStatus())\r
289                     _labelPanelList[i].Visible = false;\r
290                 if (!InGroupConfig())\r
291                     _checkBoxPanelList[i].Visible = false;\r
292                 if (!InRepairList())\r
293                     _repairPanelList[i].Visible = false;\r
294             }\r
295             for (var i = 0; i < _shipList.Length; i++)\r
296             {\r
297                 if (InShipStatus())\r
298                     SetShipStatus(i);\r
299                 if (InGroupConfig())\r
300                     SetGroupConfig(i);\r
301                 if (InRepairList())\r
302                     SetRepairList(i);\r
303             }\r
304             for (var i = _shipList.Length; i < _labelPanelList.Count; i++)\r
305             {\r
306                 _labelPanelList[i].Visible = _checkBoxPanelList[i].Visible = _repairPanelList[i].Visible;\r
307             }\r
308             panelShipList.ResumeLayout();\r
309         }\r
310 \r
311         private void SetShipStatus(int i)\r
312         {\r
313             var lbp = _labelPanelList[i];\r
314             if (!lbp.Visible)\r
315                 lbp.Location = new Point(lbp.Left, (int)lbp.Tag + panelShipList.AutoScrollPosition.Y);\r
316             var s = _shipList[i];\r
317             var labels = _labelList[i];\r
318             if (s.Level == 1000) // 艦種の表示\r
319             {\r
320                 SetShipType(i);\r
321                 return;\r
322             }\r
323             labels[0].SetHp(s);\r
324             labels[1].SetCond(s);\r
325             labels[2].SetLevel(s);\r
326             labels[3].SetExpToNext(s);\r
327             labels[4].SetName(s);\r
328             labels[5].SetFleet(s);\r
329             lbp.Visible = true;\r
330         }\r
331 \r
332         private void SetShipType(int i)\r
333         {\r
334             var lbp = _labelPanelList[i];\r
335             if (!lbp.Visible)\r
336                 lbp.Location = new Point(lbp.Left, (int)lbp.Tag + panelShipList.AutoScrollPosition.Y);\r
337             var s = _shipList[i];\r
338             var labels = _labelList[i];\r
339             for (var c = 0; c < 4; c++)\r
340             {\r
341                 labels[c].Text = "";\r
342                 labels[c].BackColor = labels[c].PresetColor;\r
343             }\r
344             labels[4].SetName("");\r
345             labels[5].Text = s.Name;\r
346             lbp.Visible = true;\r
347         }\r
348 \r
349         private void SetGroupConfig(int i)\r
350         {\r
351             var cbp = _checkBoxPanelList[i];\r
352             var s = _shipList[i];\r
353             if (s.Level == 1000)\r
354             {\r
355                 SetShipType(i);\r
356                 return;\r
357             }\r
358             if (!cbp.Visible)\r
359                 cbp.Location = new Point(cbp.Left, (int)cbp.Tag + panelShipList.AutoScrollPosition.Y);\r
360             var cfgl = _configLabelList[i];\r
361             cfgl[0].SetLevel(s);\r
362             cfgl[1].SetName(s);\r
363             cfgl[2].SetFleet(s);\r
364             var cb = _checkBoxesList[i];\r
365             for (var j = 0; j < cb.Length; j++)\r
366                 cb[j].Checked = _groupSettings[j].Contains(s.Id);\r
367             cbp.Visible = true;\r
368         }\r
369 \r
370         private void SetRepairList(int i)\r
371         {\r
372             var rpp = _repairPanelList[i];\r
373             var s = _shipList[i];\r
374             if (s.Level == 1000)\r
375             {\r
376                 SetShipType(i);\r
377                 return;\r
378             }\r
379             if (!rpp.Visible)\r
380                 rpp.Location = new Point(rpp.Left, (int)rpp.Tag + panelShipList.AutoScrollPosition.Y);\r
381             var rpl = _repairLabelList[i];\r
382             rpl[0].SetHp(s);\r
383             rpl[1].SetLevel(s);\r
384             rpl[2].SetRepairTime(s);\r
385             rpl[3].Text = TimeSpan.FromSeconds(s.RepairSecPerHp).ToString(@"mm\:ss");\r
386             rpl[4].SetName(s);\r
387             rpl[5].SetFleet(s);\r
388             rpp.Visible = true;\r
389         }\r
390 \r
391         private void HideShipLabels()\r
392         {\r
393             panelShipList.SuspendLayout();\r
394             for (var i = 0; i < _labelPanelList.Count; i++)\r
395                 _labelPanelList[i].Visible = _checkBoxPanelList[i].Visible = _repairPanelList[i].Visible = false;\r
396             panelShipList.ResumeLayout();\r
397         }\r
398 \r
399         private bool InShipStatus()\r
400         {\r
401             return Array.Exists(new[] {"全員", "A", "B", "C", "D"}, x => comboBoxGroup.Text == x);\r
402         }\r
403 \r
404         private bool InGroupConfig()\r
405         {\r
406             return comboBoxGroup.Text == "分類";\r
407         }\r
408 \r
409         private bool InRepairList()\r
410         {\r
411             return comboBoxGroup.Text == "修復";\r
412         }\r
413 \r
414         private bool InItemList()\r
415         {\r
416             return comboBoxGroup.Text == "装備";\r
417         }\r
418 \r
419         private bool InEquip()\r
420         {\r
421             return comboBoxGroup.Text == "艦隊";\r
422         }\r
423 \r
424         private void ShipListForm_Load(object sender, EventArgs e)\r
425         {\r
426             panelShipList.Width = (int)Math.Round(PanelWidth * ShipLabel.ScaleFactor.Width) + 3 +\r
427                                   SystemInformation.VerticalScrollBarWidth;\r
428             Width = panelShipList.Width + 12 + (Width - ClientSize.Width);\r
429             MinimumSize = new Size(Width, 0);\r
430             MaximumSize = new Size(Width, int.MaxValue);\r
431             var config = _config.ShipList;\r
432             checkBoxShipType.Checked = config.ShipType;\r
433             ActiveControl = panelShipList;\r
434             for (var i = 0; i < GroupCount; i++)\r
435                 _groupSettings[i] = new HashSet<int>(config.ShipGroup[i]);\r
436             comboBoxGroup.SelectedIndex = 0;\r
437             if (config.Location.X == int.MinValue)\r
438                 return;\r
439             var bounds = new Rectangle(config.Location, config.Size);\r
440             if (MainForm.IsVisibleOnAnyScreen(bounds))\r
441                 Location = bounds.Location;\r
442             Height = bounds.Height;\r
443         }\r
444 \r
445         private void ShipListForm_FormClosing(object sender, FormClosingEventArgs e)\r
446         {\r
447             var config = _config.ShipList;\r
448             var all = _sniffer.ShipList.Select(s => s.Id).ToArray();\r
449             for (var i = 0; i < GroupCount; i++)\r
450             {\r
451                 if (_groupSettings[i] == null)\r
452                     break;\r
453                 if (all.Count() > 0)\r
454                     _groupSettings[i].IntersectWith(all);\r
455                 config.ShipGroup[i] = _groupSettings[i].ToList();\r
456             }\r
457             e.Cancel = true;\r
458             if (!Visible)\r
459                 return;\r
460             var bounds = WindowState == FormWindowState.Normal ? Bounds : RestoreBounds;\r
461             config.Location = bounds.Location;\r
462             config.Size = bounds.Size;\r
463             Hide();\r
464         }\r
465 \r
466         public void ShowShip(int id)\r
467         {\r
468             if (InShipStatus())\r
469             {\r
470                 var i = Array.FindIndex(_shipList, s => s.Id == id);\r
471                 if (i == -1)\r
472                     return;\r
473                 var y = (int)Math.Round(ShipLabel.ScaleFactor.Height * LineHeight * i);\r
474                 panelShipList.AutoScrollPosition = new Point(0, y);\r
475             }\r
476             else if (InEquip())\r
477             {\r
478                 equipPanel.ShowShip(id);\r
479             }\r
480         }\r
481 \r
482         private void checkBoxShipType_CheckedChanged(object sender, EventArgs e)\r
483         {\r
484             _config.ShipList.ShipType = checkBoxShipType.Checked;\r
485             UpdateList();\r
486             SetActiveControl();\r
487         }\r
488 \r
489         private void checkboxGroup_CheckedChanged(object sender, EventArgs e)\r
490         {\r
491             var cb = (CheckBox)sender;\r
492             var group = (int)cb.Tag % 10;\r
493             var idx = (int)cb.Tag / 10;\r
494             if (cb.Checked)\r
495                 _groupSettings[group].Add(_shipList[idx].Id);\r
496             else\r
497                 _groupSettings[group].Remove(_shipList[idx].Id);\r
498         }\r
499 \r
500         private void comboBoxGroup_SelectedIndexChanged(object sender, EventArgs e)\r
501         {\r
502             UpdateList();\r
503             SetActiveControl();\r
504         }\r
505 \r
506         private void ShipListForm_KeyPress(object sender, KeyPressEventArgs e)\r
507         {\r
508             var g = Array.FindIndex(new[] {'Z', 'A', 'B', 'C', 'D', 'G', 'R', 'W', 'X'},\r
509                 x => x == char.ToUpper(e.KeyChar));\r
510             if (g == -1)\r
511                 return;\r
512             comboBoxGroup.SelectedIndex = g;\r
513             e.Handled = true;\r
514         }\r
515 \r
516         // マウスホイールでスクロールするためにコントロールにフォーカスを合わせる。\r
517         private void SetActiveControl()\r
518         {\r
519             if (InItemList())\r
520                 ActiveControl = itemTreeView;\r
521             else if (InEquip())\r
522                 ActiveControl = equipPanel;\r
523             else\r
524                 ActiveControl = panelShipList;\r
525         }\r
526     }\r
527 }