OSDN Git Service

横長のメインウィンドウの左右を入れ替えた横長2を追加する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / MainWindow.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using System.Drawing;\r
4 using System.Linq;\r
5 using System.Reflection;\r
6 using System.Windows.Forms;\r
7 using KancolleSniffer.Forms;\r
8 using KancolleSniffer.Notification;\r
9 using KancolleSniffer.Util;\r
10 using KancolleSniffer.View;\r
11 using KancolleSniffer.View.MainWindow;\r
12 \r
13 namespace KancolleSniffer\r
14 {\r
15     public class MainWindow\r
16     {\r
17         private readonly ResizableToolTip _toolTip = new ResizableToolTip();\r
18         private readonly ResizableToolTip _tooltipCopy = new ResizableToolTip {ShowAlways = false, AutomaticDelay = 0};\r
19         private readonly ListFormGroup _listFormGroup;\r
20         private readonly ContextMenuMain _contextMenuMain = new ContextMenuMain();\r
21         private readonly ContextMenuNotifyIcon _contextMenuNotifyIcon = new ContextMenuNotifyIcon();\r
22         private readonly Components _c;\r
23 \r
24         private IEnumerable<IUpdateContext> _updateable;\r
25         private IEnumerable<IUpdateTimers> _timers;\r
26         private Main _main;\r
27 \r
28         public Sniffer Sniffer { get; private set; }\r
29         public Config Config { get; private set; }\r
30         public Label PlayLogSign => _c.hqPanel.PlayLog;\r
31         public Notifier Notifier { get; }\r
32         public Form Form { get; }\r
33 \r
34         private class Components\r
35         {\r
36             // ReSharper disable InconsistentNaming\r
37             // ReSharper disable UnusedAutoPropertyAccessor.Local\r
38             public NotifyIcon notifyIconMain { get; set; }\r
39             public HqPanel hqPanel { get; set; }\r
40             public FleetPanel fleetPanel { get; set; }\r
41             public Label labelNDockCaption { get; set; }\r
42             public NDockPanel ndockPanel { get; set; }\r
43             public Label labelKDockCaption { get; set; }\r
44             public KDockPanel kdockPanel { get; set; }\r
45             public Label labelMissionCaption { get; set; }\r
46             public MissionPanel missionPanel { get; set; }\r
47             public Label labelMaterialCaption { get; set; }\r
48             public DropDownButton dropDownButtonMaterialHistory { get; set; }\r
49             public MaterialHistoryPanel materialHistoryPanel { get; set; }\r
50             public Label labelQuestCaption { get; set; }\r
51             public Label labelQuestCount { get; set; }\r
52             public QuestPanel questPanel { get; set; }\r
53             public Label labelAkashiRepair { get; set; }\r
54             public Label labelAkashiRepairTimer { get; set; }\r
55             public Label labelRepairListCaption { get; set; }\r
56             public Label dropDownButtonRepairList { get; set; }\r
57             public RepairListPanel panelRepairList { get; set; }\r
58             // ReSharper restore InconsistentNaming\r
59             // ReSharper restore UnusedAutoPropertyAccessor.Local\r
60         }\r
61 \r
62         public MainWindow(Main main, Form form)\r
63         {\r
64             _c = GetComponents(form);\r
65             Form = form;\r
66             _c.notifyIconMain.ContextMenuStrip = _contextMenuNotifyIcon;\r
67             Form.ContextMenuStrip = _contextMenuMain;\r
68             Form.ContextMenuStrip = _contextMenuMain;\r
69             SetupMain(main);\r
70             _listFormGroup = new ListFormGroup(this);\r
71             Notifier = new Notifier(FlashWindow, ShowTaster, PlaySound);\r
72             SetupView();\r
73         }\r
74 \r
75         private Components GetComponents(Form form)\r
76         {\r
77             var r = new Components();\r
78             foreach (var prop in typeof(Components).GetProperties())\r
79             {\r
80                 // ReSharper disable once PossibleNullReferenceException\r
81                 prop.SetValue(r,\r
82                     form.GetType().GetField(prop.Name, BindingFlags.NonPublic | BindingFlags.Instance).GetValue(form));\r
83             }\r
84             return r;\r
85         }\r
86 \r
87         private void SetupMain(Main main)\r
88         {\r
89             _main = main;\r
90             Config = main.Config;\r
91             Sniffer = main.Sniffer;\r
92         }\r
93 \r
94         private void SetupView()\r
95         {\r
96             SetScaleFactorOfDpiScaling();\r
97             if (Config.Shape == "横長2")\r
98                 ChangeHorizontalLayout();\r
99             SetupQuestPanel();\r
100             SetEventHandlers();\r
101             _c.fleetPanel.AkashiRepairTimer = _c.labelAkashiRepairTimer;\r
102             _c.fleetPanel.ShowShipOnList = ShowShipOnShipList;\r
103             _c.panelRepairList.CreateLabels(panelRepairList_Click);\r
104             _c.ndockPanel.SetClickHandler(_c.labelNDockCaption);\r
105             _c.missionPanel.SetClickHandler(_c.labelMissionCaption);\r
106             _c.materialHistoryPanel.SetClickHandler(_c.labelMaterialCaption, _c.dropDownButtonMaterialHistory);\r
107             SetupUpdateable();\r
108             PerformZoom();\r
109         }\r
110 \r
111         private void ChangeHorizontalLayout()\r
112         {\r
113             var diff = _c.missionPanel.Left - _c.hqPanel.Left;\r
114             foreach (var control in new Control[]\r
115             {\r
116                 _c.hqPanel, _c.questPanel, _c.labelQuestCaption, _c.labelQuestCount, _c.materialHistoryPanel,\r
117                 _c.dropDownButtonMaterialHistory, _c.labelMaterialCaption\r
118             })\r
119             {\r
120                 control.Left += diff;\r
121             }\r
122             foreach (var control in new Control[]\r
123             {\r
124                 _c.missionPanel, _c.labelMissionCaption, _c.labelRepairListCaption, _c.panelRepairList,\r
125                 _c.dropDownButtonRepairList, _c.labelAkashiRepair, _c.labelAkashiRepairTimer,\r
126                 _c.ndockPanel, _c.labelNDockCaption, _c.kdockPanel, _c.labelKDockCaption\r
127             })\r
128             {\r
129                 control.Left -= diff;\r
130             }\r
131         }\r
132 \r
133         private void SetEventHandlers()\r
134         {\r
135             SetMainFormEventHandler();\r
136             SetContextMenuMainEventHandler();\r
137             SetContextMenuNotifyIconEventHandler();\r
138             SetNotifyIconEventHandler();\r
139             SetRepairListEventHandler();\r
140         }\r
141 \r
142         private void SetMainFormEventHandler()\r
143         {\r
144             Form.Load += MainForm_Load;\r
145             Form.FormClosing += MainForm_FormClosing;\r
146             Form.Resize += MainForm_Resize;\r
147             Form.Activated += MainForm_Activated;\r
148         }\r
149 \r
150         private void SetContextMenuMainEventHandler()\r
151         {\r
152             _contextMenuMain.SetClickHandlers(\r
153                 _listFormGroup.ShowOrCreate,\r
154                 _main.ShowReport,\r
155                 _main.StartCapture,\r
156                 _main.ShowConfigDialog,\r
157                 Form.Close);\r
158         }\r
159 \r
160         private void SetContextMenuNotifyIconEventHandler()\r
161         {\r
162             _contextMenuNotifyIcon.SetEventHandlers(RevertFromIcon, Form.Close);\r
163         }\r
164 \r
165         private void SetNotifyIconEventHandler()\r
166         {\r
167             _c.notifyIconMain.MouseDoubleClick += notifyIconMain_MouseDoubleClick;\r
168         }\r
169 \r
170         private void SetRepairListEventHandler()\r
171         {\r
172             _c.labelRepairListCaption.Click += labelRepairListButton_Click;\r
173             _c.dropDownButtonRepairList.Click += labelRepairListButton_Click;\r
174         }\r
175 \r
176         private void SetupUpdateable()\r
177         {\r
178             _updateable = new IUpdateContext[]\r
179             {\r
180                 _c.hqPanel, _c.missionPanel, _c.kdockPanel, _c.ndockPanel, _c.materialHistoryPanel, _c.fleetPanel,\r
181                 Notifier\r
182             };\r
183             var context = new UpdateContext(Sniffer, Config, () => _main.Step);\r
184             foreach (var updateable in _updateable)\r
185                 updateable.Context = context;\r
186             _timers = new IUpdateTimers[] {_c.missionPanel, _c.kdockPanel, _c.ndockPanel, _c.fleetPanel};\r
187         }\r
188 \r
189         private void SetScaleFactorOfDpiScaling()\r
190         {\r
191             var autoScaleDimensions = new SizeF(6f, 12f); // AutoScaleDimensionの初期値\r
192             Scaler.Factor = new SizeF(Form.CurrentAutoScaleDimensions.Width / autoScaleDimensions.Width,\r
193                 Form.CurrentAutoScaleDimensions.Height / autoScaleDimensions.Height);\r
194         }\r
195 \r
196         private void SetupQuestPanel()\r
197         {\r
198             var prevHeight = _c.questPanel.Height;\r
199             _c.questPanel.CreateLabels(Config.QuestLines);\r
200             Form.Height += _c.questPanel.Height - prevHeight;\r
201         }\r
202 \r
203         public void UpdateInfo(Sniffer.Update update)\r
204         {\r
205             if (update == Sniffer.Update.Start)\r
206             {\r
207                 _c.hqPanel.Login.Visible = false;\r
208                 _c.fleetPanel.Start();\r
209                 Notifier.StopAllRepeat();\r
210                 return;\r
211             }\r
212             if (!Sniffer.Started)\r
213                 return;\r
214             if ((update & Sniffer.Update.Item) != 0)\r
215                 UpdateItemInfo();\r
216             if ((update & Sniffer.Update.Timer) != 0)\r
217                 UpdateTimers();\r
218             if ((update & Sniffer.Update.NDock) != 0)\r
219                 UpdateNDocLabels();\r
220             if ((update & Sniffer.Update.Mission) != 0)\r
221                 UpdateMissionLabels();\r
222             if ((update & Sniffer.Update.QuestList) != 0)\r
223                 UpdateQuestList();\r
224             if ((update & Sniffer.Update.Ship) != 0)\r
225                 UpdateShipInfo();\r
226             if ((update & Sniffer.Update.Battle) != 0)\r
227                 UpdateBattleInfo();\r
228             if ((update & Sniffer.Update.Cell) != 0)\r
229                 UpdateCellInfo();\r
230         }\r
231 \r
232         private void MainForm_Load(object sender, EventArgs e)\r
233         {\r
234             SuppressActivate.Start();\r
235             RestoreLocation();\r
236             if (Config.HideOnMinimized && Form.WindowState == FormWindowState.Minimized)\r
237                 Form.ShowInTaskbar = false;\r
238             if (Config.ShowHpInPercent)\r
239                 _c.fleetPanel.ToggleHpPercent();\r
240             if (Config.ShipList.Visible)\r
241                 _listFormGroup.Show();\r
242             _main.CheckVersionUpMain(_c.fleetPanel.Guide);\r
243         }\r
244 \r
245         private void MainForm_FormClosing(object sender, FormClosingEventArgs e)\r
246         {\r
247             if (!Config.ExitSilently)\r
248             {\r
249                 using var dialog = new ConfirmDialog();\r
250                 if (dialog.ShowDialog(Form) != DialogResult.Yes)\r
251                 {\r
252                     e.Cancel = true;\r
253                     return;\r
254                 }\r
255             }\r
256             _listFormGroup.Close();\r
257             Config.Location = (Form.WindowState == FormWindowState.Normal ? Form.Bounds : Form.RestoreBounds).Location;\r
258             Config.ShowHpInPercent = _c.fleetPanel.ShowHpInPercent;\r
259         }\r
260 \r
261         private void MainForm_Resize(object sender, EventArgs e)\r
262         {\r
263             if (_listFormGroup == null) // DPIが100%でないときにInitializeComponentから呼ばれるので\r
264                 return;\r
265             SuppressActivate.Start();\r
266             if (Form.WindowState == FormWindowState.Minimized)\r
267             {\r
268                 if (Config.HideOnMinimized)\r
269                     Form.ShowInTaskbar = false;\r
270             }\r
271             _listFormGroup.Main.ChangeWindowState(Form.WindowState);\r
272         }\r
273 \r
274         public readonly TimeOutChecker SuppressActivate = new TimeOutChecker();\r
275 \r
276         private void MainForm_Activated(object sender, EventArgs e)\r
277         {\r
278             if (SuppressActivate.Check())\r
279                 return;\r
280             if (NeedRaise)\r
281                 RaiseBothWindows();\r
282         }\r
283 \r
284         private bool NeedRaise => _listFormGroup.Visible && Form.WindowState != FormWindowState.Minimized;\r
285 \r
286         private void RaiseBothWindows()\r
287         {\r
288             _listFormGroup.Main.Owner = null;\r
289             Form.Owner = _listFormGroup.Main;\r
290             Form.BringToFront();\r
291             Form.Owner = null;\r
292         }\r
293 \r
294         public class TimeOutChecker\r
295         {\r
296             private DateTime _lastCheck;\r
297             private readonly TimeSpan _timeout = TimeSpan.FromMilliseconds(500);\r
298 \r
299             public void Start()\r
300             {\r
301                 _lastCheck = DateTime.Now;\r
302             }\r
303 \r
304             public bool Check()\r
305             {\r
306                 var now = DateTime.Now;\r
307                 var last = _lastCheck;\r
308                 _lastCheck = now;\r
309                 return now - last < _timeout;\r
310             }\r
311         }\r
312 \r
313         private void RevertFromIcon()\r
314         {\r
315             Form.ShowInTaskbar = true;\r
316             Form.WindowState = FormWindowState.Normal;\r
317             Form.TopMost = _listFormGroup.TopMost = Config.TopMost; // 最前面に表示されなくなることがあるのを回避する\r
318         }\r
319 \r
320         private void notifyIconMain_MouseDoubleClick(object sender, MouseEventArgs e)\r
321         {\r
322             RevertFromIcon();\r
323         }\r
324 \r
325         private void PerformZoom()\r
326         {\r
327             if (Config.Zoom == 100)\r
328             {\r
329                 ShipLabel.Name.BaseFont = Form.Font;\r
330                 ShipLabel.Name.LatinFont = LatinFont();\r
331                 return;\r
332             }\r
333             var prev = Form.CurrentAutoScaleDimensions;\r
334             foreach (var control in new Control[]\r
335             {\r
336                 Form, _c.fleetPanel.Guide, _c.hqPanel.Login,\r
337                 _contextMenuMain\r
338             }.Concat(_main.Controls))\r
339             {\r
340                 control.Font = ZoomFont(control.Font);\r
341             }\r
342             _listFormGroup.Font = ZoomFont(_listFormGroup.Font);\r
343             foreach (var toolTip in new[] {_toolTip, _tooltipCopy})\r
344             {\r
345                 toolTip.Font = ZoomFont(toolTip.Font);\r
346             }\r
347             ShipLabel.Name.BaseFont = Form.Font;\r
348             ShipLabel.Name.LatinFont = LatinFont();\r
349             var cur = Form.CurrentAutoScaleDimensions;\r
350             Scaler.Factor = Scaler.Scale(cur.Width / prev.Width, cur.Height / prev.Height);\r
351         }\r
352 \r
353         private Font ZoomFont(Font font)\r
354         {\r
355             return new Font(font.FontFamily, font.Size * Config.Zoom / 100);\r
356         }\r
357 \r
358         private Font LatinFont()\r
359         {\r
360             return new Font("Tahoma", 8f * Config.Zoom / 100);\r
361         }\r
362 \r
363         private void RestoreLocation()\r
364         {\r
365             if (Config.Location.X == int.MinValue)\r
366                 return;\r
367             if (IsTitleBarOnAnyScreen(Config.Location))\r
368                 Form.Location = Config.Location;\r
369         }\r
370 \r
371         public void ApplyConfig()\r
372         {\r
373             if (Form.TopMost != Config.TopMost)\r
374                 Form.TopMost = _listFormGroup.TopMost = Config.TopMost;\r
375             _c.hqPanel.Update();\r
376             _c.labelAkashiRepair.Visible = _c.labelAkashiRepairTimer.Visible = Config.UsePresetAkashi;\r
377         }\r
378 \r
379         public static bool IsTitleBarOnAnyScreen(Point location)\r
380         {\r
381             var rect = new Rectangle(\r
382                 new Point(location.X + SystemInformation.IconSize.Width + SystemInformation.HorizontalFocusThickness,\r
383                     location.Y + SystemInformation.CaptionHeight), new Size(60, 1));\r
384             return Screen.AllScreens.Any(screen => screen.WorkingArea.Contains(rect));\r
385         }\r
386 \r
387         private void ShowShipOnShipList(int id)\r
388         {\r
389             if (!_listFormGroup.Visible)\r
390                 return;\r
391             _listFormGroup.ShowShip(id);\r
392         }\r
393 \r
394         public void UpdateItemInfo()\r
395         {\r
396             _c.hqPanel.Update();\r
397             Notifier.NotifyShipItemCount();\r
398             _c.materialHistoryPanel.Update();\r
399             if (_listFormGroup.Visible)\r
400                 _listFormGroup.UpdateList();\r
401         }\r
402 \r
403         private void UpdateShipInfo()\r
404         {\r
405             _c.fleetPanel.Update();\r
406             Notifier.NotifyDamagedShip();\r
407             UpdateChargeInfo();\r
408             UpdateRepairList();\r
409             UpdateMissionLabels();\r
410             if (_listFormGroup.Visible)\r
411                 _listFormGroup.UpdateList();\r
412         }\r
413 \r
414         private void UpdateBattleInfo()\r
415         {\r
416             _listFormGroup.UpdateBattleResult();\r
417             _listFormGroup.UpdateAirBattleResult();\r
418             _c.fleetPanel.UpdateBattleInfo();\r
419         }\r
420 \r
421         private void UpdateCellInfo()\r
422         {\r
423             _listFormGroup.UpdateCellInfo();\r
424         }\r
425 \r
426         private void UpdateChargeInfo()\r
427         {\r
428             _c.fleetPanel.UpdateChargeInfo();\r
429         }\r
430 \r
431         private void UpdateNDocLabels()\r
432         {\r
433             _c.ndockPanel.Update();\r
434         }\r
435 \r
436         private void UpdateMissionLabels()\r
437         {\r
438             _c.missionPanel.Update();\r
439         }\r
440 \r
441         public void UpdateTimers()\r
442         {\r
443             foreach (var timer in _timers)\r
444                 timer.UpdateTimers();\r
445         }\r
446 \r
447         private void UpdateRepairList()\r
448         {\r
449             _c.panelRepairList.SetRepairList(Sniffer.RepairList);\r
450             _toolTip.SetToolTip(_c.labelRepairListCaption, new RepairShipCount(Sniffer.RepairList).ToString());\r
451         }\r
452 \r
453         private void UpdateQuestList()\r
454         {\r
455             _c.questPanel.Update(Sniffer.Quests);\r
456             _c.labelQuestCount.Text = Sniffer.Quests.Length.ToString();\r
457             Notifier.NotifyQuestComplete();\r
458         }\r
459 \r
460         private void FlashWindow()\r
461         {\r
462             Win32API.FlashWindow(Form.Handle);\r
463         }\r
464 \r
465         private void ShowTaster(string title, string message)\r
466         {\r
467             _c.notifyIconMain.ShowBalloonTip(20000, title, message, ToolTipIcon.Info);\r
468         }\r
469 \r
470         private void PlaySound(string file, int volume)\r
471         {\r
472             SoundPlayer.PlaySound(Form.Handle, file, volume);\r
473         }\r
474 \r
475         private void labelRepairListButton_Click(object sender, EventArgs e)\r
476         {\r
477             if (_c.panelRepairList.Visible)\r
478             {\r
479                 _c.panelRepairList.Visible = false;\r
480                 _c.dropDownButtonRepairList.BackColor = Control.DefaultBackColor;\r
481             }\r
482             else\r
483             {\r
484                 _c.panelRepairList.Visible = true;\r
485                 _c.panelRepairList.BringToFront();\r
486                 _c.dropDownButtonRepairList.BackColor = CustomColors.ActiveButtonColor;\r
487             }\r
488         }\r
489 \r
490         private void panelRepairList_Click(object sender, EventArgs e)\r
491         {\r
492             _c.panelRepairList.Visible = false;\r
493             _c.dropDownButtonRepairList.BackColor = Control.DefaultBackColor;\r
494         }\r
495     }\r
496 }