OSDN Git Service

Settingsクラスを廃止する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / View / ShipListPanel / ShipListPanel.cs
1 // Copyright (C) 2016 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.Linq;\r
18 using System.Runtime.InteropServices;\r
19 using System.Windows.Forms;\r
20 using KancolleSniffer.Forms;\r
21 using KancolleSniffer.Model;\r
22 using KancolleSniffer.View.ListWindow;\r
23 using static System.Math;\r
24 \r
25 namespace KancolleSniffer.View.ShipListPanel\r
26 {\r
27     public class ShipListPanel : Panel, IPanelResize\r
28     {\r
29         public const int LabelHeight = 12;\r
30         public const int LineHeight = 16;\r
31         private ShipStatus[] _shipList;\r
32         private readonly List<ShipLabel.Hp> _hpLabels = new List<ShipLabel.Hp>();\r
33         private readonly ShipListLabels _shipListLabels;\r
34         private readonly GroupConfigLabels _groupConfigLabels;\r
35         private readonly RepairListLabels _repairListLabels;\r
36         private int _labelCount;\r
37         private string _mode;\r
38         private bool _hpPercent;\r
39 \r
40         public HashSet<int>[] GroupSettings => _groupConfigLabels.GroupSettings;\r
41 \r
42         public bool GroupUpdated\r
43         {\r
44             get => _groupConfigLabels.GroupUpdated;\r
45             set => _groupConfigLabels.GroupUpdated = value;\r
46         }\r
47 \r
48         public ScrollBar ScrollBar { get; }\r
49 \r
50         public ShipStatus GetShip(int i)\r
51         {\r
52             return _shipList[i + ScrollBar.Value];\r
53         }\r
54 \r
55         public ShipListPanel()\r
56         {\r
57             ScrollBar = new VScrollBar {Dock = DockStyle.Right, Visible = false};\r
58             ScrollBar.ValueChanged += ScrollBarOnValueChanged;\r
59             Controls.Add(ScrollBar);\r
60             _shipListLabels = new ShipListLabels(this);\r
61             _groupConfigLabels = new GroupConfigLabels(this);\r
62             _repairListLabels = new RepairListLabels(this);\r
63         }\r
64 \r
65         private void ScrollBarOnValueChanged(object sender, EventArgs eventArgs)\r
66         {\r
67             SuspendDrawing();\r
68             SetShipLabels();\r
69             ResumeDrawing();\r
70         }\r
71 \r
72         public void ApplyResize()\r
73         {\r
74             if (_shipList == null || _shipList.Length == 0 || !Visible)\r
75                 return;\r
76             SuspendDrawing();\r
77             SetupLabels();\r
78             ResizeLabels();\r
79             SetShipLabels();\r
80             ResumeDrawing();\r
81         }\r
82 \r
83         protected override void OnMouseWheel(MouseEventArgs e)\r
84         {\r
85             if (!ScrollBar.Visible)\r
86                 return;\r
87             ScrollBar.Value = Max(ScrollBar.Minimum, Min(ScrollBar.Maximum - ScrollBar.LargeChange + 1,\r
88                 ScrollBar.Value - e.Delta * SystemInformation.MouseWheelScrollLines / 120));\r
89         }\r
90 \r
91         public void Update(Sniffer sniffer, string mode, ShipListConfig settings)\r
92         {\r
93             _mode = mode;\r
94             CreateShipList(sniffer, settings);\r
95             SuspendDrawing();\r
96             SetupLabels();\r
97             ResizeLabels();\r
98             SetShipLabels();\r
99             ResumeDrawing();\r
100         }\r
101 \r
102         [DllImport("user32.dll")]\r
103         private static extern int SendMessage(IntPtr hWnd, int wMsg, bool wParam, IntPtr lParam);\r
104 \r
105         private void SuspendDrawing()\r
106         {\r
107             SendMessage(Handle, 11, false, IntPtr.Zero); // WM_SETREDRAW = 11\r
108             SuspendLayout();\r
109         }\r
110 \r
111         private void ResumeDrawing()\r
112         {\r
113             ResumeLayout();\r
114             SendMessage(Handle, 11, true, IntPtr.Zero);\r
115             Refresh();\r
116         }\r
117 \r
118         private void CreateShipList(Sniffer sniffer, ShipListConfig settings)\r
119         {\r
120             var ships = FilterByShipTypes(\r
121                 _mode == "修復" ? sniffer.RepairList : _groupConfigLabels.FilterByGroup(sniffer.ShipList, _mode),\r
122                 settings.ShipCategories).ToArray();\r
123             var order = _mode == "修復" ? ListForm.SortOrder.Repair : settings.SortOrder;\r
124             if (!settings.ShipType)\r
125             {\r
126                 _shipList = ships.OrderBy(s => s, new CompareShip(false, order)).ToArray();\r
127                 return;\r
128             }\r
129             _shipList = ships.Select(ship => new {Id = ship.Spec.ShipType, Name = ship.Spec.ShipTypeName})\r
130                 .Distinct().Select(type => new ShipStatus\r
131                 {\r
132                     Spec = new ShipSpec {Name = type.Name, ShipType = type.Id},\r
133                     Level = 1000\r
134                 }).Concat(ships).OrderBy(ship => ship, new CompareShip(true, order)).ToArray();\r
135         }\r
136 \r
137         private static readonly int[][] ShipTypeIds =\r
138         {\r
139             new[] // 戦艦\r
140             {\r
141                 8, // 巡洋戦艦\r
142                 9, // 戦艦\r
143                 10 // 航空戦艦\r
144             },\r
145             new[] // 空母\r
146             {\r
147                 18, // 装甲空母\r
148                 11, // 正規空母\r
149                 7 // 軽空母\r
150             },\r
151             new[] // 重巡\r
152             {\r
153                 5, // 重巡洋艦\r
154                 6 // 航空巡洋艦\r
155             },\r
156             new[] // 軽巡\r
157             {\r
158                 3, // 軽巡洋艦\r
159                 4, // 重雷装巡洋艦\r
160                 21 // 練習巡洋艦\r
161             },\r
162             new[] // 駆逐\r
163             {\r
164                 2 // 駆逐艦\r
165             },\r
166             new[] // 海防\r
167             {\r
168                 1 // 海防艦\r
169             },\r
170             new[] // 潜水\r
171             {\r
172                 13, // 潜水艦\r
173                 14 // 潜水空母\r
174             },\r
175             new[] // 補助\r
176             {\r
177                 16, // 水上機母艦\r
178                 17, // 揚陸艦\r
179                 19, // 工作艦\r
180                 20, // 潜水母艦\r
181                 22 // 補給艦\r
182             }\r
183         };\r
184 \r
185         private static readonly int[] ShipTypeSortIds = CreateShipTypeSortIds();\r
186 \r
187         private static int[] CreateShipTypeSortIds()\r
188         {\r
189             var ids = ShipTypeIds.SelectMany(x => x).ToArray();\r
190             var res = new int[ids.Max() + 1];\r
191             for (var i = 0; i < ids.Length; i++)\r
192                 res[ids[i]] = i;\r
193             return res;\r
194         }\r
195 \r
196         private static IEnumerable<ShipStatus> FilterByShipTypes(IEnumerable<ShipStatus> ships, ShipCategory shipTypes)\r
197         {\r
198             var ids = Enumerable.Range(0, ShipTypeIds.Length)\r
199                 .Where(type => ((int)shipTypes & (1 << type)) != 0)\r
200                 .SelectMany(type => ShipTypeIds[type]).ToArray();\r
201             return ships.Where(ship => ids.Contains(ship.Spec.ShipType));\r
202         }\r
203 \r
204         public IEnumerable<ShipStatus> CurrentShipList => _shipList.Where(ship => ship.Level != 1000);\r
205 \r
206         private class CompareShip : IComparer<ShipStatus>\r
207         {\r
208             private readonly bool _shipType;\r
209             private readonly ListForm.SortOrder _order;\r
210 \r
211             public CompareShip(bool type, ListForm.SortOrder order)\r
212             {\r
213                 _shipType = type;\r
214                 _order = order;\r
215             }\r
216 \r
217             public int Compare(ShipStatus a, ShipStatus b)\r
218             {\r
219                 if (a == null || b == null)\r
220                     throw new ArgumentNullException();\r
221                 if (_shipType)\r
222                 {\r
223                     if (a.Spec.ShipType != b.Spec.ShipType)\r
224                         return ShipTypeSortIds[a.Spec.ShipType] - ShipTypeSortIds[b.Spec.ShipType];\r
225                     if (a.Level != b.Level)\r
226                     {\r
227                         if (a.Level == 1000)\r
228                             return -1;\r
229                         if (b.Level == 1000)\r
230                             return 1;\r
231                     }\r
232                 }\r
233                 if (_order == ListForm.SortOrder.Repair && a.RepairTime != b.RepairTime)\r
234                     return (int)(b.RepairTime - a.RepairTime).TotalSeconds;\r
235                 if (a.Cond != b.Cond)\r
236                 {\r
237                     if (_order == ListForm.SortOrder.CondAscend)\r
238                         return a.Cond - b.Cond;\r
239                     if (_order == ListForm.SortOrder.CondDescend)\r
240                         return b.Cond - a.Cond;\r
241                 }\r
242                 if (a.Level != b.Level)\r
243                 {\r
244                     if (_order == ListForm.SortOrder.ExpToNextAscend)\r
245                         return b.Level - a.Level;\r
246                     if (_order == ListForm.SortOrder.ExpToNextDescend)\r
247                         return a.Level - b.Level;\r
248                 }\r
249                 if (a.ExpToNext != b.ExpToNext)\r
250                 {\r
251                     if (_order == ListForm.SortOrder.ExpToNextAscend)\r
252                         return a.ExpToNext - b.ExpToNext;\r
253                     if (_order == ListForm.SortOrder.ExpToNextDescend)\r
254                         return b.ExpToNext - a.ExpToNext;\r
255                 }\r
256                 if (_shipType)\r
257                 {\r
258                     if (a.Spec.SortId != b.Spec.SortId)\r
259                         return a.Spec.SortId - b.Spec.SortId;\r
260                     if (a.Level != b.Level)\r
261                         return b.Level - a.Level;\r
262                 }\r
263                 else\r
264                 {\r
265                     if (a.Level != b.Level)\r
266                         return b.Level - a.Level;\r
267                     if (a.Spec.SortId != b.Spec.SortId)\r
268                         return a.Spec.SortId - b.Spec.SortId;\r
269                 }\r
270                 return a.Id - b.Id;\r
271             }\r
272         }\r
273 \r
274         private void SetupLabels()\r
275         {\r
276             for (; _labelCount * LineHeight < Height; _labelCount++)\r
277             {\r
278                 _groupConfigLabels.CreateComponents(_labelCount);\r
279                 _repairListLabels.CreateLabels(_labelCount);\r
280                 _shipListLabels.CreateShipLabels(_labelCount);\r
281             }\r
282             SetupScrollBar();\r
283         }\r
284 \r
285         private void SetupScrollBar()\r
286         {\r
287             var needBar = Scaler.ScaleHeight((float)_shipList.Length * LineHeight) > Height;\r
288             if (!needBar)\r
289             {\r
290                 ScrollBar.Visible = false;\r
291                 ScrollBar.Value = 0;\r
292                 return;\r
293             }\r
294             ScrollBar.Visible = true;\r
295             ScrollBar.Minimum = 0;\r
296             var lines = Max(1, Height / Scaler.ScaleHeight(LineHeight));\r
297             var max = _shipList.Length - lines;\r
298             var largeChange = Min(lines, max);\r
299             ScrollBar.LargeChange = largeChange;\r
300             ScrollBar.Maximum = Max(0, max + largeChange - 1); // ScrollBarを最大まで動かしてもmaxには届かない\r
301             ScrollBar.Value = Min(ScrollBar.Value, max);\r
302         }\r
303 \r
304         private void ResizeLabels()\r
305         {\r
306             var width = Width - SystemInformation.VerticalScrollBarWidth - 2;\r
307             for (var i = 0; i < _labelCount; i++)\r
308             {\r
309                 _shipListLabels.Resize(i, width);\r
310                 _groupConfigLabels.Resize(i, width);\r
311                 _repairListLabels.Resize(i, width);\r
312             }\r
313         }\r
314 \r
315         public void SetHpPercent(ShipLabel.Hp label)\r
316         {\r
317             if (_hpPercent)\r
318                 label.ToggleHpPercent();\r
319             _hpLabels.Add(label);\r
320             label.DoubleClick += HpLabelClickHandler;\r
321         }\r
322 \r
323         private void SetShipLabels()\r
324         {\r
325             for (var i = 0; i < (Height + LineHeight - 1) / LineHeight; i++)\r
326             {\r
327                 HidePanels(i);\r
328                 if (i + ScrollBar.Value >= _shipList.Length)\r
329                     continue;\r
330                 if (InShipStatus(_mode))\r
331                     _shipListLabels.SetShipStatus(i);\r
332                 if (_mode == "分類")\r
333                     _groupConfigLabels.SetGrouping(i);\r
334                 if (_mode == "修復")\r
335                     _repairListLabels.SetRepairList(i);\r
336             }\r
337         }\r
338 \r
339         public void SetShipType(int i)\r
340         {\r
341             _shipListLabels.SetShipType(i);\r
342         }\r
343 \r
344         private void HidePanels(int i)\r
345         {\r
346             _shipListLabels.HidePanel(i);\r
347             _repairListLabels.HidePanel(i);\r
348             _groupConfigLabels.HidePanel(i);\r
349         }\r
350 \r
351         private bool InShipStatus(string mode) => Array.Exists(new[] {"全艦", "A", "B", "C", "D"}, x => mode == x);\r
352 \r
353         public event Action HpLabelClick;\r
354 \r
355         private void HpLabelClickHandler(object sender, EventArgs ev)\r
356         {\r
357             HpLabelClick?.Invoke();\r
358         }\r
359 \r
360         public void ToggleHpPercent()\r
361         {\r
362             _hpPercent = !_hpPercent;\r
363             foreach (var label in _hpLabels)\r
364                 label.ToggleHpPercent();\r
365         }\r
366 \r
367         public void ShowShip(int id)\r
368         {\r
369             if (!ScrollBar.Visible)\r
370                 return;\r
371             var i = Array.FindIndex(_shipList, s => s.Id == id);\r
372             if (i == -1)\r
373                 return;\r
374             ScrollBar.Value = Min(i, ScrollBar.Maximum + 1 - ScrollBar.LargeChange);\r
375             SetShipLabels();\r
376         }\r
377     }\r
378 }