OSDN Git Service

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