using System.Collections.Generic;\r
using System.Drawing;\r
using System.Linq;\r
+using System.Runtime.InteropServices;\r
using System.Windows.Forms;\r
+using static System.Math;\r
\r
namespace KancolleSniffer\r
{\r
public class ShipListPanel : Panel\r
{\r
private const int LabelHeight = 12;\r
- private const int LineHeight = 16;\r
+ public const int LineHeight = 16;\r
private ShipStatus[] _shipList;\r
private readonly List<ShipLabel[]> _labelList = new List<ShipLabel[]>();\r
private readonly List<Panel> _labelPanelList = new List<Panel>();\r
private readonly List<CheckBox[]> _checkBoxesList = new List<CheckBox[]>();\r
- private readonly List<ShipLabel[]> _configLabelList = new List<ShipLabel[]>();\r
- private readonly List<Panel> _checkBoxPanelList = new List<Panel>();\r
+ private readonly List<ShipLabel[]> _groupingLabelList = new List<ShipLabel[]>();\r
+ private readonly List<Panel> _groupingPanelList = new List<Panel>();\r
private readonly List<ShipLabel[]> _repairLabelList = new List<ShipLabel[]>();\r
private readonly List<Panel> _repairPanelList = new List<Panel>();\r
+ private string _mode;\r
\r
public const int GroupCount = 4;\r
public HashSet<int>[] GroupSettings { get; } = new HashSet<int>[GroupCount];\r
\r
+ public ScrollBar ScrollBar { get; }\r
+\r
+ public ShipListPanel()\r
+ {\r
+ ScrollBar = new VScrollBar {Dock = DockStyle.Right, Visible = false};\r
+ ScrollBar.ValueChanged += ScrollBarOnValueChanged;\r
+ Controls.Add(ScrollBar);\r
+ }\r
+\r
+ private void ScrollBarOnValueChanged(object sender, EventArgs eventArgs)\r
+ {\r
+ SuspendDrawing();\r
+ SetShipLabels();\r
+ ResumeDrawing();\r
+ }\r
+\r
+ protected override void OnResize(EventArgs ev)\r
+ {\r
+ base.OnResize(ev);\r
+ if (_shipList == null || _shipList.Length == 0 || !Visible)\r
+ return;\r
+ SuspendDrawing();\r
+ SetupLabels();\r
+ SetShipLabels();\r
+ ResumeDrawing();\r
+ }\r
+\r
+ protected override void OnMouseWheel(MouseEventArgs e)\r
+ {\r
+ if (!ScrollBar.Visible)\r
+ return;\r
+ ScrollBar.Value = Max(ScrollBar.Minimum, Min(ScrollBar.Maximum - ScrollBar.LargeChange + 1,\r
+ ScrollBar.Value - e.Delta * SystemInformation.MouseWheelScrollLines / 120));\r
+ }\r
+\r
public void Update(Sniffer sniffer, string mode, ListForm.SortOrder sortOrder, bool byShipType)\r
{\r
- CreateShipList(sniffer, mode, sortOrder, byShipType);\r
- CreateListLabels();\r
- SetShipLabels(mode);\r
+ _mode = mode;\r
+ CreateShipList(sniffer, sortOrder, byShipType);\r
+ SuspendDrawing();\r
+ SetupLabels();\r
+ SetShipLabels();\r
+ ResumeDrawing();\r
}\r
\r
- void CreateShipList(Sniffer sniffer, string mode, ListForm.SortOrder sortOrder, bool byShipType)\r
+ [DllImport("user32.dll")]\r
+ public static extern int SendMessage(IntPtr hWnd, int wMsg, bool wParam, IntPtr lParam);\r
+\r
+ private void SuspendDrawing()\r
+ {\r
+ SendMessage(Handle, 11, false, IntPtr.Zero); // WM_SETREDRAW = 11\r
+ SuspendLayout();\r
+ }\r
+\r
+ public void ResumeDrawing()\r
+ {\r
+ ResumeLayout();\r
+ SendMessage(Handle, 11, true, IntPtr.Zero);\r
+ Refresh();\r
+ }\r
+\r
+ void CreateShipList(Sniffer sniffer, ListForm.SortOrder sortOrder, bool byShipType)\r
{\r
- var ships = mode == "修復" ? sniffer.RepairList : FilterByGroup(sniffer.ShipList, mode).ToArray();\r
- var order = mode == "修復" ? ListForm.SortOrder.Repair : sortOrder;\r
+ var ships = _mode == "修復" ? sniffer.RepairList : FilterByGroup(sniffer.ShipList, _mode).ToArray();\r
+ var order = _mode == "修復" ? ListForm.SortOrder.Repair : sortOrder;\r
if (!byShipType)\r
{\r
_shipList = ships.OrderBy(s => s, new CompareShip(false, order)).ToArray();\r
return;\r
}\r
- var types = ships.Select(s => new {Id = s.Spec.ShipType, Name = s.Spec.ShipTypeName}).Distinct().\r
- Select(stype =>\r
+ var types = ships.Select(s => new {Id = s.Spec.ShipType, Name = s.Spec.ShipTypeName})\r
+ .Distinct()\r
+ .Select(stype =>\r
new ShipStatus\r
{\r
Spec = new ShipSpec {Name = stype.Name, ShipType = stype.Id},\r
\r
private class CompareShip : IComparer<ShipStatus>\r
{\r
- private readonly bool _type;\r
+ private readonly bool _shipType;\r
private readonly ListForm.SortOrder _order;\r
\r
public CompareShip(bool type, ListForm.SortOrder order)\r
{\r
- _type = type;\r
+ _shipType = type;\r
_order = order;\r
}\r
\r
public int Compare(ShipStatus a, ShipStatus b)\r
{\r
- if (_type && a.Spec.ShipType != b.Spec.ShipType)\r
- return a.Spec.ShipType - b.Spec.ShipType;\r
- switch (_order)\r
+ if (a == null || b == null)\r
+ throw new ArgumentNullException();\r
+ if (_shipType)\r
+ {\r
+ if (a.Spec.ShipType != b.Spec.ShipType)\r
+ return a.Spec.ShipType - b.Spec.ShipType;\r
+ if (a.Level != b.Level)\r
+ {\r
+ if (a.Level == 1000)\r
+ return -1;\r
+ if (b.Level == 1000)\r
+ return 1;\r
+ }\r
+ }\r
+ if (_order == ListForm.SortOrder.Repair && a.RepairTime != b.RepairTime)\r
+ return (int)(b.RepairTime - a.RepairTime).TotalSeconds;\r
+ if (a.Cond != b.Cond)\r
+ {\r
+ if (_order == ListForm.SortOrder.CondAscend)\r
+ return a.Cond - b.Cond;\r
+ if (_order == ListForm.SortOrder.CondDescend)\r
+ return b.Cond - a.Cond;\r
+ }\r
+ if (a.Level != b.Level)\r
{\r
- case ListForm.SortOrder.None:\r
- case ListForm.SortOrder.ExpToNext:\r
- break;\r
- case ListForm.SortOrder.Cond:\r
- if (a.Cond != b.Cond)\r
- return a.Cond - b.Cond;\r
- break;\r
- case ListForm.SortOrder.Repair:\r
- if (a.RepairTime != b.RepairTime)\r
- return (int)(b.RepairTime - a.RepairTime).TotalSeconds;\r
- break;\r
+ if (_order == ListForm.SortOrder.ExpToNextAscend)\r
+ return b.Level - a.Level;\r
+ if (_order == ListForm.SortOrder.ExpToNextDescend)\r
+ return a.Level - b.Level;\r
+ if (!_shipType) // Condが同じかSortOrder.Noneで艦種なし\r
+ return b.Level - a.Level;\r
+ }\r
+ if (a.ExpToNext != b.ExpToNext)\r
+ {\r
+ if (_order == ListForm.SortOrder.ExpToNextAscend)\r
+ return a.ExpToNext - b.ExpToNext;\r
+ if (_order == ListForm.SortOrder.ExpToNextDescend)\r
+ return b.ExpToNext - a.ExpToNext;\r
}\r
- if ((!_type || _order == ListForm.SortOrder.ExpToNext) && a.Level != b.Level)\r
- return b.Level - a.Level;\r
- if (_order == ListForm.SortOrder.ExpToNext && a.ExpToNext != b.ExpToNext)\r
- return a.ExpToNext - b.ExpToNext;\r
if (a.Spec.SortNo != b.Spec.SortNo)\r
return a.Spec.SortNo - b.Spec.SortNo;\r
return a.Id - b.Id;\r
}\r
}\r
\r
- private void CreateListLabels()\r
+ private void SetupLabels()\r
{\r
- SuspendLayout();\r
- for (var i = _labelList.Count; i < _shipList.Length; i++)\r
+ for (var i = _labelList.Count; i * LineHeight < Height; i++)\r
{\r
- CreateConfigComponents(i);\r
+ CreateGroupingComponents(i);\r
CreateRepairLabels(i);\r
CreateShipLabels(i);\r
}\r
- ResumeLayout();\r
+ for (var i = 0; i * LineHeight < Height; i++)\r
+ {\r
+ _labelPanelList[i].Visible = InShipStatus(_mode);\r
+ _groupingPanelList[i].Visible = _mode == "分類";\r
+ _repairPanelList[i].Visible = _mode == "修復";\r
+ }\r
+ SetupScrollBar();\r
}\r
\r
- private void CreateConfigComponents(int i)\r
+ private void SetupScrollBar()\r
+ {\r
+ var needBar = _shipList.Length * LineHeight * ShipLabel.ScaleFactor.Height > Height;\r
+ if (!needBar)\r
+ {\r
+ ScrollBar.Visible = false;\r
+ ScrollBar.Value = 0;\r
+ return;\r
+ }\r
+ ScrollBar.Visible = true;\r
+ ScrollBar.Minimum = 0;\r
+ var lines = Max(1, Height / (int)Round(LineHeight * ShipLabel.ScaleFactor.Height));\r
+ var max = _shipList.Length - lines;\r
+ ScrollBar.LargeChange = Min(lines, max);\r
+ ScrollBar.Maximum =\r
+ Max(0, max + ScrollBar.LargeChange - 1); // ScrollBarを最大まで動かしてもmaxには届かない\r
+ ScrollBar.Value = Min(ScrollBar.Value, max);\r
+ }\r
+\r
+ private void CreateGroupingComponents(int i)\r
{\r
var y = 3 + LineHeight * i;\r
var cfgp = new Panel\r
Location = new Point(0, y - 2),\r
Size = new Size(ListForm.PanelWidth, LineHeight - 1),\r
BackColor = ShipLabels.ColumnColors[(i + 1) % 2],\r
- Visible = false\r
};\r
cfgp.Scale(ShipLabel.ScaleFactor);\r
cfgp.Tag = cfgp.Location.Y;\r
{\r
new ShipLabel\r
{\r
- Location = new Point(91, 2),\r
- Size = new Size(23, LabelHeight),\r
- TextAlign = ContentAlignment.MiddleRight,\r
+ Location = new Point(90, 2),\r
+ Size = new Size(24, LabelHeight),\r
+ TextAlign = ContentAlignment.MiddleRight\r
},\r
new ShipLabel {Location = new Point(10, 2), AutoSize = true},\r
new ShipLabel {Location = new Point(1, 2), AutoSize = true}\r
cb[j].Scale(ShipLabel.ScaleFactor);\r
cb[j].CheckedChanged += checkboxGroup_CheckedChanged;\r
}\r
- _configLabelList.Add(cfgl);\r
+ _groupingLabelList.Add(cfgl);\r
_checkBoxesList.Add(cb);\r
- _checkBoxPanelList.Add(cfgp);\r
+ _groupingPanelList.Add(cfgp);\r
// ReSharper disable CoVariantArrayConversion\r
cfgp.Controls.AddRange(cfgl);\r
cfgp.Controls.AddRange(cb);\r
var idx = (int)cb.Tag / 10;\r
if (cb.Checked)\r
{\r
- GroupSettings[group].Add(_shipList[idx].Id);\r
+ GroupSettings[group].Add(_shipList[idx + ScrollBar.Value].Id);\r
}\r
else\r
{\r
- GroupSettings[group].Remove(_shipList[idx].Id);\r
+ GroupSettings[group].Remove(_shipList[idx + ScrollBar.Value].Id);\r
}\r
}\r
\r
Location = new Point(0, y - 2),\r
Size = new Size(ListForm.PanelWidth, LineHeight - 1),\r
BackColor = ShipLabels.ColumnColors[(i + 1) % 2],\r
- Visible = false\r
};\r
rpp.Scale(ShipLabel.ScaleFactor);\r
rpp.Tag = rpp.Location.Y;\r
new ShipLabel {Location = new Point(118, 2), AutoSize = true, AnchorRight = true},\r
new ShipLabel\r
{\r
- Location = new Point(117, 2),\r
- Size = new Size(23, height),\r
+ Location = new Point(116, 2),\r
+ Size = new Size(24, height),\r
TextAlign = ContentAlignment.MiddleRight\r
},\r
new ShipLabel {Location = new Point(141, 2), AutoSize = true},\r
{\r
Location = new Point(0, y - 2),\r
Size = new Size(ListForm.PanelWidth, LineHeight - 1),\r
- BackColor = ShipLabels.ColumnColors[(i + 1) % 2],\r
- Visible = false\r
+ BackColor = ShipLabels.ColumnColors[(i + 1) % 2]\r
};\r
lbp.Scale(ShipLabel.ScaleFactor);\r
- lbp.Tag = lbp.Location.Y;\r
var labels = new[]\r
{\r
new ShipLabel {Location = new Point(126, 2), AutoSize = true, AnchorRight = true},\r
new ShipLabel\r
{\r
- Location = new Point(129, 2),\r
- Size = new Size(23, height),\r
+ Location = new Point(128, 2),\r
+ Size = new Size(24, height),\r
TextAlign = ContentAlignment.MiddleRight\r
},\r
new ShipLabel\r
{\r
- Location = new Point(155, 2),\r
- Size = new Size(23, height),\r
+ Location = new Point(154, 2),\r
+ Size = new Size(24, height),\r
TextAlign = ContentAlignment.MiddleRight\r
},\r
new ShipLabel\r
{\r
- Location = new Point(176, 2),\r
- Size = new Size(41, height),\r
+ Location = new Point(175, 2),\r
+ Size = new Size(42, height),\r
TextAlign = ContentAlignment.MiddleRight\r
},\r
new ShipLabel {Location = new Point(10, 2), AutoSize = true},\r
}\r
}\r
\r
- private void SetShipLabels(string mode)\r
+ private void SetShipLabels()\r
{\r
- SuspendLayout();\r
- for (var i = 0; i < _shipList.Length; i++)\r
+ for (var i = 0; i < (Height + LineHeight - 1) / LineHeight; i++)\r
{\r
- if (!InShipStatus(mode))\r
- _labelPanelList[i].Visible = false;\r
- if (mode != "分類")\r
- _checkBoxPanelList[i].Visible = false;\r
- if (mode != "修復")\r
- _repairPanelList[i].Visible = false;\r
- }\r
- for (var i = 0; i < _shipList.Length; i++)\r
- {\r
- if (InShipStatus(mode))\r
+ if (InShipStatus(_mode))\r
SetShipStatus(i);\r
- if (mode == "分類")\r
- SetGroupConfig(i);\r
- if (mode == "修復")\r
+ if (_mode == "分類")\r
+ SetGrouping(i);\r
+ if (_mode == "修復")\r
SetRepairList(i);\r
}\r
- for (var i = _shipList.Length; i < _labelPanelList.Count; i++)\r
- {\r
- _labelPanelList[i].Visible = _checkBoxPanelList[i].Visible = _repairPanelList[i].Visible = false;\r
- }\r
- ResumeLayout();\r
}\r
\r
private bool InShipStatus(string mode) => Array.Exists(new[] {"全員", "A", "B", "C", "D"}, x => mode == x);\r
\r
private void SetShipStatus(int i)\r
{\r
- var lbp = _labelPanelList[i];\r
- if (!lbp.Visible)\r
- lbp.Location = new Point(lbp.Left, (int)lbp.Tag + AutoScrollPosition.Y);\r
- var s = _shipList[i];\r
+ var panel = _labelPanelList[i];\r
+ if (i + ScrollBar.Value >= _shipList.Length)\r
+ {\r
+ panel.Visible = false;\r
+ return;\r
+ }\r
+ var s = _shipList[i + ScrollBar.Value];\r
var labels = _labelList[i];\r
if (s.Level == 1000) // 艦種の表示\r
{\r
labels[3].SetExpToNext(s);\r
labels[4].SetName(s, ShipNameWidth.ShipList);\r
labels[5].SetFleet(s);\r
- lbp.Visible = true;\r
+ panel.Visible = true;\r
}\r
\r
private void SetShipType(int i)\r
{\r
- var lbp = _labelPanelList[i];\r
- if (!lbp.Visible)\r
- lbp.Location = new Point(lbp.Left, (int)lbp.Tag + AutoScrollPosition.Y);\r
- var s = _shipList[i];\r
+ var s = _shipList[i + ScrollBar.Value];\r
var labels = _labelList[i];\r
for (var c = 0; c < 4; c++)\r
{\r
}\r
labels[4].SetName("");\r
labels[5].Text = s.Name;\r
- lbp.Visible = true;\r
+ _labelPanelList[i].Visible = true;\r
}\r
\r
- private void SetGroupConfig(int i)\r
+ private void SetGrouping(int i)\r
{\r
- var cbp = _checkBoxPanelList[i];\r
- var s = _shipList[i];\r
+ var panel = _groupingPanelList[i];\r
+ if (i + ScrollBar.Value >= _shipList.Length)\r
+ {\r
+ panel.Visible = false;\r
+ _labelPanelList[i].Visible = false;\r
+ return;\r
+ }\r
+ var s = _shipList[i + ScrollBar.Value];\r
+ var labels = _groupingLabelList[i];\r
if (s.Level == 1000)\r
{\r
+ panel.Visible = false;\r
SetShipType(i);\r
- cbp.Visible = false;\r
return;\r
}\r
- if (!cbp.Visible)\r
- cbp.Location = new Point(cbp.Left, (int)cbp.Tag + AutoScrollPosition.Y);\r
- var cfgl = _configLabelList[i];\r
- cfgl[0].SetLevel(s);\r
- cfgl[1].SetName(s, ShipNameWidth.GroupConfig);\r
- cfgl[2].SetFleet(s);\r
+ labels[0].SetLevel(s);\r
+ labels[1].SetName(s, ShipNameWidth.GroupConfig);\r
+ labels[2].SetFleet(s);\r
var cb = _checkBoxesList[i];\r
for (var j = 0; j < cb.Length; j++)\r
cb[j].Checked = GroupSettings[j].Contains(s.Id);\r
- cbp.Visible = true;\r
+ panel.Visible = true;\r
}\r
\r
private void SetRepairList(int i)\r
{\r
- var rpp = _repairPanelList[i];\r
- var s = _shipList[i];\r
+ var panel = _repairPanelList[i];\r
+ if (i + ScrollBar.Value >= _shipList.Length)\r
+ {\r
+ panel.Visible = false;\r
+ _labelPanelList[i].Visible = false;\r
+ return;\r
+ }\r
+ var s = _shipList[i + ScrollBar.Value];\r
if (s.Level == 1000)\r
{\r
+ panel.Visible = false;\r
SetShipType(i);\r
- rpp.Visible = false;\r
return;\r
}\r
- if (!rpp.Visible)\r
- rpp.Location = new Point(rpp.Left, (int)rpp.Tag + AutoScrollPosition.Y);\r
var rpl = _repairLabelList[i];\r
rpl[0].SetHp(s);\r
rpl[1].SetLevel(s);\r
rpl[2].SetRepairTime(s);\r
- rpl[3].Text = TimeSpan.FromSeconds(s.RepairSecPerHp).ToString(@"mm\:ss");\r
+ rpl[3].Text = s.RepairTimePerHp.ToString(@"mm\:ss");\r
rpl[4].SetName(s, ShipNameWidth.RepairListFull);\r
rpl[5].SetFleet(s);\r
- rpp.Visible = true;\r
+ panel.Visible = true;\r
}\r
\r
public void ShowShip(int id)\r
var i = Array.FindIndex(_shipList, s => s.Id == id);\r
if (i == -1)\r
return;\r
- var y = (int)Math.Round(ShipLabel.ScaleFactor.Height * LineHeight * i);\r
- AutoScrollPosition = new Point(0, y);\r
+ ScrollBar.Value = Min(i, ScrollBar.Maximum + 1 - ScrollBar.LargeChange);\r
+ SetShipLabels();\r
}\r
}\r
}
\ No newline at end of file