OSDN Git Service

一覧ウィンドウを複数開けるようにする
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / ListForm.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 KancolleSniffer.View;\r
21 using KancolleSniffer.View.ShipListPanel;\r
22 using Clipboard = KancolleSniffer.Util.Clipboard;\r
23 \r
24 namespace KancolleSniffer\r
25 {\r
26     public partial class ListForm : Form\r
27     {\r
28         private readonly Sniffer _sniffer;\r
29         private readonly Config _config;\r
30         private readonly MainForm _main;\r
31         private readonly MainForm.TimeOutChecker _suppressActivate;\r
32         private readonly CheckBox[] _shipTypeCheckBoxes;\r
33         private bool _isMaster;\r
34         public const int PanelWidth = 217;\r
35 \r
36         private object[] PanelNames => new object[] {"全艦", "A", "B", "C", "D", "分類", "修復", "装備", "艦隊", "対空", "戦況", "情報"}\r
37             .Where(n => IsMaster || (string)n != "分類").ToArray();\r
38 \r
39         private char[] PanelKeys => new[] {'Z', 'A', 'B', 'C', 'D', 'G', 'R', 'W', 'X', 'Y', 'S', 'I'}\r
40             .Where(key => IsMaster || key != 'G').ToArray();\r
41 \r
42         public bool IsMaster\r
43         {\r
44             get => _isMaster;\r
45             set\r
46             {\r
47                 _isMaster = value;\r
48                 Text = _isMaster ? "一覧 プライマリ" : "一覧";\r
49                 comboBoxGroup.Items.Clear();\r
50                 comboBoxGroup.Items.AddRange(PanelNames);\r
51             }\r
52         }\r
53 \r
54         public enum SortOrder\r
55         {\r
56             None,\r
57             Cond,\r
58             CondAscend = Cond,\r
59             CondDescend,\r
60             ExpToNext,\r
61             ExpToNextAscend = ExpToNext,\r
62             ExpToNextDescend,\r
63             Repair\r
64         }\r
65 \r
66         public ListForm(MainForm main)\r
67         {\r
68             InitializeComponent();\r
69             IsMaster = false;\r
70             _main = main;\r
71             _sniffer = main.Sniffer;\r
72             _config = main.Config;\r
73             _suppressActivate = main.SuppressActivate;\r
74             _shipTypeCheckBoxes = new[]\r
75             {\r
76                 checkBoxSTypeBattleShip,\r
77                 checkBoxSTypeAircraftCarrier,\r
78                 checkBoxSTypeHeavyCruiser,\r
79                 checkBoxSTypeLightCruiser,\r
80                 checkBoxSTypeDestroyer,\r
81                 checkBoxSTypeEscort,\r
82                 checkBoxSTypeSubmarine,\r
83                 checkBoxSTypeAuxiliary\r
84             };\r
85             battleResultPanel.HpLabelClick += ToggleHpPercent;\r
86             shipListPanel.HpLabelClick += ToggleHpPercent;\r
87             var swipe = new SwipeScrollify();\r
88             swipe.AddShipListPanel(shipListPanel);\r
89             swipe.AddTreeView(itemTreeView);\r
90             swipe.AddPanel(fleetPanel);\r
91         }\r
92 \r
93         public void UpdateList()\r
94         {\r
95             SetHeaderVisibility();\r
96             SetPanelVisibility();\r
97             if (InItemList)\r
98             {\r
99                 itemTreeView.SetNodes(_sniffer.ItemList);\r
100             }\r
101             else if (InFleetInfo)\r
102             {\r
103                 fleetPanel.Update(_sniffer);\r
104             }\r
105             else if (InAntiAir)\r
106             {\r
107                 antiAirPanel.Update(_sniffer);\r
108             }\r
109             else if (InMiscText)\r
110             {\r
111                 richTextBoxMiscText.Text = _sniffer.MiscText;\r
112             }\r
113             else if (InShipStatus || InGroupConfig || InRepairList)\r
114             {\r
115                 SetHeaderSortOrder();\r
116                 shipListPanel.Update(_sniffer, comboBoxGroup.Text, _config.ShipList);\r
117             }\r
118             if (shipListPanel.GroupUpdated)\r
119             {\r
120                 StoreShipGroupToConfig();\r
121                 _config.Save();\r
122                 shipListPanel.GroupUpdated = false;\r
123             }\r
124         }\r
125 \r
126         private void SetHeaderVisibility()\r
127         {\r
128             static void Set(Control header, bool visible)\r
129             {\r
130                 header.Visible = visible;\r
131                 if (visible)\r
132                     header.BringToFront();\r
133             }\r
134 \r
135             Set(panelItemHeader, InItemList || InAntiAir || InBattleResult || InMiscText);\r
136             Set(panelGroupHeader, InGroupConfig);\r
137             Set(panelRepairHeader, InRepairList);\r
138             Set(panelFleetHeader, InFleetInfo);\r
139         }\r
140 \r
141         private void SetPanelVisibility()\r
142         {\r
143             static void Set(Control panel, bool visible)\r
144             {\r
145                 // SwipeScrollifyが誤作動するのでEnabledも切り替える\r
146                 panel.Visible = panel.Enabled = visible;\r
147             }\r
148 \r
149             Set(shipListPanel, InShipStatus || InGroupConfig || InRepairList);\r
150             Set(itemTreeView, InItemList);\r
151             Set(fleetPanel, InFleetInfo);\r
152             Set(antiAirPanel, InAntiAir);\r
153             Set(airBattleResultPanel, InBattleResult);\r
154             Set(battleResultPanel, InBattleResult);\r
155             Set(richTextBoxMiscText, InMiscText);\r
156         }\r
157 \r
158         public void UpdateAirBattleResult()\r
159         {\r
160             airBattleResultPanel.ShowResultAutomatic = (_config.Spoilers & Spoiler.AirBattleResult) != 0;\r
161             airBattleResultPanel.SetResult(_sniffer);\r
162         }\r
163 \r
164         public void UpdateBattleResult()\r
165         {\r
166             MoveToBattleResult();\r
167             battleResultPanel.Spoilers = _config.Spoilers;\r
168             battleResultPanel.Update(_sniffer);\r
169             BackFromBattleResult();\r
170         }\r
171 \r
172         private int _prevSelectedIndex = -1;\r
173         private const int BattleResultIndex = 10;\r
174 \r
175         private void MoveToBattleResult()\r
176         {\r
177             if (!_config.ShipList.AutoBattleResult || comboBoxGroup.SelectedIndex == BattleResultIndex ||\r
178                 _sniffer.InSortie == -1)\r
179                 return;\r
180             _prevSelectedIndex = comboBoxGroup.SelectedIndex;\r
181             comboBoxGroup.SelectedIndex = BattleResultIndex;\r
182         }\r
183 \r
184         private void BackFromBattleResult()\r
185         {\r
186             if (_sniffer.InSortie != -1 || _prevSelectedIndex == -1)\r
187                 return;\r
188             comboBoxGroup.SelectedIndex = _prevSelectedIndex;\r
189             _prevSelectedIndex = -1;\r
190         }\r
191 \r
192         public void UpdateCellInfo()\r
193         {\r
194             battleResultPanel.Spoilers = _config.Spoilers;\r
195             battleResultPanel.UpdateCellInfo(_sniffer.CellInfo);\r
196         }\r
197 \r
198         private void SetHeaderSortOrder()\r
199         {\r
200             switch (_config.ShipList.SortOrder)\r
201             {\r
202                 case SortOrder.None:\r
203                     labelHeaderCond.Text = "cond";\r
204                     labelHeaderExp.Text = "Exp";\r
205                     break;\r
206                 case SortOrder.CondAscend:\r
207                     labelHeaderCond.Text = "cond▴";\r
208                     labelHeaderExp.Text = "Exp";\r
209                     break;\r
210                 case SortOrder.CondDescend:\r
211                     labelHeaderCond.Text = "cond▾";\r
212                     labelHeaderExp.Text = "Exp";\r
213                     break;\r
214                 case SortOrder.ExpToNextAscend:\r
215                     labelHeaderCond.Text = "cond";\r
216                     labelHeaderExp.Text = "Exp▴";\r
217                     break;\r
218                 case SortOrder.ExpToNextDescend:\r
219                     labelHeaderCond.Text = "cond";\r
220                     labelHeaderExp.Text = "Exp▾";\r
221                     break;\r
222             }\r
223         }\r
224 \r
225         private bool InShipStatus => Array.Exists(new[] {"全艦", "A", "B", "C", "D"}, x => comboBoxGroup.Text == x);\r
226 \r
227         private bool InGroupConfig => comboBoxGroup.Text == "分類";\r
228 \r
229         private bool InRepairList => comboBoxGroup.Text == "修復";\r
230 \r
231         private bool InItemList => comboBoxGroup.Text == "装備";\r
232 \r
233         private bool InFleetInfo => comboBoxGroup.Text == "艦隊";\r
234 \r
235         private bool InAntiAir => comboBoxGroup.Text == "対空";\r
236 \r
237         private bool InBattleResult => comboBoxGroup.Text == "戦況";\r
238 \r
239         private bool InMiscText => comboBoxGroup.Text == "情報";\r
240 \r
241         private void ListForm_Load(object sender, EventArgs e)\r
242         {\r
243             /* DPIではなくズームしたときにパネルは大きくなるがScrollBarはそのままなので隙間ができる。\r
244                そこでScrollBarの幅に合わせて全体の横幅を設定し直す。*/\r
245             Width = Scaler.ScaleWidth(PanelWidth + 12 /* PanelとFrameの内側 */) +\r
246                     SystemInformation.VerticalScrollBarWidth + 2 /* 縁の幅 */ + Width - ClientSize.Width;\r
247             MinimumSize = new Size(Width, 0);\r
248             MaximumSize = new Size(Width, int.MaxValue);\r
249             var config = GetConfig();\r
250             if (config.ShowHpInPercent)\r
251             {\r
252                 shipListPanel.ToggleHpPercent();\r
253                 battleResultPanel.ToggleHpPercent();\r
254             }\r
255             LoadShipGroupFromConfig();\r
256             comboBoxGroup.SelectedItem = config.Mode ?? "全艦";\r
257             SetCheckBoxSTypeState(config);\r
258             if (config.Location.X == int.MinValue)\r
259                 return;\r
260             var bounds = new Rectangle(config.Location, config.Size);\r
261             if (MainForm.IsTitleBarOnAnyScreen(bounds.Location))\r
262                 Location = bounds.Location;\r
263             Height = bounds.Height;\r
264         }\r
265 \r
266         private ShipListConfig GetConfig()\r
267         {\r
268             if (_isMaster || _config.ListFormGroup.Count == 0)\r
269                 return _config.ShipList;\r
270             var config = _config.ListFormGroup[0];\r
271             _config.ListFormGroup.RemoveAt(0);\r
272             if (config.Mode == "分類")\r
273                 config.Mode = "全艦";\r
274             return config;\r
275         }\r
276 \r
277         private void LoadShipGroupFromConfig()\r
278         {\r
279             var group = _config.ShipList.ShipGroup;\r
280             for (var i = 0; i < GroupConfigLabels.GroupCount; i++)\r
281                 shipListPanel.GroupSettings[i] = i < group.Count ? new HashSet<int>(group[i]) : new HashSet<int>();\r
282         }\r
283 \r
284         private void SetCheckBoxSTypeState(ShipListConfig config)\r
285         {\r
286             for (var type = 0; type < _shipTypeCheckBoxes.Length; type++)\r
287                 _shipTypeCheckBoxes[type].Checked = ((int)config.ShipCategories & (1 << type)) != 0;\r
288             checkBoxSTypeAll.Checked = config.ShipCategories == ShipCategory.All;\r
289             checkBoxSTypeDetails.Checked = config.ShipType;\r
290         }\r
291 \r
292         private void ListForm_FormClosing(object sender, FormClosingEventArgs e)\r
293         {\r
294             e.Cancel = true;\r
295             if (_isMaster)\r
296             {\r
297                 SaveMasterState();\r
298             }\r
299             else\r
300             {\r
301                 SaveSlaveState();\r
302             }\r
303             Hide();\r
304         }\r
305 \r
306         private void SaveMasterState()\r
307         {\r
308             StoreShipGroupToConfig();\r
309             var config = _config.ShipList;\r
310             config.Visible = Visible && WindowState == FormWindowState.Normal;\r
311             config.Mode = (string)comboBoxGroup.SelectedItem;\r
312             if (!Visible)\r
313                 return;\r
314             SaveBounds(config); // 最小化時は以前のサイズを記録する\r
315         }\r
316 \r
317         private void SaveSlaveState()\r
318         {\r
319             if (!Visible)\r
320                 return;\r
321             if (WindowState != FormWindowState.Normal) // 最小化時は次回復旧しない\r
322                 return;\r
323             var config = new ShipListConfig {Visible = true};\r
324             _config.ListFormGroup.Add(config);\r
325             config.Mode = (string)comboBoxGroup.SelectedItem;\r
326             SaveBounds(config);\r
327         }\r
328 \r
329         private void SaveBounds(ShipListConfig config)\r
330         {\r
331             var bounds = WindowState == FormWindowState.Normal ? Bounds : RestoreBounds;\r
332             config.Location = bounds.Location;\r
333             config.Size = bounds.Size;\r
334         }\r
335 \r
336         public void ChangeWindowState(FormWindowState newState)\r
337         {\r
338             if (!Visible)\r
339                 return;\r
340             if (newState == FormWindowState.Minimized)\r
341             {\r
342                 if (WindowState == FormWindowState.Normal)\r
343                     WindowState = FormWindowState.Minimized;\r
344                 if (_config.HideOnMinimized)\r
345                     ShowInTaskbar = false;\r
346             }\r
347             else\r
348             {\r
349                 if (WindowState == FormWindowState.Minimized)\r
350                 {\r
351                     Application.DoEvents();\r
352                     if (_config.HideOnMinimized)\r
353                         ShowInTaskbar = true;\r
354                     WindowState = FormWindowState.Normal;\r
355                 }\r
356             }\r
357         }\r
358 \r
359         private void ListForm_Activated(object sender, EventArgs e)\r
360         {\r
361             if (!_isMaster)\r
362                 return;\r
363             if (_suppressActivate.Check())\r
364                 return;\r
365             if (WindowState == FormWindowState.Minimized)\r
366                 return;\r
367             RaiseBothWindows();\r
368         }\r
369 \r
370         private void RaiseBothWindows()\r
371         {\r
372             _main.Owner = null;\r
373             Owner = _main;\r
374             BringToFront();\r
375             Owner = null;\r
376         }\r
377 \r
378         private void StoreShipGroupToConfig()\r
379         {\r
380             var all = _sniffer.ShipList.Select(s => s.Id).ToArray();\r
381             var group = _config.ShipList.ShipGroup;\r
382             group.Clear();\r
383             for (var i = 0; i < GroupConfigLabels.GroupCount; i++)\r
384             {\r
385                 if (all.Length > 0)\r
386                     shipListPanel.GroupSettings[i].IntersectWith(all);\r
387                 group.Add(shipListPanel.GroupSettings[i].ToList());\r
388             }\r
389         }\r
390 \r
391         public void ShowShip(int id)\r
392         {\r
393             if (InShipStatus)\r
394             {\r
395                 shipListPanel.ShowShip(id);\r
396             }\r
397             else if (InFleetInfo)\r
398             {\r
399                 fleetPanel.ShowShip(id);\r
400             }\r
401             else if (InAntiAir)\r
402             {\r
403                 antiAirPanel.ShowShip(id);\r
404             }\r
405         }\r
406 \r
407         private void comboBoxGroup_DropDownClosed(object sender, EventArgs e)\r
408         {\r
409             SetActiveControl();\r
410         }\r
411 \r
412         private void comboBoxGroup_SelectedIndexChanged(object sender, EventArgs e)\r
413         {\r
414             UpdateList();\r
415             SetActiveControl();\r
416             if (!(InShipStatus || InGroupConfig || InRepairList))\r
417                 SetPanelSTypeState(false);\r
418         }\r
419 \r
420         private void ListForm_KeyPress(object sender, KeyPressEventArgs e)\r
421         {\r
422             var g = Array.FindIndex(PanelKeys, x => x == char.ToUpper(e.KeyChar));\r
423             if (g == -1)\r
424                 return;\r
425             comboBoxGroup.SelectedIndex = g;\r
426             e.Handled = true;\r
427         }\r
428 \r
429         // マウスホイールでスクロールするためにコントロールにフォーカスを合わせる。\r
430         private void SetActiveControl()\r
431         {\r
432             if (InItemList)\r
433             {\r
434                 ActiveControl = itemTreeView;\r
435             }\r
436             else if (InFleetInfo)\r
437             {\r
438                 ActiveControl = fleetPanel;\r
439             }\r
440             else if (InAntiAir)\r
441             {\r
442                 ActiveControl = antiAirPanel;\r
443             }\r
444             else\r
445             {\r
446                 ActiveControl = shipListPanel;\r
447             }\r
448         }\r
449 \r
450         private void itemCsvToolStripMenuItem_Click(object sender, EventArgs e)\r
451         {\r
452             Clipboard.SetText(TextGenerator.GenerateItemList(_sniffer.ItemList));\r
453         }\r
454 \r
455         private void kantaiBunsekiToolStripMenuItem_Click(object sender, EventArgs e)\r
456         {\r
457             Clipboard.SetText(TextGenerator.GenerateKantaiBunsekiItemList(_sniffer.ItemList));\r
458         }\r
459 \r
460         private void fleetTextToolStripMenuItem_Click(object sender, EventArgs e)\r
461         {\r
462             Clipboard.SetText(TextGenerator.GenerateFleetData(_sniffer));\r
463         }\r
464 \r
465         private void deckBuilderToolStripMenuItem_Click(object sender, EventArgs e)\r
466         {\r
467             Clipboard.SetText(TextGenerator.GenerateDeckBuilderData(_sniffer));\r
468         }\r
469 \r
470         private void labelHeaderCond_Click(object sender, EventArgs e)\r
471         {\r
472             var sl = _config.ShipList;\r
473             switch (sl.SortOrder)\r
474             {\r
475                 case SortOrder.CondAscend:\r
476                     sl.SortOrder = SortOrder.CondDescend;\r
477                     break;\r
478                 case SortOrder.CondDescend:\r
479                     sl.SortOrder = SortOrder.None;\r
480                     break;\r
481                 default:\r
482                     sl.SortOrder = SortOrder.CondAscend;\r
483                     break;\r
484             }\r
485             UpdateList();\r
486         }\r
487 \r
488         private void labelHeaderExp_Click(object sender, EventArgs e)\r
489         {\r
490             var sl = _config.ShipList;\r
491             switch (sl.SortOrder)\r
492             {\r
493                 case SortOrder.ExpToNextAscend:\r
494                     sl.SortOrder = SortOrder.ExpToNextDescend;\r
495                     break;\r
496                 case SortOrder.ExpToNextDescend:\r
497                     sl.SortOrder = SortOrder.None;\r
498                     break;\r
499                 default:\r
500                     sl.SortOrder = SortOrder.ExpToNextAscend;\r
501                     break;\r
502             }\r
503             UpdateList();\r
504         }\r
505 \r
506         private void shipCsvToolStripMenuItem_Click(object sender, EventArgs e)\r
507         {\r
508             Clipboard.SetText(TextGenerator.GenerateShipList(shipListPanel.CurrentShipList));\r
509         }\r
510 \r
511         private void kantaiSarashiToolStripMenuItem_Click(object sender, EventArgs e)\r
512         {\r
513             Clipboard.SetText(TextGenerator.GenerateKantaiSarashiData(shipListPanel.CurrentShipList));\r
514         }\r
515 \r
516         private void labelFleet_Click(object sender, EventArgs e)\r
517         {\r
518             fleetPanel.ShowFleet(((Label)sender).Text);\r
519         }\r
520 \r
521         private void labelHeaderHp_Click(object sender, EventArgs e)\r
522         {\r
523             ToggleHpPercent();\r
524         }\r
525 \r
526         private void ToggleHpPercent()\r
527         {\r
528             _config.ShipList.ShowHpInPercent = !_config.ShipList.ShowHpInPercent;\r
529             shipListPanel.ToggleHpPercent();\r
530             battleResultPanel.ToggleHpPercent();\r
531         }\r
532 \r
533         private void labelSTypeButton_Click(object sender, EventArgs e)\r
534         {\r
535             SetPanelSTypeState(!panelSType.Visible);\r
536         }\r
537 \r
538         private void checkBoxSType_Click(object sender, EventArgs e)\r
539         {\r
540             _config.ShipList.ShipCategories = SelectedShipTypes;\r
541             UpdateList();\r
542             SetActiveControl();\r
543         }\r
544 \r
545         private ShipCategory SelectedShipTypes =>\r
546             (ShipCategory)_shipTypeCheckBoxes.Select((cb, type) => cb.Checked ? 1 << type : 0).Sum();\r
547 \r
548         private void checkBoxSTypeAll_Click(object sender, EventArgs e)\r
549         {\r
550             foreach (var checkBox in _shipTypeCheckBoxes)\r
551                 checkBox.Checked = checkBoxSTypeAll.Checked;\r
552             checkBoxSType_Click(sender, e);\r
553         }\r
554 \r
555         private void panelSType_Click(object sender, EventArgs e)\r
556         {\r
557             SetPanelSTypeState(false);\r
558         }\r
559 \r
560         private void SetPanelSTypeState(bool visible)\r
561         {\r
562             panelSType.Visible = visible;\r
563             if (visible)\r
564                 panelSType.BringToFront();\r
565             labelSTypeButton.BackColor = visible ? CustomColors.ActiveButtonColor : DefaultBackColor;\r
566         }\r
567 \r
568         private void checkBoxSTypeDetails_Click(object sender, EventArgs e)\r
569         {\r
570             _config.ShipList.ShipType = checkBoxSTypeDetails.Checked;\r
571             UpdateList();\r
572             SetActiveControl();\r
573         }\r
574     }\r
575 }