OSDN Git Service

PresetColorを廃止する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / View / ShipLabel.cs
1 // Copyright (C) 2014, 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
2 //\r
3 // Licensed under the Apache License, Version 2.0 (the "License");\r
4 // you may not use this file except in compliance with the License.\r
5 // You may obtain a copy of the License at\r
6 //\r
7 //    http://www.apache.org/licenses/LICENSE-2.0\r
8 //\r
9 // Unless required by applicable law or agreed to in writing, software\r
10 // distributed under the License is distributed on an "AS IS" BASIS,\r
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
12 // See the License for the specific language governing permissions and\r
13 // limitations under the License.\r
14 \r
15 using System;\r
16 using System.ComponentModel;\r
17 using System.Drawing;\r
18 using System.Linq;\r
19 using System.Text.RegularExpressions;\r
20 using System.Windows.Forms;\r
21 using KancolleSniffer.Model;\r
22 using static System.Math;\r
23 \r
24 namespace KancolleSniffer.View\r
25 {\r
26     [DesignerCategory("Code")]\r
27     public class ShipLabel : Label\r
28     {\r
29         public static Color[] ColumnColors = {SystemColors.Control, Color.White};\r
30         public static Font LatinFont { get; set; } = new Font("Tahoma", 8f);\r
31         public bool AnchorRight { get; set; }\r
32         private Color _initialBackColor;\r
33         private int _right = Int32.MinValue;\r
34         private int _left;\r
35         private SlotStatus _slotStatus;\r
36         private ShipStatus _status;\r
37         private bool _hpPercent;\r
38         private Font _strongFont;\r
39         private ShipLabel _hpStrongLabel;\r
40 \r
41         private Font BaseFont => Parent.Font;\r
42 \r
43         private Font StrongFont => _strongFont ?? (_strongFont = new Font("Leelawadee", BaseFont.Size));\r
44 \r
45         public override Color BackColor\r
46         {\r
47             get => base.BackColor;\r
48             set\r
49             {\r
50                 if (_initialBackColor == Color.Empty)\r
51                     _initialBackColor = value;\r
52                 base.BackColor = value;\r
53             }\r
54         }\r
55 \r
56         [Flags]\r
57         private enum SlotStatus\r
58         {\r
59             Equipped = 0,\r
60             SemiEquipped = 1,\r
61             NormalEmpty = 2,\r
62             ExtraEmpty = 4\r
63         }\r
64 \r
65         public ShipLabel()\r
66         {\r
67             UseMnemonic = false;\r
68         }\r
69 \r
70         public void SetName(ShipStatus status, ShipNameWidth width = ShipNameWidth.Max)\r
71         {\r
72             if (status == null)\r
73             {\r
74                 SetName("");\r
75                 return;\r
76             }\r
77             var empty = SlotStatus.Equipped;\r
78             if (!status.Empty)\r
79             {\r
80                 var slots = status.Slot.Take(status.Spec.SlotNum).ToArray();\r
81                 if (slots.Any(item => item.Empty))\r
82                     empty |= slots.All(item => item.Empty) ? SlotStatus.NormalEmpty : SlotStatus.SemiEquipped;\r
83                 if (status.SlotEx.Empty)\r
84                     empty |= SlotStatus.ExtraEmpty;\r
85             }\r
86             var dc = status.PreparedDamageControl;\r
87             var dcName = dc == 42 ? "[ダ]" :\r
88                 dc == 43 ? "[メ]" : "";\r
89             var sp = "";\r
90             switch (status.SpecialAttack)\r
91             {\r
92                 case ShipStatus.Attack.Fire:\r
93                     sp = "+";\r
94                     break;\r
95                 case ShipStatus.Attack.Fired:\r
96                     sp = "-";\r
97                     break;\r
98             }\r
99             SetName((status.Escaped ? "[避]" : dcName) + sp, status.Name, empty, width);\r
100         }\r
101 \r
102         public void SetName(string name)\r
103         {\r
104             SetName("", name, SlotStatus.Equipped);\r
105         }\r
106 \r
107         public void SetName(string name, ShipNameWidth width)\r
108         {\r
109             SetName("", name, SlotStatus.Equipped, width);\r
110         }\r
111 \r
112         private void SetName(string prefix, string name, SlotStatus slotStatus, ShipNameWidth width = ShipNameWidth.Max)\r
113         {\r
114             if (name == null)\r
115                 name = "";\r
116             _slotStatus = slotStatus;\r
117             var lu = new Regex(@"^\p{Lu}").IsMatch(name);\r
118             var shift = Scaler.ScaleHeight(1);\r
119             if (lu && Font.Equals(BaseFont))\r
120             {\r
121                 Location += new Size(0, -shift);\r
122                 Font = LatinFont;\r
123             }\r
124             else if (!lu && !Font.Equals(BaseFont))\r
125             {\r
126                 Location += new Size(0, shift);\r
127                 Font = BaseFont;\r
128             }\r
129             var result = prefix + name;\r
130             var measured = TextRenderer.MeasureText(result, Font).Width;\r
131             if (measured <= (int)width)\r
132             {\r
133                 Text = result;\r
134                 Invalidate(); // 必ずOnPaintを実行させるため\r
135                 return;\r
136             }\r
137             var truncated = "";\r
138             foreach (var ch in name)\r
139             {\r
140                 var tmp = truncated + ch;\r
141                 if (TextRenderer.MeasureText(tmp, Font).Width > Scaler.ScaleWidth((float)width))\r
142                     break;\r
143                 truncated = tmp;\r
144             }\r
145             Text = prefix + truncated.TrimEnd(' ');\r
146             Invalidate();\r
147         }\r
148 \r
149         public void SetHp(ShipStatus status)\r
150         {\r
151             _status = status;\r
152             if (_hpStrongLabel != null)\r
153                 _hpStrongLabel.Text = "";\r
154             Font = BaseFont;\r
155             if (status == null)\r
156             {\r
157                 Text = "";\r
158                 BackColor = _initialBackColor;\r
159                 return;\r
160             }\r
161             if (_hpPercent)\r
162             {\r
163                 var percent = $"{(int)Floor(status.NowHp * 100.0 / status.MaxHp):D}";\r
164                 if (status.DamageLevel == ShipStatus.Damage.Badly)\r
165                 {\r
166                     Text = "%";\r
167                     if (_hpStrongLabel == null)\r
168                         CreateHpStrongLabel();\r
169                     _hpStrongLabel.Text = percent;\r
170                 }\r
171                 else\r
172                 {\r
173                     Text = percent + "%";\r
174                 }\r
175             }\r
176             else\r
177             {\r
178                 Text = $"{status.NowHp:D}/{status.MaxHp:D}";\r
179                 if (status.DamageLevel == ShipStatus.Damage.Badly)\r
180                     Font = StrongFont;\r
181             }\r
182             BackColor = DamageColor(status);\r
183         }\r
184 \r
185         private void CreateHpStrongLabel()\r
186         {\r
187             _hpStrongLabel = new ShipLabel\r
188             {\r
189                 Font = StrongFont,\r
190                 BackColor = CUDColors.Red,\r
191                 Location = Scaler.Move(Left, Top, 4, 0),\r
192                 AutoSize = true,\r
193                 MinimumSize = new Size(0, Height),\r
194                 AnchorRight = true,\r
195                 TextAlign = ContentAlignment.MiddleLeft,\r
196                 Cursor = Cursors.Hand\r
197             };\r
198             _hpStrongLabel.DoubleClick += (sender, e) => { OnDoubleClick(e); };\r
199             Parent.Controls.Add(_hpStrongLabel);\r
200             var index = Parent.Controls.GetChildIndex(this);\r
201             Parent.Controls.SetChildIndex(_hpStrongLabel, index + 1);\r
202         }\r
203 \r
204 \r
205         public void ToggleHpPercent()\r
206         {\r
207             _hpPercent = !_hpPercent;\r
208             SetHp(_status);\r
209         }\r
210 \r
211         public void SetHp(int now, int max)\r
212         {\r
213             SetHp(new ShipStatus {NowHp = now, MaxHp = max});\r
214         }\r
215 \r
216         public Color DamageColor(ShipStatus status)\r
217         {\r
218             switch (status.DamageLevel)\r
219             {\r
220                 case ShipStatus.Damage.Sunk:\r
221                     return Color.CornflowerBlue;\r
222                 case ShipStatus.Damage.Badly:\r
223                     return CUDColors.Red;\r
224                 case ShipStatus.Damage.Half:\r
225                     return CUDColors.Orange;\r
226                 case ShipStatus.Damage.Small:\r
227                     return Color.FromArgb(240, 240, 0);\r
228                 default:\r
229                     return _initialBackColor;\r
230             }\r
231         }\r
232 \r
233         public void SetCond(ShipStatus status)\r
234         {\r
235             if (status == null)\r
236             {\r
237                 Text = "";\r
238                 BackColor = _initialBackColor;\r
239                 return;\r
240             }\r
241             var cond = status.Cond;\r
242             Text = cond.ToString("D");\r
243             BackColor = cond >= 50\r
244                 ? CUDColors.Yellow\r
245                 : cond >= 30\r
246                     ? _initialBackColor\r
247                     : cond >= 20\r
248                         ? CUDColors.Orange\r
249                         : CUDColors.Red;\r
250         }\r
251 \r
252         public void SetLevel(ShipStatus status)\r
253         {\r
254             Text = status?.Level.ToString("D");\r
255         }\r
256 \r
257         public void SetExpToNext(ShipStatus status)\r
258         {\r
259             Text = status?.ExpToNext.ToString("D");\r
260         }\r
261 \r
262         public void SetRepairTime(ShipStatus status)\r
263         {\r
264             if (status == null)\r
265             {\r
266                 Text = "";\r
267                 return;\r
268             }\r
269             SetRepairTime(status.RepairTime);\r
270         }\r
271 \r
272         public void SetRepairTime(TimeSpan span)\r
273         {\r
274             Text = $@"{(int)span.TotalHours:d2}:{span:mm\:ss}";\r
275         }\r
276 \r
277         public void SetFleet(ShipStatus status)\r
278         {\r
279             Text = status?.Fleet == null ? "" : new[] {"1", "2", "3", "4"}[status.Fleet.Number];\r
280         }\r
281 \r
282         protected override void OnSizeChanged(EventArgs args)\r
283         {\r
284             base.OnSizeChanged(args);\r
285             KeepAnchorRight();\r
286         }\r
287 \r
288         protected override void OnLayout(LayoutEventArgs args)\r
289         {\r
290             base.OnLayout(args);\r
291             KeepAnchorRight();\r
292         }\r
293 \r
294         private void KeepAnchorRight()\r
295         {\r
296             if (!AnchorRight)\r
297                 return;\r
298             if (_right == int.MinValue || _left != Left)\r
299             {\r
300                 _right = Right;\r
301                 _left = Left;\r
302                 return;\r
303             }\r
304             if (_right == Right)\r
305                 return;\r
306             _left -= Right - _right;\r
307             Location = new Point(_left, Top);\r
308         }\r
309 \r
310         protected override void OnPaint(PaintEventArgs e)\r
311         {\r
312             base.OnPaint(e);\r
313             if ((_slotStatus & SlotStatus.NormalEmpty) != 0)\r
314             {\r
315                 e.Graphics.DrawRectangle(Pens.Black,\r
316                     new Rectangle(Scaler.Move(ClientSize.Width, 0, -3, 0), Scaler.Scale(2, 5)));\r
317             }\r
318             else if ((_slotStatus & SlotStatus.SemiEquipped) != 0)\r
319             {\r
320                 e.Graphics.DrawLine(Pens.Black,\r
321                     Scaler.Move(ClientSize.Width, 0, -1, 0),\r
322                     Scaler.Move(ClientSize.Width, 0, -1, 5));\r
323             }\r
324             if ((_slotStatus & SlotStatus.ExtraEmpty) != 0)\r
325             {\r
326                 e.Graphics.DrawRectangle(Pens.Black,\r
327                     new Rectangle(Scaler.Move(ClientSize.Width, 0, -3, 8), Scaler.Scale(2, 3)));\r
328             }\r
329         }\r
330     }\r
331 }