1 // Copyright (C) 2016 Kazuhiro Fujieda <fujieda@users.osdn.me>
\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
7 // http://www.apache.org/licenses/LICENSE-2.0
\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
16 using System.Collections.Generic;
\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
25 namespace KancolleSniffer.View.ShipListPanel
\r
27 public class ShipListPanel : Panel, IPanelResize
\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
40 public HashSet<int>[] GroupSettings => _groupConfigLabels.GroupSettings;
\r
42 public bool GroupUpdated
\r
44 get => _groupConfigLabels.GroupUpdated;
\r
45 set => _groupConfigLabels.GroupUpdated = value;
\r
48 public ScrollBar ScrollBar { get; }
\r
50 public ShipStatus GetShip(int i)
\r
52 return _shipList[i + ScrollBar.Value];
\r
55 public ShipListPanel()
\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
65 private void ScrollBarOnValueChanged(object sender, EventArgs eventArgs)
\r
72 public void ApplyResize()
\r
74 if (_shipList == null || _shipList.Length == 0 || !Visible)
\r
83 protected override void OnMouseWheel(MouseEventArgs e)
\r
85 if (!ScrollBar.Visible)
\r
87 ScrollBar.Value = Max(ScrollBar.Minimum, Min(ScrollBar.Maximum - ScrollBar.LargeChange + 1,
\r
88 ScrollBar.Value - e.Delta * SystemInformation.MouseWheelScrollLines / 120));
\r
91 public void Update(Sniffer sniffer, string mode, ShipListConfig settings)
\r
94 CreateShipList(sniffer, settings);
\r
102 [DllImport("user32.dll")]
\r
103 private static extern int SendMessage(IntPtr hWnd, int wMsg, bool wParam, IntPtr lParam);
\r
105 private void SuspendDrawing()
\r
107 SendMessage(Handle, 11, false, IntPtr.Zero); // WM_SETREDRAW = 11
\r
111 private void ResumeDrawing()
\r
114 SendMessage(Handle, 11, true, IntPtr.Zero);
\r
118 private void CreateShipList(Sniffer sniffer, ShipListConfig settings)
\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
126 _shipList = ships.OrderBy(s => s, new CompareShip(false, order)).ToArray();
\r
129 _shipList = ships.Select(ship => new {Id = ship.Spec.ShipType, Name = ship.Spec.ShipTypeName})
\r
130 .Distinct().Select(type => new ShipStatus
\r
132 Spec = new ShipSpec {Name = type.Name, ShipType = type.Id},
\r
134 }).Concat(ships).OrderBy(ship => ship, new CompareShip(true, order)).ToArray();
\r
137 private static readonly int[][] ShipTypeIds =
\r
185 private static readonly int[] ShipTypeSortIds = CreateShipTypeSortIds();
\r
187 private static int[] CreateShipTypeSortIds()
\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
196 private static IEnumerable<ShipStatus> FilterByShipTypes(IEnumerable<ShipStatus> ships, ShipCategory shipTypes)
\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
204 public IEnumerable<ShipStatus> CurrentShipList => _shipList.Where(ship => ship.Level != 1000);
\r
206 private class CompareShip : IComparer<ShipStatus>
\r
208 private readonly bool _shipType;
\r
209 private readonly ListForm.SortOrder _order;
\r
211 public CompareShip(bool type, ListForm.SortOrder order)
\r
217 public int Compare(ShipStatus a, ShipStatus b)
\r
219 if (a == null || b == null)
\r
220 throw new ArgumentNullException();
\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
227 if (a.Level == 1000)
\r
229 if (b.Level == 1000)
\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
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
242 if (a.Level != b.Level)
\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
249 if (a.ExpToNext != b.ExpToNext)
\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
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
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
270 return a.Id - b.Id;
\r
274 private void SetupLabels()
\r
276 for (; _labelCount * LineHeight < Height; _labelCount++)
\r
278 _groupConfigLabels.CreateComponents(_labelCount);
\r
279 _repairListLabels.CreateLabels(_labelCount);
\r
280 _shipListLabels.CreateShipLabels(_labelCount);
\r
285 private void SetupScrollBar()
\r
287 var needBar = Scaler.ScaleHeight((float)_shipList.Length * LineHeight) > Height;
\r
290 ScrollBar.Visible = false;
\r
291 ScrollBar.Value = 0;
\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
304 private void ResizeLabels()
\r
306 var width = Width - SystemInformation.VerticalScrollBarWidth - 2;
\r
307 for (var i = 0; i < _labelCount; i++)
\r
309 _shipListLabels.Resize(i, width);
\r
310 _groupConfigLabels.Resize(i, width);
\r
311 _repairListLabels.Resize(i, width);
\r
315 public void SetHpPercent(ShipLabel.Hp label)
\r
318 label.ToggleHpPercent();
\r
319 _hpLabels.Add(label);
\r
320 label.DoubleClick += HpLabelClickHandler;
\r
323 private void SetShipLabels()
\r
325 for (var i = 0; i < (Height + LineHeight - 1) / LineHeight; i++)
\r
328 if (i + ScrollBar.Value >= _shipList.Length)
\r
330 if (InShipStatus(_mode))
\r
331 _shipListLabels.SetShipStatus(i);
\r
333 _groupConfigLabels.SetGrouping(i);
\r
335 _repairListLabels.SetRepairList(i);
\r
339 public void SetShipType(int i)
\r
341 _shipListLabels.SetShipType(i);
\r
344 private void HidePanels(int i)
\r
346 _shipListLabels.HidePanel(i);
\r
347 _repairListLabels.HidePanel(i);
\r
348 _groupConfigLabels.HidePanel(i);
\r
351 private bool InShipStatus(string mode) => Array.Exists(new[] {"全艦", "A", "B", "C", "D"}, x => mode == x);
\r
353 public event Action HpLabelClick;
\r
355 private void HpLabelClickHandler(object sender, EventArgs ev)
\r
357 HpLabelClick?.Invoke();
\r
360 public void ToggleHpPercent()
\r
362 _hpPercent = !_hpPercent;
\r
363 foreach (var label in _hpLabels)
\r
364 label.ToggleHpPercent();
\r
367 public void ShowShip(int id)
\r
369 if (!ScrollBar.Visible)
\r
371 var i = Array.FindIndex(_shipList, s => s.Id == id);
\r
374 ScrollBar.Value = Min(i, ScrollBar.Maximum + 1 - ScrollBar.LargeChange);
\r