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 List<List<int>> GroupSettings
\r
42 get => _groupConfigLabels.GroupSettings;
\r
43 set => _groupConfigLabels.GroupSettings = value;
\r
47 public bool GroupUpdated
\r
49 get => _groupConfigLabels.GroupUpdated;
\r
50 set => _groupConfigLabels.GroupUpdated = value;
\r
53 public ScrollBar ScrollBar { get; }
\r
55 public ShipStatus GetShip(int i)
\r
57 return _shipList[i + ScrollBar.Value];
\r
60 public ShipListPanel()
\r
62 ScrollBar = new VScrollBar {Dock = DockStyle.Right, Visible = false};
\r
63 ScrollBar.ValueChanged += ScrollBarOnValueChanged;
\r
64 Controls.Add(ScrollBar);
\r
65 _shipListLabels = new ShipListLabels(this);
\r
66 _groupConfigLabels = new GroupConfigLabels(this);
\r
67 _repairListLabels = new RepairListLabels(this);
\r
70 private void ScrollBarOnValueChanged(object sender, EventArgs eventArgs)
\r
77 public void ApplyResize()
\r
79 if (_shipList == null || _shipList.Length == 0 || !Visible)
\r
88 protected override void OnMouseWheel(MouseEventArgs e)
\r
90 if (!ScrollBar.Visible)
\r
92 ScrollBar.Value = Max(ScrollBar.Minimum, Min(ScrollBar.Maximum - ScrollBar.LargeChange + 1,
\r
93 ScrollBar.Value - e.Delta * SystemInformation.MouseWheelScrollLines / 120));
\r
96 public void Update(Sniffer sniffer, string mode, ShipListConfig settings)
\r
99 CreateShipList(sniffer, settings);
\r
107 [DllImport("user32.dll")]
\r
108 private static extern int SendMessage(IntPtr hWnd, int wMsg, bool wParam, IntPtr lParam);
\r
110 private void SuspendDrawing()
\r
112 SendMessage(Handle, 11, false, IntPtr.Zero); // WM_SETREDRAW = 11
\r
116 private void ResumeDrawing()
\r
119 SendMessage(Handle, 11, true, IntPtr.Zero);
\r
123 private void CreateShipList(Sniffer sniffer, ShipListConfig settings)
\r
125 var ships = FilterByShipTypes(
\r
126 _mode == "修復" ? sniffer.RepairList : FilterByGroup(sniffer.ShipList, settings.ShipGroup, _mode),
\r
127 settings.ShipCategories).ToArray();
\r
128 var order = _mode == "修復" ? ListForm.SortOrder.Repair : settings.SortOrder;
\r
129 if (!settings.ShipType)
\r
131 _shipList = ships.OrderBy(s => s, new CompareShip(false, order)).ToArray();
\r
134 _shipList = ships.Select(ship => new {Id = ship.Spec.ShipType, Name = ship.Spec.ShipTypeName})
\r
135 .Distinct().Select(type => new ShipStatus
\r
137 Spec = new ShipSpec {Name = type.Name, ShipType = type.Id},
\r
139 }).Concat(ships).OrderBy(ship => ship, new CompareShip(true, order)).ToArray();
\r
142 private static IEnumerable<ShipStatus> FilterByGroup(IEnumerable<ShipStatus> ships,
\r
143 IReadOnlyList<List<int>> groups, string groupName)
\r
145 var g = Array.FindIndex(new[] {"A", "B", "C", "D"}, x => x == groupName);
\r
148 if (groups.Count == 0)
\r
149 return new ShipStatus[0];
\r
150 return from s in ships where groups[g].Contains(s.Id) select s;
\r
153 private static readonly int[][] ShipTypeIds =
\r
201 private static readonly int[] ShipTypeSortIds = CreateShipTypeSortIds();
\r
203 private static int[] CreateShipTypeSortIds()
\r
205 var ids = ShipTypeIds.SelectMany(x => x).ToArray();
\r
206 var res = new int[ids.Max() + 1];
\r
207 for (var i = 0; i < ids.Length; i++)
\r
212 private static IEnumerable<ShipStatus> FilterByShipTypes(IEnumerable<ShipStatus> ships, ShipCategory shipTypes)
\r
214 var ids = Enumerable.Range(0, ShipTypeIds.Length)
\r
215 .Where(type => ((int)shipTypes & (1 << type)) != 0)
\r
216 .SelectMany(type => ShipTypeIds[type]).ToArray();
\r
217 return ships.Where(ship => ids.Contains(ship.Spec.ShipType));
\r
220 public IEnumerable<ShipStatus> CurrentShipList => _shipList.Where(ship => ship.Level != 1000);
\r
222 private class CompareShip : IComparer<ShipStatus>
\r
224 private readonly bool _shipType;
\r
225 private readonly ListForm.SortOrder _order;
\r
227 public CompareShip(bool type, ListForm.SortOrder order)
\r
233 public int Compare(ShipStatus a, ShipStatus b)
\r
235 if (a == null || b == null)
\r
236 throw new ArgumentNullException();
\r
239 if (a.Spec.ShipType != b.Spec.ShipType)
\r
240 return ShipTypeSortIds[a.Spec.ShipType] - ShipTypeSortIds[b.Spec.ShipType];
\r
241 if (a.Level != b.Level)
\r
243 if (a.Level == 1000)
\r
245 if (b.Level == 1000)
\r
249 if (_order == ListForm.SortOrder.Repair && a.RepairTime != b.RepairTime)
\r
250 return (int)(b.RepairTime - a.RepairTime).TotalSeconds;
\r
251 if (a.Cond != b.Cond)
\r
253 if (_order == ListForm.SortOrder.CondAscend)
\r
254 return a.Cond - b.Cond;
\r
255 if (_order == ListForm.SortOrder.CondDescend)
\r
256 return b.Cond - a.Cond;
\r
258 if (a.Level != b.Level)
\r
260 if (_order == ListForm.SortOrder.ExpToNextAscend)
\r
261 return b.Level - a.Level;
\r
262 if (_order == ListForm.SortOrder.ExpToNextDescend)
\r
263 return a.Level - b.Level;
\r
265 if (a.ExpToNext != b.ExpToNext)
\r
267 if (_order == ListForm.SortOrder.ExpToNextAscend)
\r
268 return a.ExpToNext - b.ExpToNext;
\r
269 if (_order == ListForm.SortOrder.ExpToNextDescend)
\r
270 return b.ExpToNext - a.ExpToNext;
\r
274 if (a.Spec.SortId != b.Spec.SortId)
\r
275 return a.Spec.SortId - b.Spec.SortId;
\r
276 if (a.Level != b.Level)
\r
277 return b.Level - a.Level;
\r
281 if (a.Level != b.Level)
\r
282 return b.Level - a.Level;
\r
283 if (a.Spec.SortId != b.Spec.SortId)
\r
284 return a.Spec.SortId - b.Spec.SortId;
\r
286 return a.Id - b.Id;
\r
290 private void SetupLabels()
\r
292 for (; _labelCount * LineHeight < Height; _labelCount++)
\r
294 _groupConfigLabels.CreateComponents(_labelCount);
\r
295 _repairListLabels.CreateLabels(_labelCount);
\r
296 _shipListLabels.CreateShipLabels(_labelCount);
\r
301 private void SetupScrollBar()
\r
303 var needBar = Scaler.ScaleHeight((float)_shipList.Length * LineHeight) > Height;
\r
306 ScrollBar.Visible = false;
\r
307 ScrollBar.Value = 0;
\r
310 ScrollBar.Visible = true;
\r
311 ScrollBar.Minimum = 0;
\r
312 var lines = Max(1, Height / Scaler.ScaleHeight(LineHeight));
\r
313 var max = _shipList.Length - lines;
\r
314 var largeChange = Min(lines, max);
\r
315 ScrollBar.LargeChange = largeChange;
\r
316 ScrollBar.Maximum = Max(0, max + largeChange - 1); // ScrollBarを最大まで動かしてもmaxには届かない
\r
317 ScrollBar.Value = Min(ScrollBar.Value, max);
\r
320 private void ResizeLabels()
\r
322 var width = Width - SystemInformation.VerticalScrollBarWidth - 2;
\r
323 for (var i = 0; i < _labelCount; i++)
\r
325 _shipListLabels.Resize(i, width);
\r
326 _groupConfigLabels.Resize(i, width);
\r
327 _repairListLabels.Resize(i, width);
\r
331 public void SetHpPercent(ShipLabel.Hp label)
\r
334 label.ToggleHpPercent();
\r
335 _hpLabels.Add(label);
\r
336 label.DoubleClick += HpLabelClickHandler;
\r
339 private void SetShipLabels()
\r
341 for (var i = 0; i < (Height + LineHeight - 1) / LineHeight; i++)
\r
344 if (i + ScrollBar.Value >= _shipList.Length)
\r
346 if (InShipStatus(_mode))
\r
347 _shipListLabels.SetShipStatus(i);
\r
349 _groupConfigLabels.SetGrouping(i);
\r
351 _repairListLabels.SetRepairList(i);
\r
355 public void SetShipType(int i)
\r
357 _shipListLabels.SetShipType(i);
\r
360 private void HidePanels(int i)
\r
362 _shipListLabels.HidePanel(i);
\r
363 _repairListLabels.HidePanel(i);
\r
364 _groupConfigLabels.HidePanel(i);
\r
367 private bool InShipStatus(string mode) => Array.Exists(new[] {"全艦", "A", "B", "C", "D"}, x => mode == x);
\r
369 public event Action HpLabelClick;
\r
371 private void HpLabelClickHandler(object sender, EventArgs ev)
\r
373 HpLabelClick?.Invoke();
\r
376 public void ToggleHpPercent()
\r
378 _hpPercent = !_hpPercent;
\r
379 foreach (var label in _hpLabels)
\r
380 label.ToggleHpPercent();
\r
383 public void ShowShip(int id)
\r
385 if (!ScrollBar.Visible)
\r
387 var i = Array.FindIndex(_shipList, s => s.Id == id);
\r
390 ScrollBar.Value = Min(i, ScrollBar.Maximum + 1 - ScrollBar.LargeChange);
\r