OSDN Git Service

各種報告書の表を列単位で検索可能にする
[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.FromArgb(255, 250, 250, 250)};\r
30         public static SizeF ScaleFactor { get; set; }\r
31         public static Font LatinFont { get; set; } = new Font("Tahoma", 8f);\r
32         public Color PresetColor { get; set; }\r
33         public bool AnchorRight { get; set; }\r
34         private int _right = Int32.MinValue;\r
35         private int _left;\r
36         private SlotStatus _slotStatus;\r
37         private ShipStatus _status;\r
38         private bool _hpPercent;\r
39 \r
40         public override Color BackColor\r
41         {\r
42             get => base.BackColor;\r
43             set => base.BackColor = value == DefaultBackColor ? PresetColor : value;\r
44         }\r
45 \r
46         [Flags]\r
47         private enum SlotStatus\r
48         {\r
49             Equipped = 0,\r
50             SemiEquipped = 1,\r
51             NormalEmpty = 2,\r
52             ExtraEmpty = 4\r
53         }\r
54 \r
55         public ShipLabel()\r
56         {\r
57             UseMnemonic = false;\r
58         }\r
59 \r
60         public void SetName(ShipStatus status, ShipNameWidth width = ShipNameWidth.Max)\r
61         {\r
62             if (status == null)\r
63             {\r
64                 SetName("");\r
65                 return;\r
66             }\r
67             var empty = SlotStatus.Equipped;\r
68             if (!status.Empty)\r
69             {\r
70                 var slots = status.Slot.Take(status.Spec.SlotNum).ToArray();\r
71                 if (slots.Any(item => item.Empty))\r
72                     empty |= slots.All(item => item.Empty) ? SlotStatus.NormalEmpty : SlotStatus.SemiEquipped;\r
73                 if (status.SlotEx.Empty)\r
74                     empty |= SlotStatus.ExtraEmpty;\r
75             }\r
76             var dc = status.PreparedDamageControl;\r
77             var dcName = dc == 42 ? "[ダ]" :\r
78                 dc == 43 ? "[メ]" : "";\r
79             var sp = "";\r
80             switch (status.SpecialAttack)\r
81             {\r
82                 case ShipStatus.Attack.Fire:\r
83                     sp = "+";\r
84                     break;\r
85                 case ShipStatus.Attack.Fired:\r
86                     sp = "-";\r
87                     break;\r
88             }\r
89             SetName((status.Escaped ? "[避]" : dcName) + sp, status.Name, empty, width);\r
90         }\r
91 \r
92         public void SetName(string name)\r
93         {\r
94             SetName("", name, SlotStatus.Equipped);\r
95         }\r
96 \r
97         public void SetName(string name, ShipNameWidth width)\r
98         {\r
99             SetName("", name, SlotStatus.Equipped, width);\r
100         }\r
101 \r
102         private void SetName(string prefix, string name, SlotStatus slotStatus, ShipNameWidth width = ShipNameWidth.Max)\r
103         {\r
104             if (name == null)\r
105                 name = "";\r
106             _slotStatus = slotStatus;\r
107             var lu = new Regex(@"^\p{Lu}").IsMatch(name);\r
108             var shift = (int)Round(ScaleFactor.Height);\r
109             if (lu && Font.Equals(Parent.Font))\r
110             {\r
111                 Location += new Size(0, -shift);\r
112                 Font = LatinFont;\r
113             }\r
114             else if (!lu && !Font.Equals(Parent.Font))\r
115             {\r
116                 Location += new Size(0, shift);\r
117                 Font = Parent.Font;\r
118             }\r
119             var result = prefix + name;\r
120             var measured = TextRenderer.MeasureText(result, Font).Width;\r
121             if (measured <= (int)width)\r
122             {\r
123                 Text = result;\r
124                 Invalidate(); // 必ずOnPaintを実行させるため\r
125                 return;\r
126             }\r
127             var truncated = "";\r
128             foreach (var ch in name)\r
129             {\r
130                 var tmp = truncated + ch;\r
131                 if (TextRenderer.MeasureText(tmp, Font).Width > (int)width * ScaleFactor.Width)\r
132                     break;\r
133                 truncated = tmp;\r
134             }\r
135             Text = prefix + truncated.TrimEnd(' ');\r
136             Invalidate();\r
137         }\r
138 \r
139         public void SetHp(ShipStatus status)\r
140         {\r
141             _status = status;\r
142             if (status == null)\r
143             {\r
144                 Text = "";\r
145                 BackColor = PresetColor;\r
146                 return;\r
147             }\r
148             Text = _hpPercent\r
149                 ? $"{(int)Floor(status.NowHp * 100.0 / status.MaxHp):D}%"\r
150                 : $"{status.NowHp:D}/{status.MaxHp:D}";\r
151             BackColor = DamageColor(status, PresetColor);\r
152         }\r
153 \r
154         public void ToggleHpPercent()\r
155         {\r
156             _hpPercent = !_hpPercent;\r
157             SetHp(_status);\r
158         }\r
159 \r
160         public void SetHp(int now, int max)\r
161         {\r
162             SetHp(new ShipStatus {NowHp = now, MaxHp = max});\r
163         }\r
164 \r
165         public static Color DamageColor(ShipStatus status, Color backColor)\r
166         {\r
167             switch (status.DamageLevel)\r
168             {\r
169                 case ShipStatus.Damage.Sunk:\r
170                     return Color.CornflowerBlue;\r
171                 case ShipStatus.Damage.Badly:\r
172                     return CUDColors.Red;\r
173                 case ShipStatus.Damage.Half:\r
174                     return CUDColors.Orange;\r
175                 case ShipStatus.Damage.Small:\r
176                     return Color.FromArgb(240, 240, 0);\r
177                 default:\r
178                     return backColor;\r
179             }\r
180         }\r
181 \r
182         public void SetCond(ShipStatus status)\r
183         {\r
184             if (status == null)\r
185             {\r
186                 Text = "";\r
187                 BackColor = PresetColor;\r
188                 return;\r
189             }\r
190             var cond = status.Cond;\r
191             Text = cond.ToString("D");\r
192             BackColor = cond >= 50\r
193                 ? CUDColors.Yellow\r
194                 : cond >= 30\r
195                     ? PresetColor\r
196                     : cond >= 20\r
197                         ? CUDColors.Orange\r
198                         : CUDColors.Red;\r
199         }\r
200 \r
201         public void SetLevel(ShipStatus status)\r
202         {\r
203             Text = status?.Level.ToString("D");\r
204         }\r
205 \r
206         public void SetExpToNext(ShipStatus status)\r
207         {\r
208             Text = status?.ExpToNext.ToString("D");\r
209         }\r
210 \r
211         public void SetRepairTime(ShipStatus status)\r
212         {\r
213             if (status == null)\r
214             {\r
215                 Text = "";\r
216                 return;\r
217             }\r
218             SetRepairTime(status.RepairTime);\r
219         }\r
220 \r
221         public void SetRepairTime(TimeSpan span)\r
222         {\r
223             Text = $@"{(int)span.TotalHours:d2}:{span:mm\:ss}";\r
224         }\r
225 \r
226         public void SetFleet(ShipStatus status)\r
227         {\r
228             Text = status?.Fleet == null ? "" : new[] {"1", "2", "3", "4"}[status.Fleet.Number];\r
229         }\r
230 \r
231         protected override void OnSizeChanged(EventArgs args)\r
232         {\r
233             base.OnSizeChanged(args);\r
234             KeepAnchorRight();\r
235         }\r
236 \r
237         protected override void OnLayout(LayoutEventArgs args)\r
238         {\r
239             base.OnLayout(args);\r
240             KeepAnchorRight();\r
241         }\r
242 \r
243         private void KeepAnchorRight()\r
244         {\r
245             if (!AnchorRight)\r
246                 return;\r
247             if (_right == int.MinValue || _left != Left)\r
248             {\r
249                 _right = Right;\r
250                 _left = Left;\r
251                 return;\r
252             }\r
253             if (_right == Right)\r
254                 return;\r
255             _left -= Right - _right;\r
256             Location = new Point(_left, Top);\r
257         }\r
258 \r
259         protected override void OnPaint(PaintEventArgs e)\r
260         {\r
261             base.OnPaint(e);\r
262             if ((_slotStatus & SlotStatus.NormalEmpty) != 0)\r
263             {\r
264                 e.Graphics.DrawRectangle(\r
265                     Pens.Black,\r
266                     ClientSize.Width - 3 * ScaleFactor.Width, 0,\r
267                     2 * ScaleFactor.Width, 5 * ScaleFactor.Height);\r
268             }\r
269             else if ((_slotStatus & SlotStatus.SemiEquipped) != 0)\r
270             {\r
271                 e.Graphics.DrawLine(\r
272                     Pens.Black,\r
273                     ClientSize.Width - 1 * ScaleFactor.Width, 0,\r
274                     ClientSize.Width - 1 * ScaleFactor.Width, 5 * ScaleFactor.Height);\r
275             }\r
276             if ((_slotStatus & SlotStatus.ExtraEmpty) != 0)\r
277             {\r
278                 e.Graphics.DrawRectangle(\r
279                     Pens.Black,\r
280                     ClientSize.Width - 3 * ScaleFactor.Width, 8 * ScaleFactor.Height,\r
281                     2 * ScaleFactor.Width, 3 * ScaleFactor.Height);\r
282             }\r
283         }\r
284 \r
285         public void Scale()\r
286         {\r
287             Scale(ScaleFactor);\r
288         }\r
289     }\r
290 }