OSDN Git Service

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