OSDN Git Service

対潜攻撃力に爆雷のシナジー効果を反映させる
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / ShipListPanel.cs
index 84bfe61..d924c7e 100644 (file)
@@ -16,44 +16,102 @@ using System;
 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
@@ -76,56 +134,99 @@ namespace KancolleSniffer
 \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
@@ -133,7 +234,6 @@ namespace KancolleSniffer
                 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
@@ -143,7 +243,7 @@ namespace KancolleSniffer
                 {\r
                     Location = new Point(91, 2),\r
                     Size = new Size(23, LabelHeight),\r
-                    TextAlign = ContentAlignment.MiddleRight,\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
@@ -162,9 +262,9 @@ namespace KancolleSniffer
                 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
@@ -185,11 +285,11 @@ namespace KancolleSniffer
             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
@@ -202,7 +302,6 @@ namespace KancolleSniffer
                 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
@@ -241,11 +340,9 @@ namespace KancolleSniffer
             {\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
@@ -283,42 +380,30 @@ namespace KancolleSniffer
             }\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
@@ -331,15 +416,12 @@ namespace KancolleSniffer
             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
@@ -348,51 +430,59 @@ namespace KancolleSniffer
             }\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
@@ -400,8 +490,8 @@ namespace KancolleSniffer
             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