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.Model;
\r
21 using static System.Math;
\r
23 namespace KancolleSniffer.View.ShipListPanel
\r
25 public class ShipListPanel : Panel
\r
27 public const int LabelHeight = 12;
\r
28 public const int LineHeight = 16;
\r
29 private ShipStatus[] _shipList;
\r
30 private readonly List<ShipLabel.Hp> _hpLabels = new List<ShipLabel.Hp>();
\r
31 private readonly ShipListLabels _shipListLabels;
\r
32 private readonly GroupConfigLabels _groupConfigLabels;
\r
33 private readonly RepairListLabels _repairListLabels;
\r
34 private int _labelCount;
\r
35 private string _mode;
\r
36 private bool _hpPercent;
\r
38 public HashSet<int>[] GroupSettings => _groupConfigLabels.GroupSettings;
\r
40 public bool GroupUpdated
\r
42 get => _groupConfigLabels.GroupUpdated;
\r
43 set => _groupConfigLabels.GroupUpdated = value;
\r
46 public ScrollBar ScrollBar { get; }
\r
48 public ShipStatus GetShip(int i)
\r
50 return _shipList[i + ScrollBar.Value];
\r
53 public ShipListPanel()
\r
55 ScrollBar = new VScrollBar {Dock = DockStyle.Right, Visible = false};
\r
56 ScrollBar.ValueChanged += ScrollBarOnValueChanged;
\r
57 Controls.Add(ScrollBar);
\r
58 _shipListLabels = new ShipListLabels(this);
\r
59 _groupConfigLabels = new GroupConfigLabels(this);
\r
60 _repairListLabels = new RepairListLabels(this);
\r
63 private void ScrollBarOnValueChanged(object sender, EventArgs eventArgs)
\r
70 protected override void OnResize(EventArgs ev)
\r
73 if (_shipList == null || _shipList.Length == 0 || !Visible)
\r
81 protected override void OnMouseWheel(MouseEventArgs e)
\r
83 if (!ScrollBar.Visible)
\r
85 ScrollBar.Value = Max(ScrollBar.Minimum, Min(ScrollBar.Maximum - ScrollBar.LargeChange + 1,
\r
86 ScrollBar.Value - e.Delta * SystemInformation.MouseWheelScrollLines / 120));
\r
89 public void Update(Sniffer sniffer, string mode, ShipListConfig config)
\r
92 CreateShipList(sniffer, config);
\r
99 [DllImport("user32.dll")]
\r
100 public static extern int SendMessage(IntPtr hWnd, int wMsg, bool wParam, IntPtr lParam);
\r
102 private void SuspendDrawing()
\r
104 SendMessage(Handle, 11, false, IntPtr.Zero); // WM_SETREDRAW = 11
\r
108 public void ResumeDrawing()
\r
111 SendMessage(Handle, 11, true, IntPtr.Zero);
\r
115 private void CreateShipList(Sniffer sniffer, ShipListConfig config)
\r
117 var ships = FilterByShipTypes(
\r
118 _mode == "修復" ? sniffer.RepairList : _groupConfigLabels.FilterByGroup(sniffer.ShipList, _mode),
\r
119 config.ShipCategories).ToArray();
\r
120 var order = _mode == "修復" ? ListForm.SortOrder.Repair : config.SortOrder;
\r
121 if (!config.ShipType)
\r
123 _shipList = ships.OrderBy(s => s, new CompareShip(false, order)).ToArray();
\r
126 _shipList = ships.Select(ship => new {Id = ship.Spec.ShipType, Name = ship.Spec.ShipTypeName})
\r
127 .Distinct().Select(type => new ShipStatus
\r
129 Spec = new ShipSpec {Name = type.Name, ShipType = type.Id},
\r
131 }).Concat(ships).OrderBy(ship => ship, new CompareShip(true, order)).ToArray();
\r
134 private static readonly int[][] ShipTypeIds =
\r
182 private static readonly int[] ShipTypeSortIds = CreateShipTypeSortIds();
\r
184 private static int[] CreateShipTypeSortIds()
\r
186 var ids = ShipTypeIds.SelectMany(x => x).ToArray();
\r
187 var res = new int[ids.Max() + 1];
\r
188 for (var i = 0; i < ids.Length; i++)
\r
193 private IEnumerable<ShipStatus> FilterByShipTypes(IEnumerable<ShipStatus> ships, ShipCategory shipTypes)
\r
195 var ids = Enumerable.Range(0, ShipTypeIds.Length)
\r
196 .Where(type => ((int)shipTypes & (1 << type)) != 0)
\r
197 .SelectMany(type => ShipTypeIds[type]).ToArray();
\r
198 return ships.Where(ship => ids.Contains(ship.Spec.ShipType));
\r
201 public IEnumerable<ShipStatus> CurrentShipList => _shipList.Where(ship => ship.Level != 1000);
\r
203 private class CompareShip : IComparer<ShipStatus>
\r
205 private readonly bool _shipType;
\r
206 private readonly ListForm.SortOrder _order;
\r
208 public CompareShip(bool type, ListForm.SortOrder order)
\r
214 public int Compare(ShipStatus a, ShipStatus b)
\r
216 if (a == null || b == null)
\r
217 throw new ArgumentNullException();
\r
220 if (a.Spec.ShipType != b.Spec.ShipType)
\r
221 return ShipTypeSortIds[a.Spec.ShipType] - ShipTypeSortIds[b.Spec.ShipType];
\r
222 if (a.Level != b.Level)
\r
224 if (a.Level == 1000)
\r
226 if (b.Level == 1000)
\r
230 if (_order == ListForm.SortOrder.Repair && a.RepairTime != b.RepairTime)
\r
231 return (int)(b.RepairTime - a.RepairTime).TotalSeconds;
\r
232 if (a.Cond != b.Cond)
\r
234 if (_order == ListForm.SortOrder.CondAscend)
\r
235 return a.Cond - b.Cond;
\r
236 if (_order == ListForm.SortOrder.CondDescend)
\r
237 return b.Cond - a.Cond;
\r
239 if (a.Level != b.Level)
\r
241 if (_order == ListForm.SortOrder.ExpToNextAscend)
\r
242 return b.Level - a.Level;
\r
243 if (_order == ListForm.SortOrder.ExpToNextDescend)
\r
244 return a.Level - b.Level;
\r
246 if (a.ExpToNext != b.ExpToNext)
\r
248 if (_order == ListForm.SortOrder.ExpToNextAscend)
\r
249 return a.ExpToNext - b.ExpToNext;
\r
250 if (_order == ListForm.SortOrder.ExpToNextDescend)
\r
251 return b.ExpToNext - a.ExpToNext;
\r
255 if (a.Spec.SortId != b.Spec.SortId)
\r
256 return a.Spec.SortId - b.Spec.SortId;
\r
257 if (a.Level != b.Level)
\r
258 return b.Level - a.Level;
\r
262 if (a.Level != b.Level)
\r
263 return b.Level - a.Level;
\r
264 if (a.Spec.SortId != b.Spec.SortId)
\r
265 return a.Spec.SortId - b.Spec.SortId;
\r
267 return a.Id - b.Id;
\r
271 private void SetupLabels()
\r
273 for (; _labelCount * LineHeight < Height; _labelCount++)
\r
275 _groupConfigLabels.CreateComponents(_labelCount);
\r
276 _repairListLabels.CreateLabels(_labelCount);
\r
277 _shipListLabels.CreateShipLabels(_labelCount);
\r
282 private void SetupScrollBar()
\r
284 var needBar = Scaler.ScaleHeight((float)_shipList.Length * LineHeight) > Height;
\r
287 ScrollBar.Visible = false;
\r
288 ScrollBar.Value = 0;
\r
291 ScrollBar.Visible = true;
\r
292 ScrollBar.Minimum = 0;
\r
293 var lines = Max(1, Height / Scaler.ScaleHeight(LineHeight));
\r
294 var max = _shipList.Length - lines;
\r
295 var largeChange = Min(lines, max);
\r
296 ScrollBar.LargeChange = largeChange;
\r
297 ScrollBar.Maximum = Max(0, max + largeChange - 1); // ScrollBarを最大まで動かしてもmaxには届かない
\r
298 ScrollBar.Value = Min(ScrollBar.Value, max);
\r
301 public void SetHpPercent(ShipLabel.Hp label)
\r
304 label.ToggleHpPercent();
\r
305 _hpLabels.Add(label);
\r
306 label.DoubleClick += HpLabelClickHandler;
\r
309 private void SetShipLabels()
\r
311 for (var i = 0; i < (Height + LineHeight - 1) / LineHeight; i++)
\r
314 if (i + ScrollBar.Value >= _shipList.Length)
\r
316 if (InShipStatus(_mode))
\r
317 _shipListLabels.SetShipStatus(i);
\r
319 _groupConfigLabels.SetGrouping(i);
\r
321 _repairListLabels.SetRepairList(i);
\r
325 public void SetShipType(int i)
\r
327 _shipListLabels.SetShipType(i);
\r
330 private void HidePanels(int i)
\r
332 _shipListLabels.HidePanel(i);
\r
333 _repairListLabels.HidePanel(i);
\r
334 _groupConfigLabels.HidePanel(i);
\r
337 private bool InShipStatus(string mode) => Array.Exists(new[] {"全艦", "A", "B", "C", "D"}, x => mode == x);
\r
339 public event Action HpLabelClick;
\r
341 private void HpLabelClickHandler(object sender, EventArgs ev)
\r
343 HpLabelClick?.Invoke();
\r
346 public void ToggleHpPercent()
\r
348 _hpPercent = !_hpPercent;
\r
349 foreach (var label in _hpLabels)
\r
350 label.ToggleHpPercent();
\r
353 public void ShowShip(int id)
\r
355 if (!ScrollBar.Visible)
\r
357 var i = Array.FindIndex(_shipList, s => s.Id == id);
\r
360 ScrollBar.Value = Min(i, ScrollBar.Maximum + 1 - ScrollBar.LargeChange);
\r