OSDN Git Service

IUpdatableをIUpdateContextとIUpdateTimerに分離する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / View / BattleResultPanel.cs
index e3e9885..f1d0348 100644 (file)
@@ -23,28 +23,87 @@ using static System.Math;
 \r
 namespace KancolleSniffer.View\r
 {\r
-    public class BattleResultPanel : Panel\r
+    public class BattleResultPanel : PanelWithToolTip\r
     {\r
-        private const int LineHeight = 16;\r
-        private readonly List<ShipLabel[]> _friendLabels = new List<ShipLabel[]>();\r
-        private readonly List<ShipLabel[]> _enemyLabels = new List<ShipLabel[]>();\r
-        private readonly List<Panel> _panelList = new List<Panel>();\r
-        private readonly List<ShipLabel> _hpLabels = new List<ShipLabel>();\r
-        private readonly ResizableToolTip _toolTip = new ResizableToolTip {ShowAlways = true};\r
-        private readonly BattleInfo.BattleResult[] _result = new BattleInfo.BattleResult[2];\r
-        private Label _phaseLabel, _rankLabel, _cellLabel;\r
-        private BattleState _prevBattleState;\r
-        private readonly BattleResultRank[] _rank = new BattleResultRank[2];\r
-        private readonly InformationPanel _infomationPanel;\r
+        private readonly List<ShipLabels> _friendLabels = new List<ShipLabels>();\r
+        private readonly List<ShipLabels> _enemyLabels = new List<ShipLabels>();\r
+        private readonly List<ShipLabel.Hp> _hpLabels = new List<ShipLabel.Hp>();\r
+        private Label _phaseLabel, _rankLabel, _supportLabel, _cellLabel;\r
+        private readonly InformationPanel _information;\r
+        private CellInfo _cellInfo;\r
+        private readonly BattleData _data = new BattleData();\r
 \r
         public Spoiler Spoilers { get; set; }\r
 \r
+        private class BattleData\r
+        {\r
+            private Result _day;\r
+            private Result _night;\r
+            public int[] Formation;\r
+            public Range FighterPower;\r
+            public EnemyFighterPower EnemyFighterPower;\r
+            public int AirControlLevel;\r
+            public int SupportType;\r
+            public bool HaveDay => _day != null;\r
+            public bool HaveNight => _night != null;\r
+\r
+            public class Result\r
+            {\r
+                public BattleInfo.BattleResult Damage;\r
+                public BattleResultRank Rank;\r
+            }\r
+\r
+            public Result GetResult(BattleState state)\r
+            {\r
+                switch (state)\r
+                {\r
+                    case BattleState.Day:\r
+                    case BattleState.AirRaid:\r
+                        return _day;\r
+                    case BattleState.SpNight:\r
+                    case BattleState.Night:\r
+                        return _night;\r
+                    default:\r
+                        return _day;\r
+                }\r
+            }\r
+\r
+            public void SetData(BattleInfo battle)\r
+            {\r
+                switch (battle.BattleState)\r
+                {\r
+                    case BattleState.Day:\r
+                    case BattleState.AirRaid:\r
+                        _day = new Result {Damage = battle.Result, Rank = battle.ResultRank};\r
+                        _night = null;\r
+                        break;\r
+                    case BattleState.SpNight:\r
+                        _day = null;\r
+                        goto case BattleState.Night;\r
+                    case BattleState.Night:\r
+                        _night = new Result {Damage = battle.Result, Rank = battle.ResultRank};\r
+                        break;\r
+                }\r
+                if (battle.BattleState != BattleState.Night)\r
+                    SetNonStateData(battle);\r
+            }\r
+\r
+            private void SetNonStateData(BattleInfo battle)\r
+            {\r
+                Formation = battle.Formation;\r
+                FighterPower = battle.FighterPower;\r
+                EnemyFighterPower = battle.EnemyFighterPower;\r
+                AirControlLevel = battle.AirControlLevel;\r
+                SupportType = battle.SupportType;\r
+            }\r
+        }\r
+\r
         public BattleResultPanel()\r
         {\r
             SuspendLayout();\r
             CreateLabels();\r
-            _infomationPanel = new InformationPanel();\r
-            Controls.Add(_infomationPanel);\r
+            _information = new InformationPanel();\r
+            Controls.Add(_information);\r
             ResumeLayout();\r
         }\r
 \r
@@ -64,53 +123,41 @@ namespace KancolleSniffer.View
         public void Update(Sniffer sniffer)\r
         {\r
             var state = sniffer.Battle.BattleState;\r
-            var prev = _prevBattleState;\r
-            _prevBattleState = state;\r
-            if (prev == BattleState.None && state != BattleState.None)\r
-                _result[0] = _result[1] = null;\r
-            if (prev != BattleState.None && state == BattleState.None &&\r
-                !(_result[0] == null && _result[1] == null))\r
+            _cellInfo = sniffer.CellInfo;\r
+            switch (sniffer.Battle.BattleState)\r
             {\r
-                ClearResult();\r
-                SetPhase("結果");\r
-                return;\r
+                case BattleState.None:\r
+                    if (!_data.HaveDay && !_data.HaveNight)\r
+                        return;\r
+                    ClearResult();\r
+                    SetPhase("結果");\r
+                    UpdateCellInfo(_cellInfo);\r
+                    return;\r
+                case BattleState.Result:\r
+                case BattleState.Unknown:\r
+                    return;\r
             }\r
-            if (state != BattleState.Day && state != BattleState.Night)\r
-                return;\r
+            _data.SetData(sniffer.Battle);\r
             if ((Spoilers & Spoiler.BattleResult) != 0)\r
             {\r
-                ShowResult(sniffer.Battle.Result);\r
-                ShowResultRank(sniffer.Battle.ResultRank);\r
-                if (state == BattleState.Day)\r
-                {\r
-                    _result[0] = sniffer.Battle.Result;\r
-                    _rank[0] = sniffer.Battle.ResultRank;\r
-                    SetPhase("昼戦");\r
-                }\r
-                else if (state == BattleState.Night)\r
+                ShowData(sniffer.Battle.BattleState);\r
+                switch (state)\r
                 {\r
-                    _result[1] = sniffer.Battle.Result;\r
-                    _rank[1] = sniffer.Battle.ResultRank;\r
-                    SetPhase("夜戦");\r
+                    case BattleState.Day:\r
+                    case BattleState.AirRaid:\r
+                        SetPhase("昼戦");\r
+                        break;\r
+                    case BattleState.Night:\r
+                    case BattleState.SpNight:\r
+                        SetPhase("夜戦");\r
+                        break;\r
                 }\r
-                _infomationPanel.Visible = true;\r
             }\r
             else\r
             {\r
                 ClearResult();\r
                 SetPhase("結果");\r
-                if (state == BattleState.Day)\r
-                {\r
-                    _result[0] = sniffer.Battle.Result;\r
-                    _rank[0] = sniffer.Battle.ResultRank;\r
-                }\r
-                else if (state == BattleState.Night)\r
-                {\r
-                    _result[1] = sniffer.Battle.Result;\r
-                    _rank[1] = sniffer.Battle.ResultRank;\r
-                }\r
             }\r
-            _infomationPanel.SetInformation(sniffer.Battle);\r
         }\r
 \r
         private void PhaseLabelClick(object sender, EventArgs ev)\r
@@ -118,32 +165,28 @@ namespace KancolleSniffer.View
             switch (_phaseLabel.Text)\r
             {\r
                 case "結果":\r
-                    if (_result[0] != null)\r
+                    if (_data.HaveDay)\r
                     {\r
-                        ShowResult(_result[0]);\r
-                        ShowResultRank(_rank[0]);\r
+                        ShowData(BattleState.Day);\r
                         SetPhase("昼戦");\r
                     }\r
-                    else if (_result[1] != null)\r
+                    else if (_data.HaveNight)\r
                     {\r
-                        ShowResult(_result[1]);\r
-                        ShowResultRank(_rank[1]);\r
+                        ShowData(BattleState.Night);\r
                         SetPhase("夜戦");\r
                     }\r
                     break;\r
                 case "昼戦":\r
-                    if (_result[1] != null)\r
+                    if (_data.HaveNight)\r
                     {\r
-                        ShowResult(_result[1]);\r
-                        ShowResultRank(_rank[1]);\r
+                        ShowData(BattleState.Night);\r
                         SetPhase("夜戦");\r
                     }\r
                     break;\r
                 case "夜戦":\r
-                    if (_result[0] != null)\r
+                    if (_data.HaveDay)\r
                     {\r
-                        ShowResult(_result[0]);\r
-                        ShowResultRank(_rank[0]);\r
+                        ShowData(BattleState.Day);\r
                         SetPhase("昼戦");\r
                     }\r
                     break;\r
@@ -153,7 +196,7 @@ namespace KancolleSniffer.View
         private void SetPhase(string phase)\r
         {\r
             _phaseLabel.Text = phase;\r
-            if (phase == "結果" || _result[0] != null && _result[1] != null)\r
+            if (phase == "結果" || _data.HaveDay && _data.HaveNight)\r
             {\r
                 _phaseLabel.BorderStyle = BorderStyle.FixedSingle;\r
                 _phaseLabel.Cursor = Cursors.Hand;\r
@@ -170,110 +213,87 @@ namespace KancolleSniffer.View
         private void ClearResult()\r
         {\r
             _scrollPosition = AutoScrollPosition;\r
-            foreach (var panel in _panelList)\r
-                panel.Visible = false;\r
-            _infomationPanel.Visible = false;\r
+            SetPanelVisible(0);\r
+            _information.Visible = false;\r
             _rankLabel.Text = "";\r
+            _supportLabel.Text = "";\r
+        }\r
+\r
+        private void ShowData(BattleState state)\r
+        {\r
+            var result = _data.GetResult(state);\r
+            ShowDamage(result.Damage);\r
+            ShowResultRank(result.Rank);\r
+            _information.Show(_data);\r
+            ShowSupportType(_data.SupportType);\r
+            UpdateCellInfo(_cellInfo);\r
+            AutoScrollPosition = new Point(-_scrollPosition.X, -_scrollPosition.Y);\r
         }\r
 \r
-        private void ShowResult(BattleInfo.BattleResult result)\r
+        private void ShowDamage(BattleInfo.BattleResult result)\r
         {\r
             SuspendLayout();\r
-            AutoScrollPosition = _scrollPosition;\r
-            var friend = result.Friend;\r
-            var enemy = result.Enemy;\r
-            for (var i = 0; i < friend.Main.Length; i++)\r
-            {\r
-                var labels = _friendLabels[i];\r
-                var ship = friend.Main[i];\r
-                labels[0].SetHp(ship);\r
-                labels[1].SetName(ship, ShipNameWidth.BattleResult);\r
-                _toolTip.SetToolTip(labels[1], GetEqipString(ship));\r
-            }\r
-            if (friend.Guard.Length > 0)\r
+            SetEachResult(_friendLabels, result.Friend);\r
+            SetEachResult(_enemyLabels, result.Enemy);\r
+            var lines = Max(Ships(result.Friend).Length, Ships(result.Enemy).Length);\r
+            SetPanelVisible(lines);\r
+            ResumeLayout(); // スクロールバーの有無を決定する\r
+            AdjustPanelWidth(lines);\r
+        }\r
+\r
+        private void SetEachResult(IReadOnlyList<ShipLabels> labelsList, BattleInfo.BattleResult.Combined fleet)\r
+        {\r
+            var ships = Ships(fleet);\r
+            for (var i = 0; i < ships.Length; i++)\r
             {\r
-                _friendLabels[friend.Main.Length][1].Text = "護衛";\r
-                _friendLabels[friend.Main.Length][0].SetHp(null);\r
-                for (var i = 0; i < friend.Guard.Length; i++)\r
+                var labels = labelsList[i];\r
+                if (i == fleet.Main.Length)\r
                 {\r
-                    var labels = _friendLabels[friend.Main.Length + 1 + i];\r
-                    var ship = friend.Guard[i];\r
-                    labels[0].SetHp(ship);\r
-                    labels[1].SetName(ship, ShipNameWidth.BattleResult);\r
-                    _toolTip.SetToolTip(labels[1], GetEqipString(ship));\r
+                    labels.Name.Text = "護衛";\r
+                    labels.Hp.Reset();\r
+                    continue;\r
                 }\r
-            }\r
-            var friendLines = friend.Main.Length + (friend.Guard.Length > 0 ? friend.Guard.Length + 1 : 0);\r
-            for (var i = friendLines; i < _friendLabels.Count; i++)\r
-            {\r
-                _friendLabels[i][0].SetHp(null);\r
-                _friendLabels[i][1].SetName("");\r
-            }\r
-            for (var i = 0; i < enemy.Main.Length; i++)\r
-            {\r
-                var labels = _enemyLabels[i];\r
-                var ship = enemy.Main[i];\r
-                labels[0].SetHp(ship);\r
-                labels[1].SetName(ShortenName(ship.Name));\r
-                _toolTip.SetToolTip(labels[1], GetEqipString(ship));\r
-            }\r
-            if (enemy.Guard.Length > 0)\r
-            {\r
-                _enemyLabels[enemy.Main.Length][1].Text = "護衛";\r
-                _enemyLabels[enemy.Main.Length][0].SetHp(null);\r
-                for (var i = 0; i < enemy.Guard.Length; i++)\r
+                var ship = ships[i];\r
+                if (ShipMaster.IsEnemyId(ship.Spec.Id))\r
                 {\r
-                    var labels = _enemyLabels[enemy.Main.Length + 1 + i];\r
-                    var ship = enemy.Guard[i];\r
-                    labels[0].SetHp(ship);\r
-                    labels[1].SetName(ShortenName(ship.Name));\r
-                    _toolTip.SetToolTip(labels[1], GetEqipString(ship));\r
+                    labels.Hp.Set(ship);\r
+                    labels.Name.SetName(ShortenName(ship.Name));\r
                 }\r
+                else\r
+                {\r
+                    labels.Set(ship);\r
+                    if (ship.Name.StartsWith("基地航空隊"))\r
+                        labels.Name.SetName(ship.Name.Substring(2));\r
+                }\r
+                ToolTip.SetToolTip(labels.Name, GetEquipString(ship));\r
             }\r
-            var enemyLines = enemy.Main.Length + (enemy.Guard.Length > 0 ? enemy.Guard.Length + 1 : 0);\r
-            for (var i = enemyLines; i < _enemyLabels.Count; i++)\r
-            {\r
-                _enemyLabels[i][0].SetHp(null);\r
-                _enemyLabels[i][1].SetName("");\r
-            }\r
-            var lines = Max(friendLines, enemyLines);\r
-            for (var i = 0; i < lines; i++)\r
-            {\r
-                var panel = _panelList[i];\r
-                if (panel.Visible)\r
-                    continue;\r
-                panel.Location = new Point(AutoScrollPosition.X,\r
-                    (int)Round((int)panel.Tag * ShipLabel.ScaleFactor.Height) + AutoScrollPosition.Y);\r
-                panel.Visible = true;\r
-            }\r
-            for (var i = lines; i < _panelList.Count; i++)\r
-                _panelList[i].Visible = false;\r
-            ResumeLayout(); // スクロールバーの有無を決定する\r
-            var panelWidth = Max(ClientSize.Width, // スクロールバーの有無を反映した横幅\r
-                _enemyLabels[0][1].Location.X + _enemyLabels.Max(labels => labels[1].Size.Width) - 1); // 敵の名前の右端\r
-            for (var i = 0; i < lines; i++)\r
-                _panelList[i].Width = panelWidth;\r
-            _infomationPanel.Location = new Point(\r
-                (int)Round(0 * ShipLabel.ScaleFactor.Width) + AutoScrollPosition.X,\r
-                (int)Round(20 * ShipLabel.ScaleFactor.Height) + AutoScrollPosition.Y);\r
-            _infomationPanel.Visible = true;\r
+            for (var i = ships.Length; i < labelsList.Count; i++)\r
+                labelsList[i].Reset();\r
         }\r
 \r
-        private string GetEqipString(ShipStatus ship)\r
+        private static ShipStatus[] Ships(BattleInfo.BattleResult.Combined fleet)\r
+        {\r
+            if (fleet.Guard.Length == 0)\r
+                return fleet.Main;\r
+            return fleet.Main.Concat(new[] {new ShipStatus()}.Concat(fleet.Guard)).ToArray();\r
+        }\r
+\r
+        private static string GetEquipString(ShipStatus ship)\r
         {\r
             var result =\r
-            (from i in Enumerable.Range(0, ship.Slot.Length)\r
-                let item = ship.Slot[i]\r
-                where !item.Empty\r
-                select item.Spec.Name + (item.Spec.IsAircraft && ship.OnSlot.Length > 0 && ship.Spec.MaxEq.Length > 0\r
-                           ? $"{ship.OnSlot[i]}/{ship.Spec.MaxEq[i]}"\r
-                           : ""));\r
+                (from i in Enumerable.Range(0, ship.Slot.Count)\r
+                    let item = ship.Slot[i]\r
+                    where !item.Empty\r
+                    select item.Spec.Name +\r
+                           (item.Spec.IsAircraft && ship.OnSlot.Length > 0 && ship.Spec.MaxEq.Length > 0\r
+                               ? $"{ship.OnSlot[i]}/{ship.Spec.MaxEq[i]}"\r
+                               : ""));\r
             if (ship.SlotEx.Id > 0)\r
                 result = result.Concat(new[] {ship.SlotEx.Spec.Name});\r
             return string.Join("\r\n", result);\r
         }\r
 \r
-        private string ShortenName(string name)\r
+        private static string ShortenName(string name)\r
         {\r
             return new Regex(@"\(elite\)|\(flagship\)").Replace(name,\r
                 match => match.Value == "(elite)" ? "(e)" : "(f)");\r
@@ -285,86 +305,97 @@ namespace KancolleSniffer.View
             _rankLabel.Text = result[(int)rank];\r
         }\r
 \r
-        public void UpdateCellInfo(Sniffer sniffer)\r
+        private void ShowSupportType(int support)\r
         {\r
-            var text = sniffer.CellInfo;\r
-            if (text == null)\r
-                return;\r
-            _cellLabel.Text = (Spoilers & Spoiler.NextCell) == 0 ? sniffer.CellInfo.Current : sniffer.CellInfo.Next;\r
-            _cellLabel.Location = new Point(ClientSize.Width - _cellLabel.Width - 2, 4);\r
+            _supportLabel.Text = new[] {"", "空支援", "砲支援", "雷支援", "潜支援"}[support];\r
         }\r
 \r
+        public void UpdateCellInfo(CellInfo cellInfo)\r
+        {\r
+            _cellLabel.Text = (Spoilers & Spoiler.NextCell) == 0 ? cellInfo.Current : cellInfo.Next;\r
+            _cellLabel.Location = new Point(ClientSize.Width - _cellLabel.Width - 2, _cellLabel.Location.Y);\r
+        }\r
+\r
+        private const int LineHeight = 16;\r
+        private const int LabelHeight = 12;\r
+        private const int LabelMargin = (LineHeight - LabelHeight) / 2;\r
+        private const int TopMargin = 4;\r
+\r
         private void CreateLabels()\r
         {\r
             _phaseLabel = new Label\r
             {\r
-                Location = new Point(4, 4),\r
-                Size = new Size(31, 14)\r
+                Location = new Point(4, TopMargin),\r
+                Size = new Size(31, LabelHeight + 2)\r
             };\r
             _phaseLabel.Click += PhaseLabelClick;\r
             Controls.Add(_phaseLabel);\r
             _rankLabel = new Label\r
             {\r
-                Location = new Point(37, 4),\r
-                Size = new Size(42, 12)\r
+                Location = new Point(37, TopMargin),\r
+                Size = new Size(42, LabelHeight)\r
             };\r
             Controls.Add(_rankLabel);\r
+            _supportLabel = new Label\r
+            {\r
+                Location = new Point(77, TopMargin),\r
+                AutoSize = true\r
+            };\r
+            Controls.Add(_supportLabel);\r
             _cellLabel = new Label\r
             {\r
-                Location = new Point(0, 4),\r
+                Location = new Point(0, TopMargin),\r
                 AutoSize = true\r
             };\r
             Controls.Add(_cellLabel);\r
             for (var i = 0; i < 13; i++)\r
             {\r
-                var y = LineHeight * i + 38;\r
-                var panel = new Panel\r
+                var friend = new ShipLabels\r
                 {\r
-                    Location = new Point(0, y),\r
-                    Size = new Size(0, LineHeight),\r
-                    BackColor = ShipLabel.ColumnColors[i % 2],\r
-                    Visible = false,\r
-                    Tag = y\r
-                };\r
-                _panelList.Add(panel);\r
-\r
-                var friend = new[]\r
-                {\r
-                    new ShipLabel\r
+                    Name = new ShipLabel.Name(new Point(1, LabelMargin), ShipNameWidth.BattleResult),\r
+                    Hp = new ShipLabel.Hp(new Point(101, 0), LineHeight),\r
+                    BackPanel = new Panel\r
                     {\r
-                        Location = new Point(101, 0),\r
-                        AutoSize = true,\r
-                        AnchorRight = true,\r
-                        MinimumSize = new Size(0, LineHeight),\r
-                        TextAlign = ContentAlignment.MiddleLeft,\r
-                        Cursor = Cursors.Hand\r
-                    },\r
-                    new ShipLabel {Location = new Point(1, 2), AutoSize = true}\r
+                        Location = new Point(0, LineHeight * i + 38),\r
+                        Size = new Size(0, LineHeight),\r
+                        BackColor = CustomColors.ColumnColors.DarkFirst(i),\r
+                        Visible = false\r
+                    }\r
                 };\r
                 _friendLabels.Add(friend);\r
-                _hpLabels.Add(friend[0]);\r
-                friend[0].Click += HpLabelClickHandler;\r
-                var enemy = new[]\r
+                friend.Arrange(this, CustomColors.ColumnColors.DarkFirst(i));\r
+                _hpLabels.Add(friend.Hp);\r
+                friend.Hp.Click += HpLabelClickHandler;\r
+                var enemy = new ShipLabels\r
                 {\r
-                    new ShipLabel\r
+                    Name = new ShipLabel.Name(new Point(164, LabelMargin), ShipNameWidth.Max),\r
+                    Hp = new ShipLabel.Hp\r
                     {\r
                         Location = new Point(119, 0),\r
                         AutoSize = true,\r
                         MinimumSize = new Size(0, LineHeight),\r
                         TextAlign = ContentAlignment.MiddleLeft\r
-                    },\r
-                    new ShipLabel {Location = new Point(164, 2), AutoSize = true}\r
+                    }\r
                 };\r
                 _enemyLabels.Add(enemy);\r
-                foreach (var label in friend.Concat(enemy))\r
-                {\r
-                    panel.Controls.Add(label);\r
-                    label.BackColor = label.PresetColor = ShipLabel.ColumnColors[i % 2];\r
-                }\r
-                Controls.Add(panel);\r
+                enemy.Arrange(friend.BackPanel, CustomColors.ColumnColors.DarkFirst(i));\r
             }\r
         }\r
 \r
+        private void SetPanelVisible(int showPanels)\r
+        {\r
+            for (var i = 0; i < _friendLabels.Count; i++)\r
+                _friendLabels[i].BackPanel.Visible = i < showPanels;\r
+        }\r
+\r
+        private void AdjustPanelWidth(int lines)\r
+        {\r
+            var panelWidth = Max(ClientSize.Width, // スクロールバーの有無を反映した横幅\r
+                _enemyLabels[0].Name.Location.X + _enemyLabels.Max(labels => labels.Name.Size.Width) - 1); // 敵の名前の右端\r
+            for (var i = 0; i < lines; i++)\r
+                _friendLabels[i].BackPanel.Width = panelWidth;\r
+        }\r
+\r
         protected override void OnMouseWheel(MouseEventArgs e)\r
         {\r
             if (VScroll && (ModifierKeys & Keys.Shift) == Keys.Shift)\r
@@ -377,127 +408,156 @@ namespace KancolleSniffer.View
             base.OnMouseWheel(e);\r
         }\r
 \r
-        protected override void ScaleControl(SizeF factor, BoundsSpecified specified)\r
-        {\r
-            base.ScaleControl(factor, specified);\r
-            if (factor.Height > 1)\r
-                _toolTip.Font = new Font(_toolTip.Font.FontFamily, _toolTip.Font.Size * factor.Height);\r
-        }\r
-\r
-        private class InformationPanel : Panel\r
+        private sealed class InformationPanel : PanelWithToolTip\r
         {\r
-            private readonly Label[] _formation;\r
-            private readonly Label[] _fighterPower;\r
-            private readonly ResizableToolTip _toolTip = new ResizableToolTip {ShowAlways = true};\r
+            private readonly Formation _formation;\r
+            private readonly FighterPower _fighterPower;\r
 \r
             public InformationPanel()\r
             {\r
-                Visible = false;\r
-                Size = new Size(206, 16);\r
-                Controls.AddRange(_formation = new[]\r
+                _formation = new Formation\r
                 {\r
-                    new Label\r
+                    Friend = new Label\r
                     {\r
-                        Location = new Point(47, 2),\r
-                        Size = new Size(29, 12)\r
+                        Location = new Point(47, LabelMargin),\r
+                        Size = new Size(29, LabelHeight)\r
                     },\r
-                    new Label\r
+                    Enemy = new Label\r
                     {\r
-                        Location = new Point(75, 2),\r
-                        Size = new Size(29, 12)\r
+                        Location = new Point(75, LabelMargin),\r
+                        Size = new Size(29, LabelHeight)\r
                     },\r
-                    new Label\r
+                    State = new Label\r
                     {\r
-                        Location = new Point(1, 2),\r
-                        Size = new Size(48, 12),\r
+                        Location = new Point(1, LabelMargin),\r
+                        Size = new Size(48, LabelHeight),\r
                         TextAlign = ContentAlignment.MiddleCenter\r
                     }\r
-                });\r
-                Controls.AddRange(_fighterPower = new[]\r
+                };\r
+                Controls.AddRange(_formation.Controls);\r
+                _fighterPower = new FighterPower\r
                 {\r
-                    new Label\r
+                    ToolTip = ToolTip,\r
+                    Friend = new Label\r
                     {\r
-                        Location = new Point(162, 2),\r
-                        Size = new Size(23, 12),\r
+                        Location = new Point(162, LabelMargin),\r
+                        Size = new Size(23, LabelHeight),\r
                         TextAlign = ContentAlignment.MiddleRight\r
                     },\r
-                    new Label\r
+                    Enemy = new Label\r
                     {\r
-                        Location = new Point(183, 2),\r
-                        Size = new Size(23, 12),\r
+                        Location = new Point(183, LabelMargin),\r
+                        Size = new Size(23, LabelHeight),\r
                         TextAlign = ContentAlignment.MiddleRight\r
                     },\r
-                    new Label\r
+                    State = new Label\r
                     {\r
-                        Location = new Point(110, 2),\r
-                        Size = new Size(53, 12)\r
+                        Location = new Point(110, LabelMargin),\r
+                        Size = new Size(53, LabelHeight)\r
                     }\r
-                });\r
-                // ReSharper disable once VirtualMemberCallInConstructor\r
-                BackColor = ShipLabel.ColumnColors[1];\r
+                };\r
+                Controls.AddRange(_fighterPower.Controls);\r
+                Location = new Point(0, 20);\r
+                Size = new Size(206, 16);\r
+                BackColor = CustomColors.ColumnColors.Bright;\r
+                Visible = false;\r
             }\r
 \r
-            public void SetInformation(BattleInfo battleInfo)\r
+            public void Show(BattleData data)\r
             {\r
-                _formation[0].Text = FormationName(battleInfo.Formation[0]);\r
-                _formation[1].Text = FormationName(battleInfo.Formation[1]);\r
-                _formation[2].Text = new[] {"同航戦", "反航戦", "T字有利", "T字不利"}[battleInfo.Formation[2] - 1];\r
+                SetData(data);\r
+                Visible = true;\r
+            }\r
 \r
-                if (battleInfo.AirControlLevel == -1)\r
-                {\r
-                    if (battleInfo.BattleState == BattleState.Night)\r
-                        return;\r
-                    foreach (var label in _fighterPower)\r
-                        label.Visible = false;\r
-                    return;\r
-                }\r
-                var fp = battleInfo.FighterPower;\r
-                _fighterPower[0].Text = fp[0].ToString("D");\r
-                _toolTip.SetToolTip(_fighterPower[0], fp[0] == fp[1] ? "" : $"{fp[0]}~{fp[1]}");\r
-                var efp = battleInfo.EnemyFighterPower;\r
-                _fighterPower[1].Text = efp.AirCombat + efp.UnknownMark;\r
-                _toolTip.SetToolTip(_fighterPower[1],\r
-                    efp.AirCombat == efp.Interception ? "" : "防空:" + efp.Interception + efp.UnknownMark);\r
-                _fighterPower[2].Text =\r
-                    new[] {"", "制空均衡", "制空確保", "航空優勢", "航空劣勢", "制空喪失"}[battleInfo.AirControlLevel + 1];\r
-                foreach (var label in _fighterPower)\r
-                    label.Visible = true;\r
+            private void SetData(BattleData data)\r
+            {\r
+                _formation.SetFormation(data.Formation);\r
+                _fighterPower.SetFighterPower(data);\r
             }\r
 \r
-            private string FormationName(int formation)\r
+            private class StateLabels\r
             {\r
-                switch (formation)\r
+                public Label Friend;\r
+                public Label Enemy;\r
+                public Label State;\r
+\r
+                public Control[] Controls => new Control[] {Friend, Enemy, State};\r
+            }\r
+\r
+            private class Formation : StateLabels\r
+            {\r
+                public void SetFormation(int[] formation)\r
                 {\r
-                    case 1:\r
-                        return "単縦";\r
-                    case 2:\r
-                        return "複縦";\r
-                    case 3:\r
-                        return "輪形";\r
-                    case 4:\r
-                        return "梯形";\r
-                    case 5:\r
-                        return "単横";\r
-                    case 6:\r
-                        return "警戒";\r
-                    case 11:\r
-                        return "第一";\r
-                    case 12:\r
-                        return "第二";\r
-                    case 13:\r
-                        return "第三";\r
-                    case 14:\r
-                        return "第四";\r
-                    default:\r
-                        return "";\r
+                    Friend.Text = FormationName(formation[0]);\r
+                    Enemy.Text = FormationName(formation[1]);\r
+                    State.Text = new[] {"同航戦", "反航戦", "T字有利", "T字不利"}[formation[2] - 1];\r
+                }\r
+\r
+                private static string FormationName(int formation)\r
+                {\r
+                    switch (formation)\r
+                    {\r
+                        case 1:\r
+                            return "単縦";\r
+                        case 2:\r
+                            return "複縦";\r
+                        case 3:\r
+                            return "輪形";\r
+                        case 4:\r
+                            return "梯形";\r
+                        case 5:\r
+                            return "単横";\r
+                        case 6:\r
+                            return "警戒";\r
+                        case 11:\r
+                            return "第一";\r
+                        case 12:\r
+                            return "第二";\r
+                        case 13:\r
+                            return "第三";\r
+                        case 14:\r
+                            return "第四";\r
+                        default:\r
+                            return "";\r
+                    }\r
                 }\r
             }\r
 \r
-            protected override void ScaleControl(SizeF factor, BoundsSpecified specified)\r
+            private class FighterPower : StateLabels\r
             {\r
-                base.ScaleControl(factor, specified);\r
-                if (factor.Height > 1)\r
-                    _toolTip.Font = new Font(_toolTip.Font.FontFamily, _toolTip.Font.Size * factor.Height);\r
+                public ToolTip ToolTip { private get; set; }\r
+\r
+                public void SetFighterPower(BattleData data)\r
+                {\r
+                    if (data.AirControlLevel == -1)\r
+                    {\r
+                        foreach (var control in Controls)\r
+                            control.Text = "";\r
+                        return;\r
+                    }\r
+                    SetFriend(data.FighterPower);\r
+                    SetEnemy(data.EnemyFighterPower);\r
+                    SetAirControlLevel(data.AirControlLevel);\r
+                }\r
+\r
+                private void SetFriend(Range fighterPower)\r
+                {\r
+                    Friend.Text = fighterPower.Min.ToString();\r
+                    ToolTip.SetToolTip(Friend, fighterPower.Diff ? fighterPower.RangeString : "");\r
+                }\r
+\r
+                private void SetEnemy(EnemyFighterPower enemy)\r
+                {\r
+                    Enemy.Text = enemy.AirCombat + enemy.UnknownMark;\r
+                    ToolTip.SetToolTip(Enemy,\r
+                        enemy.AirCombat == enemy.Interception ? "" : "防空:" + enemy.Interception + enemy.UnknownMark);\r
+                }\r
+\r
+                private void SetAirControlLevel(int level)\r
+                {\r
+                    State.Text =\r
+                        new[] {"", "制空均衡", "制空確保", "航空優勢", "航空劣勢", "制空喪失"}[level + 1];\r
+                }\r
             }\r
         }\r
     }\r