OSDN Git Service

ラベルの再描画を減らす
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / View / ShipLabel.cs
index d2c1459..bec8f9a 100644 (file)
@@ -24,12 +24,9 @@ using static System.Math;
 namespace KancolleSniffer.View\r
 {\r
     [DesignerCategory("Code")]\r
-    public class ShipLabel : GrowLeftLabel\r
+    public abstract class ShipLabel : GrowLeftLabel\r
     {\r
         protected Color InitialBackColor;\r
-        protected ShipStatus Status;\r
-\r
-        protected Font BaseFont => Parent.Font;\r
 \r
         public override Color BackColor\r
         {\r
@@ -42,34 +39,26 @@ namespace KancolleSniffer.View
             }\r
         }\r
 \r
-        public ShipLabel()\r
+        protected ShipLabel()\r
         {\r
             UseMnemonic = false;\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
+        public abstract void Set(ShipStatus status);\r
 \r
-        public void SetRepairTime(TimeSpan span)\r
-        {\r
-            Text = $@"{(int)span.TotalHours:d2}:{span:mm\:ss}";\r
-        }\r
+        public abstract void Reset();\r
 \r
         public new sealed class Name : ShipLabel\r
         {\r
-            private SlotStatus _slotStatus;\r
+            private SlotStatus _slotStatus, _prevSlotStatus;\r
+            private readonly ShipNameWidth _defaultWidth;\r
 \r
-            public static Font LatinFont { get; set; } = new Font("Tahoma", 8f);\r
+            public static Font LatinFont { get; set; }\r
+            public static Font BaseFont { get; set; }\r
 \r
-            public Name(Point location)\r
+            public Name(Point location, ShipNameWidth defaultWidth)\r
             {\r
+                _defaultWidth = defaultWidth;\r
                 Location = location;\r
                 AutoSize = true;\r
             }\r
@@ -83,41 +72,65 @@ namespace KancolleSniffer.View
                 ExtraEmpty = 4\r
             }\r
 \r
-            public void SetName(ShipStatus status, ShipNameWidth width = ShipNameWidth.Max)\r
+            public override void Set(ShipStatus status)\r
             {\r
-                if (status == null)\r
-                {\r
-                    SetName("");\r
-                    return;\r
-                }\r
-                var empty = SlotStatus.Equipped;\r
-                if (!status.Empty)\r
+                SetName(status, _defaultWidth);\r
+            }\r
+\r
+            public override void Reset()\r
+            {\r
+                SetName("");\r
+            }\r
+\r
+            public void SetName(ShipStatus status, ShipNameWidth width)\r
+            {\r
+                var slotStatus = GetSlotStatus(status);\r
+                var dcName = DameConName(status);\r
+                var sp = SpecialAttack(status);\r
+                SetName((status.Escaped ? "[避]" : dcName) + sp, status.Name, slotStatus, width);\r
+            }\r
+\r
+            private static SlotStatus GetSlotStatus(ShipStatus status)\r
+            {\r
+                if (status.Empty)\r
+                    return SlotStatus.Equipped;\r
+                var slots = status.Slot.Take(status.Spec.SlotNum).ToArray();\r
+                var normal = slots.Any(item => item.Empty)\r
+                    ? slots.All(item => item.Empty) ? SlotStatus.NormalEmpty : SlotStatus.SemiEquipped\r
+                    : SlotStatus.Equipped;\r
+                var extra = status.SlotEx.Empty ? SlotStatus.ExtraEmpty : SlotStatus.Equipped;\r
+                return normal | extra;\r
+            }\r
+\r
+            private string DameConName(ShipStatus status)\r
+            {\r
+                switch (status.PreparedDamageControl)\r
                 {\r
-                    var slots = status.Slot.Take(status.Spec.SlotNum).ToArray();\r
-                    if (slots.Any(item => item.Empty))\r
-                        empty |= slots.All(item => item.Empty) ? SlotStatus.NormalEmpty : SlotStatus.SemiEquipped;\r
-                    if (status.SlotEx.Empty)\r
-                        empty |= SlotStatus.ExtraEmpty;\r
+                    case 42:\r
+                        return "[ダ]";\r
+                    case 43:\r
+                        return "[メ]";\r
+                    default:\r
+                        return "";\r
                 }\r
-                var dc = status.PreparedDamageControl;\r
-                var dcName = dc == 42 ? "[ダ]" :\r
-                    dc == 43 ? "[メ]" : "";\r
-                var sp = "";\r
+            }\r
+\r
+            private string SpecialAttack(ShipStatus status)\r
+            {\r
                 switch (status.SpecialAttack)\r
                 {\r
                     case ShipStatus.Attack.Fire:\r
-                        sp = "+";\r
-                        break;\r
+                        return "+";\r
                     case ShipStatus.Attack.Fired:\r
-                        sp = "-";\r
-                        break;\r
+                        return "-";\r
+                    default:\r
+                        return "";\r
                 }\r
-                SetName((status.Escaped ? "[避]" : dcName) + sp, status.Name, empty, width);\r
             }\r
 \r
             public void SetName(string name)\r
             {\r
-                SetName("", name, SlotStatus.Equipped);\r
+                SetName(name, _defaultWidth);\r
             }\r
 \r
             public void SetName(string name, ShipNameWidth width)\r
@@ -125,42 +138,36 @@ namespace KancolleSniffer.View
                 SetName("", name, SlotStatus.Equipped, width);\r
             }\r
 \r
-            private void SetName(string prefix, string name, SlotStatus slotStatus,\r
-                ShipNameWidth width = ShipNameWidth.Max)\r
+            private void SetName(string prefix, string name, SlotStatus slotStatus, ShipNameWidth width)\r
             {\r
-                if (name == null)\r
-                    name = "";\r
                 _slotStatus = slotStatus;\r
-                var lu = new Regex(@"^\p{Lu}").IsMatch(name);\r
+                ChangeFont(name);\r
+                var realWidth = width == ShipNameWidth.Max ? (int)width : Scaler.ScaleWidth((int)width);\r
+                Text = prefix + StringTruncator.Truncate(name, "", realWidth, Font);\r
+                if (_prevSlotStatus != _slotStatus)\r
+                    Invalidate(); // OnPaintを実行させるため\r
+                _prevSlotStatus = _slotStatus;\r
+            }\r
+\r
+            private void ChangeFont(string name)\r
+            {\r
+                var lu = StartWithLetter(name);\r
                 var shift = Scaler.ScaleHeight(1);\r
-                if (lu && Font.Equals(BaseFont))\r
+                if (lu && !Font.Equals(LatinFont))\r
                 {\r
                     Location += new Size(0, -shift);\r
                     Font = LatinFont;\r
                 }\r
-                else if (!lu && !Font.Equals(BaseFont))\r
+                else if (!lu && Font.Equals(LatinFont))\r
                 {\r
                     Location += new Size(0, shift);\r
                     Font = BaseFont;\r
                 }\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 > Scaler.ScaleWidth((float)width))\r
-                        break;\r
-                    truncated = tmp;\r
-                }\r
-                Text = prefix + truncated.TrimEnd(' ');\r
-                Invalidate();\r
+            }\r
+\r
+            public static bool StartWithLetter(string name)\r
+            {\r
+                return Regex.IsMatch(name, @"^\p{Lu}");\r
             }\r
 \r
             protected override void OnPaint(PaintEventArgs e)\r
@@ -188,9 +195,7 @@ namespace KancolleSniffer.View
         public sealed class Hp : ShipLabel\r
         {\r
             private bool _hpPercent;\r
-            private Font _strongFont;\r
-            private ShipLabel _hpStrongLabel;\r
-            private Font StrongFont => _strongFont ?? (_strongFont = new Font("Leelawadee", BaseFont.Size));\r
+            private ShipStatus _status;\r
 \r
             public Hp()\r
             {\r
@@ -205,64 +210,32 @@ namespace KancolleSniffer.View
                 Cursor = Cursors.Hand;\r
             }\r
 \r
-            public void SetHp(ShipStatus status)\r
+            public override void Reset()\r
             {\r
-                Status = status;\r
-                if (_hpStrongLabel != null)\r
-                    _hpStrongLabel.Text = "";\r
-                Font = BaseFont;\r
-                if (status == null)\r
-                {\r
-                    Text = "";\r
-                    BackColor = InitialBackColor;\r
-                    return;\r
-                }\r
-                if (_hpPercent)\r
-                {\r
-                    var percent = $"{(int)Floor(status.NowHp * 100.0 / status.MaxHp):D}";\r
-                    if (status.DamageLevel == ShipStatus.Damage.Badly)\r
-                    {\r
-                        Text = "%";\r
-                        if (_hpStrongLabel == null)\r
-                            CreateHpStrongLabel();\r
-                        _hpStrongLabel.Text = percent;\r
-                    }\r
-                    else\r
-                    {\r
-                        Text = percent + "%";\r
-                    }\r
-                }\r
-                else\r
-                {\r
-                    Text = $"{status.NowHp:D}/{status.MaxHp:D}";\r
-                    if (status.DamageLevel == ShipStatus.Damage.Badly)\r
-                        Font = StrongFont;\r
-                }\r
-                BackColor = DamageColor(status);\r
+                _status = null;\r
+                Text = "";\r
+                BackColor = InitialBackColor;\r
             }\r
 \r
-            private void CreateHpStrongLabel()\r
+            public override void Set(ShipStatus status)\r
             {\r
-                _hpStrongLabel = new Hp(Scaler.Move(Left, Top, 4, 0), Height)\r
-                {\r
-                    Font = StrongFont,\r
-                    BackColor = CUDColors.Red\r
-                };\r
-                _hpStrongLabel.DoubleClick += (sender, e) => { OnDoubleClick(e); };\r
-                Parent.Controls.Add(_hpStrongLabel);\r
-                var index = Parent.Controls.GetChildIndex(this);\r
-                Parent.Controls.SetChildIndex(_hpStrongLabel, index + 1);\r
+                _status = status;\r
+                Text = _hpPercent\r
+                    ? $"{(int)Floor(status.NowHp * 100.0 / status.MaxHp):D}%"\r
+                    : $"{status.NowHp:D}/{status.MaxHp:D}";\r
+                BackColor = DamageColor(status);\r
             }\r
 \r
             public void ToggleHpPercent()\r
             {\r
                 _hpPercent = !_hpPercent;\r
-                SetHp(Status);\r
+                if (_status != null)\r
+                    Set(_status);\r
             }\r
 \r
             public void SetHp(int now, int max)\r
             {\r
-                SetHp(new ShipStatus {NowHp = now, MaxHp = max});\r
+                Set(new ShipStatus {NowHp = now, MaxHp = max});\r
             }\r
 \r
             public Color DamageColor(ShipStatus status)\r
@@ -297,14 +270,14 @@ namespace KancolleSniffer.View
                 TextAlign = ContentAlignment.MiddleRight;\r
             }\r
 \r
-            public void SetCond(ShipStatus status)\r
+            public override void Reset()\r
+            {\r
+                Text = "";\r
+                BackColor = InitialBackColor;\r
+            }\r
+\r
+            public override void Set(ShipStatus status)\r
             {\r
-                if (status == null)\r
-                {\r
-                    Text = "";\r
-                    BackColor = InitialBackColor;\r
-                    return;\r
-                }\r
                 var cond = status.Cond;\r
                 Text = cond.ToString("D");\r
                 BackColor = cond >= 50\r
@@ -326,9 +299,14 @@ namespace KancolleSniffer.View
                 TextAlign = ContentAlignment.MiddleRight;\r
             }\r
 \r
-            public void SetLevel(ShipStatus status)\r
+            public override void Reset()\r
+            {\r
+                Text = "";\r
+            }\r
+\r
+            public override void Set(ShipStatus status)\r
             {\r
-                Text = status?.Level.ToString("D");\r
+                Text = status.Level.ToString("D");\r
             }\r
         }\r
 \r
@@ -341,9 +319,14 @@ namespace KancolleSniffer.View
                 TextAlign = ContentAlignment.MiddleRight;\r
             }\r
 \r
-            public void SetExpToNext(ShipStatus status)\r
+            public override void Reset()\r
             {\r
-                Text = status?.ExpToNext.ToString("D");\r
+                Text = "";\r
+            }\r
+\r
+            public override void Set(ShipStatus status)\r
+            {\r
+                Text = status.ExpToNext.ToString("D");\r
             }\r
         }\r
 \r
@@ -355,9 +338,38 @@ namespace KancolleSniffer.View
                 AutoSize = true;\r
             }\r
 \r
-            public void SetFleet(ShipStatus status)\r
+            public override void Reset()\r
+            {\r
+                Text = "";\r
+            }\r
+\r
+            public override void Set(ShipStatus status)\r
+            {\r
+                Text = status.Fleet == null ? "" : new[] {"1", "2", "3", "4"}[status.Fleet.Number];\r
+            }\r
+        }\r
+\r
+        public sealed class RepairTime : ShipLabel\r
+        {\r
+            public RepairTime(Point location)\r
+            {\r
+                Location = location;\r
+                AutoSize = true;\r
+            }\r
+\r
+            public override void Reset()\r
+            {\r
+                Text = "";\r
+            }\r
+\r
+            public override void Set(ShipStatus status)\r
+            {\r
+                SetRepairTime(status.RepairTime);\r
+            }\r
+\r
+            public void SetRepairTime(TimeSpan span)\r
             {\r
-                Text = status?.Fleet == null ? "" : new[] {"1", "2", "3", "4"}[status.Fleet.Number];\r
+                Text = $@"{(int)span.TotalHours:d2}:{span:mm\:ss}";\r
             }\r
         }\r
     }\r