OSDN Git Service

ズーム時にメインウィンドウで経験値とレベルが重なるのを直す
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / ShipLabels.cs
index 353b6b5..8d0a742 100644 (file)
@@ -14,6 +14,7 @@
 \r
 using System;\r
 using System.Collections.Generic;\r
+using System.ComponentModel;\r
 using System.Drawing;\r
 using System.Linq;\r
 using System.Text.RegularExpressions;\r
@@ -22,62 +23,89 @@ using static System.Math;
 \r
 namespace KancolleSniffer\r
 {\r
+    public enum ShipNameWidth\r
+    {\r
+        MainPanel = 93,\r
+        AkashiTimer = 53,\r
+        NDock = 69,\r
+        RepairList = NDock,\r
+        RepairListFull = 75,\r
+        ShipList = 82,\r
+        GroupConfig = 82,\r
+        Combined = 54,\r
+        BattleResult = 65,\r
+        CiShipName = 65,\r
+        Max = int.MaxValue\r
+    }\r
+\r
     public class ShipLabels\r
     {\r
-        private readonly ShipLabel[][] _labels = new ShipLabel[ShipInfo.MemberCount][];\r
+        private readonly ShipLabel[][] _shiplabels = new ShipLabel[ShipInfo.MemberCount][];\r
+        private readonly ShipLabel[][] _shipLabels7 = new ShipLabel[7][];\r
         private readonly ShipLabel[][] _combinedLabels = new ShipLabel[ShipInfo.MemberCount * 2][];\r
         private readonly ShipLabel[] _akashiTimers = new ShipLabel[ShipInfo.MemberCount];\r
-        private readonly ShipLabel[][] _damagedShipList = new ShipLabel[16][];\r
-        private Control _panelDamagedShipList;\r
+        private readonly ShipLabel[] _akashiTimers7 = new ShipLabel[ShipInfo.MemberCount];\r
         private readonly ShipLabel[][] _ndockLabels = new ShipLabel[DockInfo.DockCount][];\r
         public static Color[] ColumnColors = {SystemColors.Control, Color.FromArgb(255, 250, 250, 250)};\r
+        private readonly List<ShipLabel> _hpLables = new List<ShipLabel>();\r
+        public bool ShowHpInPercent { get; private set; }\r
+\r
+        public void CreateShipLabels(Control parent, EventHandler onClick)\r
+        {\r
+            CreateShipLabels(parent, onClick, _shiplabels, 16);\r
+        }\r
 \r
-        public void CreateLabels(Control parent, EventHandler onClick)\r
+        public void CreateShipLabels7(Control parent, EventHandler onClick)\r
+        {\r
+            CreateShipLabels(parent, onClick, _shipLabels7, 14);\r
+        }\r
+\r
+        public void CreateShipLabels(Control parent, EventHandler onClick, ShipLabel[][] shipLabels, int lineHeight)\r
         {\r
             parent.SuspendLayout();\r
-            const int top = 3, height = 12, lh = 16;\r
+            const int top = 3, height = 12;\r
             ShipLabel[] headings;\r
             parent.Controls.AddRange(headings = new[]\r
             {\r
                 new ShipLabel {Location = new Point(109, top), Text = "HP", AutoSize = true},\r
                 new ShipLabel {Location = new Point(128, top), Text = "cond", AutoSize = true},\r
-                new ShipLabel {Location = new Point(163, top), Text = "Lv", AutoSize = true},\r
+                new ShipLabel {Location = new Point(162, top), Text = "Lv", AutoSize = true},\r
                 new ShipLabel {Location = new Point(194, top), Text = "Exp", AutoSize = true},\r
-                new ShipLabel {Location = new Point(0, 1), Size = new Size(parent.Width, lh - 1)}\r
+                new ShipLabel {Location = new Point(0, 1), Size = new Size(parent.Width, lineHeight - 1)}\r
             });\r
             foreach (var label in headings)\r
             {\r
                 label.Scale();\r
                 label.BackColor = ColumnColors[1];\r
             }\r
-            for (var i = 0; i < _labels.Length; i++)\r
+            for (var i = 0; i < shipLabels.Length; i++)\r
             {\r
-                var y = top + lh * (i + 1);\r
-                parent.Controls.AddRange(_labels[i] = new[]\r
+                var y = top + lineHeight * (i + 1);\r
+                parent.Controls.AddRange(shipLabels[i] = new[]\r
                 {\r
                     new ShipLabel {Location = new Point(129, y), AutoSize = true, AnchorRight = true},\r
                     new ShipLabel\r
                     {\r
-                        Location = new Point(132, y),\r
-                        Size = new Size(23, height),\r
+                        Location = new Point(131, y),\r
+                        Size = new Size(24, height),\r
                         TextAlign = ContentAlignment.MiddleRight\r
                     },\r
                     new ShipLabel\r
                     {\r
-                        Location = new Point(157, y),\r
-                        Size = new Size(23, height),\r
+                        Location = new Point(155, y),\r
+                        Size = new Size(24, height),\r
                         TextAlign = ContentAlignment.MiddleRight\r
                     },\r
                     new ShipLabel\r
                     {\r
-                        Location = new Point(177, y),\r
-                        Size = new Size(41, height),\r
+                        Location = new Point(176, y),\r
+                        Size = new Size(42, height),\r
                         TextAlign = ContentAlignment.MiddleRight\r
                     },\r
                     new ShipLabel {Location = new Point(2, y), AutoSize = true}, // 名前のZ-orderを下に\r
-                    new ShipLabel {Location = new Point(0, y - 2), Size = new Size(parent.Width, lh - 1)}\r
+                    new ShipLabel {Location = new Point(0, y - 2), Size = new Size(parent.Width, lineHeight - 1)}\r
                 });\r
-                foreach (var label in _labels[i])\r
+                foreach (var label in shipLabels[i])\r
                 {\r
                     label.Scale();\r
                     label.PresetColor = label.BackColor = ColumnColors[i % 2];\r
@@ -85,29 +113,35 @@ namespace KancolleSniffer
                     label.Click += onClick;\r
                 }\r
             }\r
+            _hpLables.AddRange(shipLabels.Select(labels => labels[0]));\r
+            headings[0].Cursor = Cursors.Hand;\r
+            headings[0].Click += (sender, ev) => ToggleHpPercent();\r
             parent.ResumeLayout();\r
         }\r
 \r
-        public void SetShipInfo(ShipStatus[] statuses)\r
+        public void ToggleHpPercent()\r
         {\r
-            for (var i = 0; i < _labels.Length; i++)\r
+            ShowHpInPercent = !ShowHpInPercent;\r
+            foreach (var label in _hpLables)\r
+                label.ToggleHpPercent();\r
+        }\r
+\r
+        public void SetShipLabels(ShipStatus[] statuses)\r
+        {\r
+            SetShipLabels(statuses, statuses.Length == 7 ? _shipLabels7 : _shiplabels);\r
+        }\r
+\r
+        public void SetShipLabels(ShipStatus[] statuses, ShipLabel[][] shipLabels)\r
+        {\r
+            for (var i = 0; i < shipLabels.Length; i++)\r
             {\r
-                var labels = _labels[i];\r
-                if (i < statuses.Length)\r
-                {\r
-                    var s = statuses[i];\r
-                    labels[0].SetHp(s);\r
-                    labels[1].SetCond(s);\r
-                    labels[2].SetLevel(s);\r
-                    labels[3].SetExpToNext(s);\r
-                    labels[4].SetName(s);\r
-                }\r
-                else\r
-                {\r
-                    labels[0].Text = labels[1].Text = labels[2].Text = labels[3].Text = "";\r
-                    labels[4].SetName("");\r
-                    labels[0].BackColor = labels[1].BackColor = labels[0].PresetColor;\r
-                }\r
+                var labels = shipLabels[i];\r
+                var s = i < statuses.Length ? statuses[i] : null;\r
+                labels[0].SetHp(s);\r
+                labels[1].SetCond(s);\r
+                labels[2].SetLevel(s);\r
+                labels[3].SetExpToNext(s);\r
+                labels[4].SetName(s, ShipNameWidth.MainPanel);\r
             }\r
         }\r
 \r
@@ -115,6 +149,7 @@ namespace KancolleSniffer
         {\r
             parent.SuspendLayout();\r
             const int top = 3, height = 12, lh = 16;\r
+            const int parentWidth = 220; // parent.Widthを使うとDPIスケーリング時に計算がくるうので\r
             ShipLabel[] headings;\r
             parent.Controls.AddRange(headings = new[]\r
             {\r
@@ -122,7 +157,7 @@ namespace KancolleSniffer
                 new ShipLabel {Location = new Point(86, top), Text = "cnd", AutoSize = true},\r
                 new ShipLabel {Location = new Point(177, top), Text = "HP", AutoSize = true},\r
                 new ShipLabel {Location = new Point(195, top), Text = "cnd", AutoSize = true},\r
-                new ShipLabel {Location = new Point(0, 1), Size = new Size(parent.Width, lh - 1)}\r
+                new ShipLabel {Location = new Point(0, 1), Size = new Size(parentWidth, lh - 1)}\r
             });\r
             foreach (var label in headings)\r
             {\r
@@ -131,19 +166,19 @@ namespace KancolleSniffer
             }\r
             for (var i = 0; i < _combinedLabels.Length; i++)\r
             {\r
-                var x = (parent.Width / 2) * (i / ShipInfo.MemberCount);\r
-                var y = top + lh * ((i % ShipInfo.MemberCount) + 1);\r
+                var x = parentWidth / 2 * (i / ShipInfo.MemberCount);\r
+                var y = top + lh * (i % ShipInfo.MemberCount + 1);\r
                 parent.Controls.AddRange(_combinedLabels[i] = new[]\r
                 {\r
                     new ShipLabel {Location = new Point(x + 88, y), AutoSize = true, AnchorRight = true},\r
                     new ShipLabel\r
                     {\r
-                        Location = new Point(x + 86, y),\r
-                        Size = new Size(23, height),\r
+                        Location = new Point(x + 85, y),\r
+                        Size = new Size(24, height),\r
                         TextAlign = ContentAlignment.MiddleRight\r
                     },\r
                     new ShipLabel {Location = new Point(x + 2, y), AutoSize = true}, // 名前のZ-orderを下に\r
-                    new ShipLabel {Location = new Point(x, y - 2), Size = new Size(parent.Width / 2, lh - 1)}\r
+                    new ShipLabel {Location = new Point(x, y - 2), Size = new Size(parentWidth / 2, lh - 1)}\r
                 });\r
                 foreach (var label in _combinedLabels[i])\r
                 {\r
@@ -153,57 +188,100 @@ namespace KancolleSniffer
                     label.Click += onClick;\r
                 }\r
             }\r
+            _hpLables.AddRange(_combinedLabels.Select(record => record[0]).ToArray());\r
+            headings[0].Cursor = headings[2].Cursor = Cursors.Hand;\r
+            void HpToggle(object sender, EventArgs ev)\r
+            {\r
+                foreach (var label in _hpLables)\r
+                    label.ToggleHpPercent();\r
+            }\r
+            headings[0].Click += HpToggle;\r
+            headings[2].Click += HpToggle;\r
             parent.ResumeLayout();\r
         }\r
 \r
-        public void SetCombinedShipInfo(ShipStatus[] first, ShipStatus[] second)\r
+        public void SetCombinedShipLabels(ShipStatus[] first, ShipStatus[] second)\r
         {\r
             for (var i = 0; i < _combinedLabels.Length; i++)\r
             {\r
                 var idx = i % ShipInfo.MemberCount;\r
                 var statuses = i < ShipInfo.MemberCount ? first : second;\r
                 var labels = _combinedLabels[i];\r
-                if (idx < statuses.Length)\r
-                {\r
-                    var s = statuses[idx];\r
-                    labels[0].SetHp(s);\r
-                    labels[1].SetCond(s);\r
-                    labels[2].SetName(s);\r
-                }\r
-                else\r
-                {\r
-                    labels[0].Text = labels[1].Text = "";\r
-                    labels[2].SetName("");\r
-                    labels[0].BackColor = labels[1].BackColor = labels[0].PresetColor;\r
-                }\r
+                var s = idx < statuses.Length ? statuses[idx] : null;\r
+                labels[0].SetHp(s);\r
+                labels[1].SetCond(s);\r
+                labels[2].SetName(s, ShipNameWidth.Combined);\r
             }\r
         }\r
 \r
         public void CreateAkashiTimers(Control parent)\r
         {\r
+            CreateAkashiTimers(parent, _akashiTimers, 16);\r
+        }\r
+\r
+        public void CreateAkashiTimers7(Control parent)\r
+        {\r
+            CreateAkashiTimers(parent, _akashiTimers7, 14);\r
+        }\r
+\r
+        public void CreateAkashiTimers(Control parent, ShipLabel[] timerLabels, int lineHeight)\r
+        {\r
             parent.SuspendLayout();\r
-            for (var i = 0; i < _akashiTimers.Length; i++)\r
+            for (var i = 0; i < timerLabels.Length; i++)\r
             {\r
                 const int x = 55;\r
-                var y = 3 + 16 * (i + 1);\r
+                var y = 3 + lineHeight * (i + 1);\r
                 ShipLabel label;\r
                 parent.Controls.Add(\r
-                    label = _akashiTimers[i] =\r
+                    label = timerLabels[i] =\r
                         new ShipLabel\r
                         {\r
                             Location = new Point(x, y),\r
-                            Size = new Size(34, 12),\r
+                            Size = new Size(31, 12),\r
                             TextAlign = ContentAlignment.TopRight\r
                         });\r
                 label.BackColor = ColumnColors[i % 2];\r
             }\r
-            foreach (var label in _akashiTimers)\r
+            foreach (var label in timerLabels)\r
                 label.Scale();\r
             parent.ResumeLayout();\r
         }\r
 \r
+        public void AdjustAkashiTimers()\r
+        {\r
+            AdjustAkashiTimers(_akashiTimers, 16);\r
+            AdjustAkashiTimers(_akashiTimers7, 14);\r
+        }\r
+\r
+        public void AdjustAkashiTimers(ShipLabel[] timers, int lineHeight)\r
+        {\r
+            var scale = ShipLabel.ScaleFactor;\r
+            if (scale.Height < 1.2)\r
+                return;\r
+            for (var i = 0; i < timers.Length; i++)\r
+            {\r
+                const int x = 55;\r
+                var y = 3 + lineHeight * (i + 1);\r
+                timers[i].Location = new Point((int)Round(x * scale.Width) - 3, (int)Round(y * scale.Height));\r
+                timers[i].Size = new Size((int)Round(31 * scale.Width) + 1, (int)Round(12 * scale.Height));\r
+            }\r
+        }\r
+\r
         public void SetAkashiTimer(ShipStatus[] statuses, AkashiTimer.RepairSpan[] timers)\r
         {\r
+            if (statuses.Length == 7)\r
+            {\r
+                SetAkashiTimer(statuses, timers, _akashiTimers7, _shipLabels7);\r
+            }\r
+            else\r
+            {\r
+\r
+                SetAkashiTimer(statuses, timers, _akashiTimers, _shiplabels);\r
+            }\r
+        }\r
+\r
+        public void SetAkashiTimer(ShipStatus[] statuses, AkashiTimer.RepairSpan[] timers, ShipLabel[] timerLabels, ShipLabel[][] shipLabels)\r
+        {\r
             var shortest = -1;\r
             for (var i = 0; i < timers.Length; i++)\r
             {\r
@@ -212,11 +290,11 @@ namespace KancolleSniffer
                 if (shortest == -1 || timers[i].Span < timers[shortest].Span)\r
                     shortest = i;\r
             }\r
-            for (var i = 0; i < _akashiTimers.Length; i++)\r
+            for (var i = 0; i < timerLabels.Length; i++)\r
             {\r
-                var label = _akashiTimers[i];\r
-                var labelHp = _labels[i][0];\r
-                var labelName = _labels[i][4];\r
+                var label = timerLabels[i];\r
+                var labelHp = shipLabels[i][0];\r
+                var labelName = shipLabels[i][4];\r
                 if (i >= timers.Length || timers[i].Span == TimeSpan.MinValue)\r
                 {\r
                     label.Visible = false;\r
@@ -228,92 +306,19 @@ namespace KancolleSniffer
                 label.Visible = true;\r
                 label.Text = timer.Span.ToString(@"mm\:ss");\r
                 label.ForeColor = Control.DefaultForeColor;\r
-                labelName.SetName(stat, _shortNameDict);\r
+                labelName.SetName(stat, ShipNameWidth.AkashiTimer);\r
                 if (timer.Diff == 0)\r
                 {\r
                     labelHp.ForeColor = Control.DefaultForeColor;\r
                     continue;\r
                 }\r
                 if (i == shortest)\r
-                    label.ForeColor = Color.Red;\r
+                    label.ForeColor = CUDColor.Red;\r
                 labelHp.ForeColor = Color.DimGray;\r
                 labelHp.SetHp(stat.NowHp + timer.Diff, stat.MaxHp);\r
             }\r
         }\r
 \r
-        private readonly Dictionary<string, string> _shortNameDict = new Dictionary<string, string>\r
-        {\r
-            {"千代田航改", "千代田航"},\r
-            {"千代田航改二", "千代田航"},\r
-            {"千歳航改二", "千歳航改"},\r
-            {"五十鈴改二", "五十鈴改"},\r
-            {"あきつ丸改", "あきつ丸"},\r
-            {"Bismarck改", "Bismarck"},\r
-            {"Bismarck twei", "Bismarck"},\r
-            {"Bismarck drei", "Bismarck"},\r
-            {"Prinz Eugen", "Prinz Eug"},\r
-            {"Prinz Eugen改", "Prinz Eug"},\r
-            {"Graf Zeppelin", "Graf Zep"},\r
-            {"Graf Zeppelin改", "Graf Zep"},\r
-            {"Libeccio改", "Libeccio"},\r
-            {"阿武隈改二", "阿武隈改"},\r
-            {"瑞鶴改二甲", "瑞鶴改二"},\r
-            {"翔鶴改二甲", "翔鶴改二"},\r
-        };\r
-\r
-        public void CreateDamagedShipList(Control parent, EventHandler onClick)\r
-        {\r
-            parent.SuspendLayout();\r
-            for (var i = 0; i < _damagedShipList.Length; i++)\r
-            {\r
-                var y = 3 + i * 16;\r
-                const int height = 12;\r
-                parent.Controls.AddRange(_damagedShipList[i] = new[]\r
-                {\r
-                    new ShipLabel {Location = new Point(0, y), Size = new Size(11, height)},\r
-                    new ShipLabel {Location = new Point(119, y), Size = new Size(5, height - 1)},\r
-                    new ShipLabel {Location = new Point(75, y), AutoSize = true},\r
-                    new ShipLabel {Location = new Point(9, y), AutoSize = true},\r
-                    new ShipLabel {Location = new Point(0, y - 2), Size = new Size(parent.Width, height + 3)}\r
-                });\r
-                foreach (var label in _damagedShipList[i])\r
-                {\r
-                    label.Scale();\r
-                    label.PresetColor = label.BackColor = ColumnColors[(i + 1) % 2];\r
-                    label.Click += onClick;\r
-                }\r
-            }\r
-            _panelDamagedShipList = parent;\r
-            parent.ResumeLayout();\r
-        }\r
-\r
-        public void SetDamagedShipList(ShipStatus[] list)\r
-        {\r
-            const int fleet = 0, name = 3, time = 2, damage = 1;\r
-            var parent = _panelDamagedShipList;\r
-            var num = Min(list.Length, _damagedShipList.Length);\r
-            if (num == 0)\r
-            {\r
-                parent.Size = new Size(parent.Width, (int)Round(ShipLabel.ScaleFactor.Height * 19));\r
-                var labels = _damagedShipList[0];\r
-                labels[fleet].Text = "";\r
-                labels[name].SetName("なし");\r
-                labels[time].Text = "";\r
-                labels[damage].BackColor = labels[damage].PresetColor;\r
-                return;\r
-            }\r
-            parent.Size = new Size(parent.Width, (int)Round(ShipLabel.ScaleFactor.Height * (num * 16 + 3)));\r
-            for (var i = 0; i < num; i++)\r
-            {\r
-                var s = list[i];\r
-                var labels = _damagedShipList[i];\r
-                labels[fleet].SetFleet(s);\r
-                labels[name].SetName(s);\r
-                labels[time].SetRepairTime(s);\r
-                labels[damage].BackColor = ShipLabel.DamageColor(s, labels[damage].PresetColor);\r
-            }\r
-        }\r
-\r
         public void CreateNDockLabels(Control parent, EventHandler onClick)\r
         {\r
             for (var i = 0; i < _ndockLabels.Length; i++)\r
@@ -341,60 +346,137 @@ namespace KancolleSniffer
         public void SetNDockLabels(NameAndTimer[] ndock)\r
         {\r
             for (var i = 0; i < _ndockLabels.Length; i++)\r
-                _ndockLabels[i][1].SetName(ndock[i].Name);\r
+                _ndockLabels[i][1].SetName(ndock[i].Name, ShipNameWidth.NDock);\r
         }\r
 \r
-        public void SetNDockTimer(int dock, RingTimer timer, bool finishTime)\r
+        public void SetNDockTimer(int dock, AlarmTimer timer, DateTime now, bool finishTime)\r
         {\r
             var label = _ndockLabels[dock][0];\r
-            label.ForeColor = timer.IsFinished ? Color.Red : Color.Black;\r
-            label.Text = timer.ToString(finishTime);\r
+            label.ForeColor = timer.IsFinished(now) ? CUDColor.Red : Color.Black;\r
+            label.Text = timer.ToString(now, finishTime);\r
         }\r
     }\r
 \r
-    [System.ComponentModel.DesignerCategory("Code")]\r
+    [DesignerCategory("Code")]\r
     public class ShipLabel : Label\r
     {\r
         public static SizeF ScaleFactor { get; set; }\r
+        public static Font LatinFont { get; set; } = new Font("Tahoma", 8f);\r
         public Color PresetColor { get; set; }\r
         public bool AnchorRight { get; set; }\r
         private int _right = int.MinValue;\r
         private int _left;\r
+        private SlotStatus _slotStatus;\r
+        private ShipStatus _status;\r
+        private bool _hpPercent;\r
 \r
-        public void SetName(ShipStatus status, Dictionary<string, string> convDict = null)\r
+        public override Color BackColor\r
         {\r
-            string name;\r
-            if (convDict == null || !convDict.TryGetValue(status.Name, out name))\r
-                name = status.Name;\r
-            var empty = status.Id != -1 && status.Slot.All(e => e.Id == -1) ? "▫" : "";\r
+            get => base.BackColor;\r
+            set => base.BackColor = value == DefaultBackColor ? PresetColor : value;\r
+        }\r
+\r
+        [Flags]\r
+        private enum SlotStatus\r
+        {\r
+            Equipped = 0,\r
+            NormalEmpty = 1,\r
+            ExtraEmpty = 2\r
+        }\r
+\r
+        public ShipLabel()\r
+        {\r
+            UseMnemonic = false;\r
+        }\r
+\r
+        public void SetName(ShipStatus status, ShipNameWidth width = ShipNameWidth.Max)\r
+        {\r
+            if (status == null)\r
+            {\r
+                SetName("");\r
+                return;\r
+            }\r
+            var empty = SlotStatus.Equipped;\r
+            if (status.Id != -1)\r
+            {\r
+                if (status.Slot.All(item => item.Id == -1))\r
+                    empty |= SlotStatus.NormalEmpty;\r
+                if (status.SlotEx.Id == -1)\r
+                    empty |= SlotStatus.ExtraEmpty;\r
+            }\r
             var dc = status.PreparedDamageControl;\r
             var dcname = dc == 42 ? "[ダ]" : dc == 43 ? "[メ]" : "";\r
-            SetName((status.Escaped ? "[避]" : dcname) + name + empty);\r
+            SetName(status.Escaped ? "[避]" : dcname, status.Name, empty, width);\r
         }\r
 \r
         public void SetName(string name)\r
         {\r
-            var lu = name != null && new Regex(@"^(?:\[.\])?\p{Lu}").IsMatch(name);\r
+            SetName("", name, SlotStatus.Equipped);\r
+        }\r
+\r
+        public void SetName(string name, ShipNameWidth width)\r
+        {\r
+            SetName("", name, SlotStatus.Equipped, width);\r
+        }\r
+\r
+        private void SetName(string prefix, string name, SlotStatus slotStatus, ShipNameWidth width = ShipNameWidth.Max)\r
+        {\r
+            if (name == null)\r
+                name = "";\r
+            _slotStatus = slotStatus;\r
+            var lu = new Regex(@"^\p{Lu}").IsMatch(name);\r
             var shift = (int)Round(ScaleFactor.Height);\r
             if (lu && Font.Equals(Parent.Font))\r
             {\r
                 Location += new Size(0, -shift);\r
-                Font = new Font("Tahoma", 8f);\r
+                Font = LatinFont;\r
             }\r
             else if (!lu && !Font.Equals(Parent.Font))\r
             {\r
                 Location += new Size(0, shift);\r
                 Font = Parent.Font;\r
             }\r
-            Text = name;\r
+            var result = prefix + name;\r
+            var measured = TextRenderer.MeasureText(result, Font).Width;\r
+            if (measured <= (int)width)\r
+            {\r
+                Text = result;\r
+                Invalidate(); // 必ずOnPaintを実行させるため\r
+                return;\r
+            }\r
+            var truncated = "";\r
+            foreach (var ch in name)\r
+            {\r
+                var tmp = truncated + ch;\r
+                if (TextRenderer.MeasureText(tmp, Font).Width > (int)width * ScaleFactor.Width)\r
+                    break;\r
+                truncated = tmp;\r
+            }\r
+            Text = prefix + truncated.TrimEnd(' ');\r
+            Invalidate();\r
         }\r
 \r
         public void SetHp(ShipStatus status)\r
         {\r
-            Text = $"{status.NowHp:D}/{status.MaxHp:D}";\r
+            _status = status;\r
+            if (status == null)\r
+            {\r
+                Text = "";\r
+                BackColor = PresetColor;\r
+                return;\r
+            }\r
+            Text = _hpPercent\r
+                ? $"{(int)Ceiling(status.NowHp * 100.0 / status.MaxHp):D}%"\r
+                : $"{status.NowHp:D}/{status.MaxHp:D}";\r
             BackColor = DamageColor(status, PresetColor);\r
         }\r
 \r
+        public void ToggleHpPercent()\r
+        {\r
+            _hpPercent = !_hpPercent;\r
+            SetHp(_status);\r
+        }\r
+\r
         public void SetHp(int now, int max)\r
         {\r
             SetHp(new ShipStatus {NowHp = now, MaxHp = max});\r
@@ -404,10 +486,12 @@ namespace KancolleSniffer
         {\r
             switch (status.DamageLevel)\r
             {\r
+                case ShipStatus.Damage.Sunk:\r
+                    return Color.CornflowerBlue;\r
                 case ShipStatus.Damage.Badly:\r
-                    return Color.Red;\r
+                    return CUDColor.Red;\r
                 case ShipStatus.Damage.Half:\r
-                    return Color.Orange;\r
+                    return CUDColor.Orange;\r
                 case ShipStatus.Damage.Small:\r
                     return Color.FromArgb(240, 240, 0);\r
                 default:\r
@@ -417,27 +501,40 @@ namespace KancolleSniffer
 \r
         public void SetCond(ShipStatus status)\r
         {\r
+            if (status == null)\r
+            {\r
+                Text = "";\r
+                BackColor = PresetColor;\r
+                return;\r
+            }\r
             var cond = status.Cond;\r
             Text = cond.ToString("D");\r
             BackColor = cond >= 50\r
-                ? Color.Yellow\r
+                ? CUDColor.Yellow\r
                 : cond >= 30\r
                     ? PresetColor\r
-                    : cond >= 20 ? Color.Orange : Color.Red;\r
+                    : cond >= 20\r
+                        ? CUDColor.Orange\r
+                        : CUDColor.Red;\r
         }\r
 \r
         public void SetLevel(ShipStatus status)\r
         {\r
-            Text = status.Level.ToString("D");\r
+            Text = status?.Level.ToString("D");\r
         }\r
 \r
         public void SetExpToNext(ShipStatus status)\r
         {\r
-            Text = status.ExpToNext.ToString("D");\r
+            Text = status?.ExpToNext.ToString("D");\r
         }\r
 \r
         public void SetRepairTime(ShipStatus status)\r
         {\r
+            if (status == null)\r
+            {\r
+                Text = "";\r
+                return;\r
+            }\r
             SetRepairTime(status.RepairTime);\r
         }\r
 \r
@@ -448,7 +545,7 @@ namespace KancolleSniffer
 \r
         public void SetFleet(ShipStatus status)\r
         {\r
-            Text = new[] {"", "1", "2", "3", "4"}[status.Fleet + 1];\r
+            Text = status == null ? "" : new[] {"", "1", "2", "3", "4"}[status.Fleet + 1];\r
         }\r
 \r
         protected override void OnLayout(LayoutEventArgs levent)\r
@@ -468,6 +565,25 @@ namespace KancolleSniffer
             Location = new Point(_left, Top);\r
         }\r
 \r
+        protected override void OnPaint(PaintEventArgs e)\r
+        {\r
+            base.OnPaint(e);\r
+            if ((_slotStatus & SlotStatus.NormalEmpty) != 0)\r
+            {\r
+                e.Graphics.DrawRectangle(\r
+                    Pens.Black,\r
+                    ClientSize.Width - 3 * ScaleFactor.Width, 1 * ScaleFactor.Height,\r
+                    2 * ScaleFactor.Width, 4 * ScaleFactor.Height);\r
+            }\r
+            if ((_slotStatus & SlotStatus.ExtraEmpty) != 0)\r
+            {\r
+                e.Graphics.DrawRectangle(\r
+                    Pens.Black,\r
+                    ClientSize.Width - 3 * ScaleFactor.Width, 7 * ScaleFactor.Height,\r
+                    2 * ScaleFactor.Width, 3 * ScaleFactor.Height);\r
+            }\r
+        }\r
+\r
         public void Scale()\r
         {\r
             Scale(ScaleFactor);\r