OSDN Git Service

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