OSDN Git Service

ツールチップで表示する任務詳細に獲得資材を加える
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / MainForm.cs
1 // Copyright (C) 2013, 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.Collections.Generic;\r
17 using System.Diagnostics;\r
18 using System.Drawing;\r
19 using System.Globalization;\r
20 using System.IO;\r
21 using System.Linq;\r
22 using System.Net;\r
23 using System.Runtime.InteropServices;\r
24 using System.Text;\r
25 using System.Text.RegularExpressions;\r
26 using System.Threading.Tasks;\r
27 using System.Windows.Forms;\r
28 using Microsoft.CSharp.RuntimeBinder;\r
29 using static System.Math;\r
30 \r
31 namespace KancolleSniffer\r
32 {\r
33     public partial class MainForm : Form\r
34     {\r
35         private readonly Sniffer _sniffer = new Sniffer();\r
36         private readonly Config _config = new Config();\r
37         private readonly ConfigDialog _configDialog;\r
38         private readonly ProxyManager _proxyManager;\r
39         private readonly ToolTip _toolTipQuest = new ToolTip {ShowAlways = true};\r
40         private readonly ToolTip _tooltipCopy = new ToolTip {AutomaticDelay = 0};\r
41         private int _currentFleet;\r
42         private bool _combinedFleet;\r
43         private readonly Label[] _labelCheckFleets;\r
44         private readonly ShipLabels _shipLabels;\r
45         private readonly ListForm _listForm;\r
46         private readonly NotificationManager _notificationManager;\r
47         private bool _started;\r
48         private bool _timerEnabled;\r
49         private string _debugLogFile;\r
50         private IEnumerator<string> _playLog;\r
51         private DateTime _prev, _now;\r
52 \r
53         private readonly ErrorDialog _errorDialog = new ErrorDialog();\r
54         private readonly ErrorLog _errorLog;\r
55 \r
56         public MainForm()\r
57         {\r
58             InitializeComponent();\r
59             HttpProxy.AfterSessionComplete += HttpProxy_AfterSessionComplete;\r
60             _configDialog = new ConfigDialog(_config, this);\r
61             _labelCheckFleets = new[] {labelCheckFleet1, labelCheckFleet2, labelCheckFleet3, labelCheckFleet4};\r
62 \r
63             // この時点でAutoScaleDimensions == CurrentAutoScaleDimensionsなので、\r
64             // MainForm.Designer.csのAutoScaleDimensionsの6f,12fを使う。\r
65             ShipLabel.ScaleFactor = new SizeF(CurrentAutoScaleDimensions.Width / 6f,\r
66                 CurrentAutoScaleDimensions.Height / 12f);\r
67 \r
68             SetupFleetClick();\r
69             _shipLabels = new ShipLabels();\r
70             _shipLabels.CreateAkashiTimers(panelShipInfo);\r
71             _shipLabels.CreateShipLabels(panelShipInfo, ShowShipOnShipList);\r
72             _shipLabels.CreateAkashiTimers7(panel7Ships);\r
73             _shipLabels.CreateShipLabels7(panel7Ships, ShowShipOnShipList);\r
74             _shipLabels.CreateCombinedShipLabels(panelCombinedFleet, ShowShipOnShipList);\r
75             _shipLabels.CreateNDockLabels(panelDock, labelNDock_Click);\r
76             panelRepairList.CreateLabels(panelRepairList_Click);\r
77             labelPresetAkashiTimer.BackColor = ShipLabels.ColumnColors[1];\r
78             _listForm = new ListForm(_sniffer, _config) {Owner = this};\r
79             _notificationManager = new NotificationManager(Alarm);\r
80             try\r
81             {\r
82                 _config.Load();\r
83             }\r
84             catch (Exception ex)\r
85             {\r
86                 throw new ConfigFileException("設定ファイルが壊れています。", ex);\r
87             }\r
88             _proxyManager = new ProxyManager(_config, this);\r
89             _errorLog = new ErrorLog(_sniffer);\r
90             _proxyManager.UpdatePacFile();\r
91             PerformZoom();\r
92             _shipLabels.AdjustAkashiTimers();\r
93             _sniffer.LoadState();\r
94             _sniffer.RepeatingTimerController = new RepeatingTimerController(_notificationManager, _config);\r
95         }\r
96 \r
97         private class RepeatingTimerController : Sniffer.IRepeatingTimerController\r
98         {\r
99             private readonly NotificationManager _manager;\r
100             private readonly Config _config;\r
101 \r
102             public RepeatingTimerController(NotificationManager manager, Config config)\r
103             {\r
104                 _manager = manager;\r
105                 _config = config;\r
106             }\r
107 \r
108             public void Stop(string key)\r
109             {\r
110                 _manager.StopRepeat(key,\r
111                     (key == "入渠終了" || key == "遠征終了") &&\r
112                     (_config.Notifications[key].Flags & NotificationType.Cont) != 0);\r
113             }\r
114 \r
115             public void Stop(string key, int fleet) => _manager.StopRepeat(key, fleet);\r
116 \r
117             public void Suspend() => _manager.SuspendRepeat();\r
118 \r
119             public void Resume() => _manager.ResumeRepeat();\r
120         }\r
121 \r
122         public class ConfigFileException : Exception\r
123         {\r
124             public ConfigFileException(string message, Exception innerException) : base(message, innerException)\r
125             {\r
126             }\r
127         }\r
128 \r
129         private void HttpProxy_AfterSessionComplete(HttpProxy.Session session)\r
130         {\r
131             BeginInvoke(new Action<HttpProxy.Session>(ProcessRequest), session);\r
132         }\r
133 \r
134         private void ProcessRequest(HttpProxy.Session session)\r
135         {\r
136             var url = session.Request.PathAndQuery;\r
137             if (!url.Contains("kcsapi/"))\r
138                 return;\r
139             var request = session.Request.BodyAsString;\r
140             var response = session.Response.BodyAsString;\r
141             if (response == null || !response.StartsWith("svdata="))\r
142             {\r
143                 WriteDebugLog(url, request, response);\r
144                 return;\r
145             }\r
146             response = UnescapeString(response.Remove(0, "svdata=".Length));\r
147             WriteDebugLog(url, request, response);\r
148             ProcessRequestMain(url, request, response);\r
149         }\r
150 \r
151         private void ProcessRequestMain(string url, string request, string response)\r
152         {\r
153             try\r
154             {\r
155                 UpdateInfo(_sniffer.Sniff(url, request, JsonParser.Parse(response)));\r
156                 _errorLog.CheckBattleApi(url, request, response);\r
157             }\r
158 \r
159             catch (RuntimeBinderException e)\r
160             {\r
161                 if (_errorDialog.ShowDialog(this,\r
162                         "艦これに仕様変更があったか、受信内容が壊れています。",\r
163                         _errorLog.GenerateErrorLog(url, request, response, e.ToString())) == DialogResult.Abort)\r
164                     Exit();\r
165             }\r
166             catch (LogIOException e)\r
167             {\r
168                 // ReSharper disable once PossibleNullReferenceException\r
169                 if (_errorDialog.ShowDialog(this, e.Message, e.InnerException.ToString()) == DialogResult.Abort)\r
170                     Exit();\r
171             }\r
172             catch (BattleResultError)\r
173             {\r
174                 if (_errorDialog.ShowDialog(this, "戦闘結果の計算に誤りがあります。",\r
175                         _errorLog.GenerateBattleErrorLog()) == DialogResult.Abort)\r
176                     Exit();\r
177             }\r
178             catch (Exception e)\r
179             {\r
180                 if (_errorDialog.ShowDialog(this, "エラーが発生しました。",\r
181                         _errorLog.GenerateErrorLog(url, request, response, e.ToString())) == DialogResult.Abort)\r
182                     Exit();\r
183             }\r
184         }\r
185 \r
186         private void Exit()\r
187         {\r
188             _proxyManager.Shutdown();\r
189             Environment.Exit(1);\r
190         }\r
191 \r
192         private void WriteDebugLog(string url, string request, string response)\r
193         {\r
194             if (_debugLogFile != null)\r
195             {\r
196                 File.AppendAllText(_debugLogFile,\r
197                     $"date: {DateTime.Now:g}\nurl: {url}\nrequest: {request}\nresponse: {response ?? "(null)"}\n");\r
198             }\r
199         }\r
200 \r
201         private string UnescapeString(string s)\r
202         {\r
203             try\r
204             {\r
205                 var rx = new Regex(@"\\[uU]([0-9A-Fa-f]{4})");\r
206                 return rx.Replace(s,\r
207                     match => ((char)int.Parse(match.Value.Substring(2), NumberStyles.HexNumber)).ToString());\r
208             }\r
209             catch (ArgumentException)\r
210             {\r
211                 return s;\r
212             }\r
213         }\r
214 \r
215         private void UpdateInfo(Sniffer.Update update)\r
216         {\r
217             if (update == Sniffer.Update.Start)\r
218             {\r
219                 labelLogin.Visible = false;\r
220                 linkLabelGuide.Visible = false;\r
221                 _started = true;\r
222                 return;\r
223             }\r
224             if (!_started)\r
225                 return;\r
226             if (_now == DateTime.MinValue)\r
227                 _now = DateTime.Now;\r
228             if ((update & Sniffer.Update.Item) != 0)\r
229                 UpdateItemInfo();\r
230             if ((update & Sniffer.Update.Timer) != 0)\r
231                 UpdateTimers();\r
232             if ((update & Sniffer.Update.NDock) != 0)\r
233                 UpdateNDocLabels();\r
234             if ((update & Sniffer.Update.Mission) != 0)\r
235                 UpdateMissionLabels();\r
236             if ((update & Sniffer.Update.QuestList) != 0)\r
237                 UpdateQuestList();\r
238             if ((update & Sniffer.Update.Ship) != 0)\r
239                 UpdateShipInfo();\r
240             if ((update & Sniffer.Update.Battle) != 0)\r
241                 UpdateBattleInfo();\r
242         }\r
243 \r
244         private void MainForm_Load(object sender, EventArgs e)\r
245         {\r
246             RestoreLocation();\r
247             if (_config.HideOnMinimized && WindowState == FormWindowState.Minimized)\r
248                 ShowInTaskbar = false;\r
249             if (_config.ShowHpInPercent)\r
250                 _shipLabels.ToggleHpPercent();\r
251             if (_config.ShipList.Visible)\r
252                 _listForm.Show();\r
253             ApplyConfig();\r
254             ApplyDebugLogSetting();\r
255             ApplyLogSetting();\r
256             ApplyProxySetting();\r
257             CheckVersionUp((current, latest) =>\r
258             {\r
259                 if (double.Parse(latest) <= double.Parse(current))\r
260                     return;\r
261                 linkLabelGuide.Text = $"バージョン{latest}があります。";\r
262                 linkLabelGuide.LinkArea = new LinkArea(0, linkLabelGuide.Text.Length);\r
263                 linkLabelGuide.Click += (obj, ev) =>\r
264                 {\r
265                     Process.Start("https://ja.osdn.net/rel/kancollesniffer/" + latest);\r
266                 };\r
267             });\r
268         }\r
269 \r
270         public async void CheckVersionUp(Action<string, string> action)\r
271         {\r
272             var current = string.Join(".", Application.ProductVersion.Split('.').Take(2));\r
273             try\r
274             {\r
275                 var latest = (await new WebClient().DownloadStringTaskAsync("http://kancollesniffer.osdn.jp/version"))\r
276                     .TrimEnd();\r
277                 try\r
278                 {\r
279                     action(current, latest);\r
280                 }\r
281                 catch (InvalidOperationException)\r
282                 {\r
283                 }\r
284             }\r
285             catch (WebException)\r
286             {\r
287             }\r
288         }\r
289 \r
290         private void MainForm_FormClosing(object sender, FormClosingEventArgs e)\r
291         {\r
292             if (!_config.ExitSilently)\r
293             {\r
294                 using (var dialog = new ConfirmDialog())\r
295                 {\r
296                     if (dialog.ShowDialog(this) != DialogResult.Yes)\r
297                     {\r
298                         e.Cancel = true;\r
299                         return;\r
300                     }\r
301                 }\r
302             }\r
303             e.Cancel = false;\r
304             _sniffer.FlashLog();\r
305             _config.Location = (WindowState == FormWindowState.Normal ? Bounds : RestoreBounds).Location;\r
306             _config.ShowHpInPercent = _shipLabels.ShowHpInPercent;\r
307             _config.ShipList.Visible = _listForm.Visible && _listForm.WindowState == FormWindowState.Normal;\r
308             _config.Save();\r
309             _sniffer.SaveState();\r
310             _proxyManager.Shutdown();\r
311         }\r
312 \r
313         private void MainForm_Resize(object sender, EventArgs e)\r
314         {\r
315             ShowInTaskbar = !(_config.HideOnMinimized && WindowState == FormWindowState.Minimized);\r
316         }\r
317 \r
318         private void notifyIconMain_MouseDoubleClick(object sender, MouseEventArgs e)\r
319         {\r
320             NotifyIconOpenToolStripMenuItem_Click(sender, e);\r
321         }\r
322 \r
323         private void NotifyIconOpenToolStripMenuItem_Click(object sender, EventArgs e)\r
324         {\r
325             ShowInTaskbar = true;\r
326             WindowState = FormWindowState.Normal;\r
327             TopMost = _config.TopMost; // 最前面に表示されなくなることがあるのを回避する\r
328             Activate();\r
329         }\r
330 \r
331         private void ExitToolStripMenuItem_Click(object sender, EventArgs e)\r
332         {\r
333             Close();\r
334         }\r
335 \r
336         private void ConfigToolStripMenuItem_Click(object sender, EventArgs e)\r
337         {\r
338             if (_configDialog.ShowDialog(this) == DialogResult.OK)\r
339             {\r
340                 ApplyConfig();\r
341                 StopRepeatingTimer(_configDialog.RepeatSettingsChanged);\r
342             }\r
343         }\r
344 \r
345         private void StopRepeatingTimer(IEnumerable<string> names)\r
346         {\r
347             foreach (var name in names)\r
348                 _notificationManager.StopRepeat(name);\r
349         }\r
350 \r
351         private void PerformZoom()\r
352         {\r
353             if (_config.Zoom == 100)\r
354                 return;\r
355             var prev = CurrentAutoScaleDimensions;\r
356             foreach (var control in new Control[]\r
357             {\r
358                 this, _listForm, labelLogin, linkLabelGuide,\r
359                 _configDialog, _configDialog.NotificationConfigDialog,\r
360                 contextMenuStripMain, _errorDialog\r
361             })\r
362             {\r
363                 control.Font = new Font(control.Font.FontFamily, control.Font.Size * _config.Zoom / 100);\r
364             }\r
365             ShipLabel.LatinFont = new Font("Tahoma", 8f * _config.Zoom / 100);\r
366             var cur = CurrentAutoScaleDimensions;\r
367             ShipLabel.ScaleFactor = new SizeF(ShipLabel.ScaleFactor.Width * cur.Width / prev.Width,\r
368                 ShipLabel.ScaleFactor.Height * cur.Height / prev.Height);\r
369         }\r
370 \r
371         private void RestoreLocation()\r
372         {\r
373             if (_config.Location.X == int.MinValue)\r
374                 return;\r
375             if (IsTitleBarOnAnyScreen(_config.Location))\r
376                 Location = _config.Location;\r
377         }\r
378 \r
379         private void ApplyConfig()\r
380         {\r
381             _listForm.TopMost = TopMost = _config.TopMost;\r
382             _sniffer.Item.MarginShips = _config.MarginShips;\r
383             UpdateNumOfShips();\r
384             _sniffer.Item.MarginEquips = _config.MarginEquips;\r
385             UpdateNumOfEquips();\r
386             _sniffer.Achievement.ResetHours = _config.ResetHours;\r
387             labelAkashiRepair.Visible = labelAkashiRepairTimer.Visible =\r
388                 labelPresetAkashiTimer.Visible = _config.UsePresetAkashi;\r
389         }\r
390 \r
391         public void ApplyDebugLogSetting()\r
392         {\r
393             _debugLogFile = _config.DebugLogging ? _config.DebugLogFile : null;\r
394         }\r
395 \r
396         public bool ApplyProxySetting()\r
397         {\r
398             return _proxyManager.ApplyConfig();\r
399         }\r
400 \r
401         public void ApplyLogSetting()\r
402         {\r
403             LogServer.OutputDir = _config.Log.OutputDir;\r
404             LogServer.MaterialHistory = _sniffer.Material.MaterialHistory;\r
405             _sniffer.EnableLog(_config.Log.On ? LogType.All : LogType.None);\r
406             _sniffer.MaterialLogInterval = _config.Log.MaterialLogInterval;\r
407             _sniffer.LogOutputDir = _config.Log.OutputDir;\r
408         }\r
409 \r
410         public static bool IsTitleBarOnAnyScreen(Point location)\r
411         {\r
412             var rect = new Rectangle(\r
413                 new Point(location.X + SystemInformation.IconSize.Width + SystemInformation.HorizontalFocusThickness,\r
414                     location.Y + SystemInformation.CaptionHeight), new Size(60, 1));\r
415             return Screen.AllScreens.Any(screen => screen.WorkingArea.Contains(rect));\r
416         }\r
417 \r
418         private void timerMain_Tick(object sender, EventArgs e)\r
419         {\r
420             if (_timerEnabled)\r
421             {\r
422                 try\r
423                 {\r
424                     _now = DateTime.Now;\r
425                     UpdateTimers();\r
426                     NotifyTimers();\r
427                     _prev = _now;\r
428                 }\r
429                 catch (Exception ex)\r
430                 {\r
431                     if (_errorDialog.ShowDialog(this, "エラーが発生しました。", ex.ToString()) == DialogResult.Abort)\r
432                         Application.Exit();\r
433                 }\r
434             }\r
435             if (_playLog == null || _configDialog.Visible)\r
436             {\r
437                 labelPlayLog.Visible = false;\r
438                 return;\r
439             }\r
440             PlayLog();\r
441         }\r
442 \r
443         public void SetPlayLog(string file)\r
444         {\r
445             _playLog = File.ReadLines(file).GetEnumerator();\r
446         }\r
447 \r
448         private void PlayLog()\r
449         {\r
450             var lines = new List<string>();\r
451             foreach (var s in new[] {"url: ", "request: ", "response: "})\r
452             {\r
453                 do\r
454                 {\r
455                     if (!_playLog.MoveNext() || _playLog.Current == null)\r
456                     {\r
457                         labelPlayLog.Visible = false;\r
458                         return;\r
459                     }\r
460                 } while (!_playLog.Current.StartsWith(s));\r
461                 lines.Add(_playLog.Current.Substring(s.Length));\r
462             }\r
463             labelPlayLog.Visible = !labelPlayLog.Visible;\r
464             ProcessRequestMain(lines[0], lines[1], lines[2]);\r
465         }\r
466 \r
467         private void ShowShipOnShipList(object sender, EventArgs ev)\r
468         {\r
469             if (!_listForm.Visible)\r
470                 return;\r
471             var idx = (int)((Control)sender).Tag;\r
472             var statuses = _sniffer.GetShipStatuses(_currentFleet);\r
473             if (statuses.Length <= idx)\r
474                 return;\r
475             _listForm.ShowShip(statuses[idx].Id);\r
476         }\r
477 \r
478         private void UpdateItemInfo()\r
479         {\r
480             UpdateNumOfShips();\r
481             UpdateNumOfEquips();\r
482             _notificationManager.Flash();\r
483             labelNumOfBuckets.Text = _sniffer.Material.MaterialHistory[(int)Material.Bucket].Now.ToString("D");\r
484             UpdateBucketHistory();\r
485             var ac = _sniffer.Achievement.Value;\r
486             if (ac >= 10000)\r
487                 ac = 9999;\r
488             labelAchievement.Text = ac >= 1000 ? ((int)ac).ToString("D") : ac.ToString("F1");\r
489             toolTipAchievement.SetToolTip(labelAchievement,\r
490                 "今月 " + _sniffer.Achievement.ValueOfMonth.ToString("F1") + "\n" +\r
491                 "EO " + _sniffer.ExMap.Achievement);\r
492             UpdateMaterialHistry();\r
493             if (_listForm.Visible)\r
494                 _listForm.UpdateList();\r
495         }\r
496 \r
497         private void UpdateNumOfShips()\r
498         {\r
499             var item = _sniffer.Item;\r
500             labelNumOfShips.Text = $"{item.NowShips:D}/{item.MaxShips:D}";\r
501             labelNumOfShips.ForeColor = item.TooManyShips ? CUDColor.Red : Color.Black;\r
502             if (item.AlarmShips)\r
503             {\r
504                 var message = $"残り{_sniffer.Item.MaxShips - _sniffer.Item.NowShips:D}隻";\r
505                 _notificationManager.Enqueue("艦娘数超過", message);\r
506                 item.AlarmShips = false;\r
507             }\r
508         }\r
509 \r
510         private void UpdateNumOfEquips()\r
511         {\r
512             var item = _sniffer.Item;\r
513             labelNumOfEquips.Text = $"{item.NowEquips:D}/{item.MaxEquips:D}";\r
514             labelNumOfEquips.ForeColor = item.TooManyEquips ? CUDColor.Red : Color.Black;\r
515             if (item.AlarmEquips)\r
516             {\r
517                 var message = $"残り{_sniffer.Item.MaxEquips - _sniffer.Item.NowEquips:D}個";\r
518                 _notificationManager.Enqueue("装備数超過", message);\r
519                 item.AlarmEquips = false;\r
520             }\r
521         }\r
522 \r
523         private void UpdateBucketHistory()\r
524         {\r
525             var count = _sniffer.Material.MaterialHistory[(int)Material.Bucket];\r
526             var day = CutOverflow(count.Now - count.BegOfDay, 999);\r
527             var week = CutOverflow(count.Now - count.BegOfWeek, 999);\r
528             labelBucketHistory.Text = $"{day:+#;-#;±0} 今日\n{week:+#;-#;±0} 今週";\r
529         }\r
530 \r
531         private void UpdateMaterialHistry()\r
532         {\r
533             var labels = new[] {labelFuelHistory, labelBulletHistory, labelSteelHistory, labelBouxiteHistory};\r
534             var text = new[] {"燃料", "弾薬", "鋼材", "ボーキ"};\r
535             for (var i = 0; i < labels.Length; i++)\r
536             {\r
537                 var count = _sniffer.Material.MaterialHistory[i];\r
538                 var port = CutOverflow(count.Now - _sniffer.Material.PrevPort[i], 99999);\r
539                 var day = CutOverflow(count.Now - count.BegOfDay, 99999);\r
540                 var week = CutOverflow(count.Now - count.BegOfWeek, 99999);\r
541                 labels[i].Text = $"{text[i]}\n{port:+#;-#;±0}\n{day:+#;-#;±0}\n{week:+#;-#;±0}";\r
542             }\r
543         }\r
544 \r
545         private int CutOverflow(int value, int limit)\r
546         {\r
547             if (value > limit)\r
548                 return limit;\r
549             if (value < -limit)\r
550                 return -limit;\r
551             return value;\r
552         }\r
553 \r
554         private void UpdateShipInfo()\r
555         {\r
556             UpdatePanelShipInfo();\r
557             NotifyDamagedShip();\r
558             UpdateChargeInfo();\r
559             UpdateRepairList();\r
560             if (_listForm.Visible)\r
561                 _listForm.UpdateList();\r
562         }\r
563 \r
564         private void UpdatePanelShipInfo()\r
565         {\r
566             var statuses = _sniffer.GetShipStatuses(_currentFleet);\r
567             panel7Ships.Visible = statuses.Length == 7;\r
568             _shipLabels.SetShipLabels(statuses);\r
569             if (_sniffer.CombinedFleetType == 0)\r
570                 _combinedFleet = false;\r
571             labelFleet1.Text = _combinedFleet ? "連合" : "第一";\r
572             panelCombinedFleet.Visible = _combinedFleet;\r
573             if (_combinedFleet)\r
574                 _shipLabels.SetCombinedShipLabels(_sniffer.GetShipStatuses(0), _sniffer.GetShipStatuses(1));\r
575             UpdateAkashiTimer();\r
576             UpdateFighterPower(_combinedFleet);\r
577             UpdateLoS();\r
578             UpdateCondTimers();\r
579         }\r
580 \r
581         private void NotifyDamagedShip()\r
582         {\r
583             if (!_sniffer.BadlyDamagedShips.Any())\r
584                 return;\r
585             _notificationManager.Enqueue("大破警告", string.Join(" ", _sniffer.BadlyDamagedShips));\r
586             _notificationManager.Flash();\r
587         }\r
588 \r
589         public void UpdateFighterPower(bool combined)\r
590         {\r
591             var fp = combined\r
592                 ? _sniffer.GetFighterPower(0).Zip(_sniffer.GetFighterPower(1), (a, b) => a + b).ToArray()\r
593                 : _sniffer.GetFighterPower(_currentFleet);\r
594             labelFighterPower.Text = fp[0].ToString("D");\r
595             var cr = combined\r
596                 ? _sniffer.GetContactTriggerRate(0) + _sniffer.GetContactTriggerRate(1)\r
597                 : _sniffer.GetContactTriggerRate(_currentFleet);\r
598             var text = "制空: " + (fp[0] == fp[1] ? $"{fp[0]}" : $"{fp[0]}~{fp[1]}") +\r
599                        $" 触接: {cr * 100:f1}";\r
600             toolTipFighterPower.SetToolTip(labelFighterPower, text);\r
601             toolTipFighterPower.SetToolTip(labelFighterPowerCaption, text);\r
602         }\r
603 \r
604         private void UpdateLoS()\r
605         {\r
606             labelLoS.Text = RoundDown(_sniffer.GetFleetLineOfSights(_currentFleet, 1)).ToString("F1");\r
607             var text = $"係数3: {RoundDown(_sniffer.GetFleetLineOfSights(_currentFleet, 3)):F1}\r\n" +\r
608                        $"係数4: {RoundDown(_sniffer.GetFleetLineOfSights(_currentFleet, 4)):F1}";\r
609             toolTipLoS.SetToolTip(labelLoS, text);\r
610             toolTipLoS.SetToolTip(labelLoSCaption, text);\r
611         }\r
612 \r
613         private double RoundDown(double number)\r
614         {\r
615             return Floor(number * 10) / 10.0;\r
616         }\r
617 \r
618         private void UpdateBattleInfo()\r
619         {\r
620             ResetBattleInfo();\r
621             _listForm.UpdateBattleResult();\r
622             if (_sniffer.Battle.BattleState == BattleState.None)\r
623                 return;\r
624             panelBattleInfo.BringToFront();\r
625             var battle = _sniffer.Battle;\r
626             labelFormation.Text = new[] {"同航戦", "反航戦", "T字有利", "T字不利"}[battle.Formation[2] - 1];\r
627             UpdateBattleFighterPower();\r
628             if ((_config.Spoilers & Spoiler.ResultRank) != 0)\r
629                 ShowResultRank();\r
630             if (_sniffer.Battle.BattleState == BattleState.Day)\r
631                 _listForm.UpdateAirBattleResult();\r
632         }\r
633 \r
634         private void ResetBattleInfo()\r
635         {\r
636             labelFormation.Text = "";\r
637             labelEnemyFighterPower.Text = "";\r
638             labelFighterPower.ForeColor = DefaultForeColor;\r
639             labelResultRank.Text = "判定";\r
640             panelBattleInfo.Visible = _sniffer.Battle.BattleState != BattleState.None;\r
641         }\r
642 \r
643         private void UpdateBattleFighterPower()\r
644         {\r
645             var battle = _sniffer.Battle;\r
646             var power = battle.EnemyFighterPower;\r
647             labelEnemyFighterPower.Text = power.AirCombat + power.UnknownMark;\r
648             if (power.AirCombat != power.Interception)\r
649             {\r
650                 var text = "防空: " + power.Interception + power.UnknownMark;\r
651                 toolTipFighterPower.SetToolTip(labelEnemyFighterPower, text);\r
652                 toolTipFighterPower.SetToolTip(labelEnemyFighterPowerCaption, text);\r
653             }\r
654             UpdateFighterPower(_sniffer.CombinedFleetType > 0 && battle.EnemyIsCombined);\r
655             labelFighterPower.ForeColor = new[]\r
656                 {DefaultForeColor, DefaultForeColor, CUDColor.Blue, CUDColor.Green, CUDColor.Orange, CUDColor.Red}[\r
657                 battle.AirControlLevel + 1];\r
658         }\r
659 \r
660         private void ShowResultRank()\r
661         {\r
662             var result = new[] {"完全S", "勝利S", "勝利A", "勝利B", "敗北C", "敗北D", "敗北E"};\r
663             labelResultRank.Text = result[(int)_sniffer.Battle.ResultRank];\r
664         }\r
665 \r
666         private void labelResultRank_Click(object sender, EventArgs e)\r
667         {\r
668             ShowResultRank();\r
669         }\r
670 \r
671         private void UpdateChargeInfo()\r
672         {\r
673             var fuelSq = new[] {labelFuelSq1, labelFuelSq2, labelFuelSq3, labelFuelSq4};\r
674             var bullSq = new[] {labelBullSq1, labelBullSq2, labelBullSq3, labelBullSq4};\r
675 \r
676             for (var i = 0; i < fuelSq.Length; i++)\r
677             {\r
678                 var stat = _sniffer.ChargeStatuses[i];\r
679                 fuelSq[i].ImageIndex = stat.Fuel;\r
680                 bullSq[i].ImageIndex = stat.Bull;\r
681             }\r
682         }\r
683 \r
684         private void UpdateNDocLabels()\r
685         {\r
686             _shipLabels.SetNDockLabels(_sniffer.NDock);\r
687         }\r
688 \r
689 \r
690         private void labelNDock_Click(object sender, EventArgs e)\r
691         {\r
692             _config.ShowEndTime ^= TimerKind.NDock;\r
693             UpdateTimers();\r
694         }\r
695 \r
696         private void UpdateMissionLabels()\r
697         {\r
698             foreach (var entry in\r
699                 new[] {labelMissionName1, labelMissionName2, labelMissionName3}.Zip(_sniffer.Missions,\r
700                     (label, mission) => new {label, mission.Name}))\r
701                 entry.label.Text = entry.Name;\r
702         }\r
703 \r
704         private void labelMission_Click(object sender, EventArgs e)\r
705         {\r
706             _config.ShowEndTime ^= TimerKind.Mission;\r
707             UpdateTimers();\r
708         }\r
709 \r
710         private void UpdateTimers()\r
711         {\r
712             var mission = new[] {labelMission1, labelMission2, labelMission3};\r
713             for (var i = 0; i < mission.Length; i++)\r
714             {\r
715                 var entry = _sniffer.Missions[i];\r
716                 SetTimerColor(mission[i], entry.Timer, _now);\r
717                 mission[i].Text = entry.Timer.ToString(_now, (_config.ShowEndTime & TimerKind.Mission) != 0);\r
718             }\r
719             for (var i = 0; i < _sniffer.NDock.Length; i++)\r
720             {\r
721                 var entry = _sniffer.NDock[i];\r
722                 _shipLabels.SetNDockTimer(i, entry.Timer, _now, (_config.ShowEndTime & TimerKind.NDock) != 0);\r
723             }\r
724             var kdock = new[] {labelConstruct1, labelConstruct2, labelConstruct3, labelConstruct4};\r
725             for (var i = 0; i < kdock.Length; i++)\r
726             {\r
727                 var timer = _sniffer.KDock[i];\r
728                 SetTimerColor(kdock[i], timer, _now);\r
729                 kdock[i].Text = timer.ToString(_now);\r
730             }\r
731             UpdateCondTimers();\r
732             UpdateAkashiTimer();\r
733             _timerEnabled = true;\r
734         }\r
735 \r
736         private void NotifyTimers()\r
737         {\r
738             for (var i = 0; i < _sniffer.Missions.Length; i++)\r
739             {\r
740                 var entry = _sniffer.Missions[i];\r
741                 CheckAlarm("遠征終了", entry.Timer, i + 1, entry.Name);\r
742             }\r
743             for (var i = 0; i < _sniffer.NDock.Length; i++)\r
744             {\r
745                 var entry = _sniffer.NDock[i];\r
746                 CheckAlarm("入渠終了", entry.Timer, i, entry.Name);\r
747             }\r
748             for (var i = 0; i < _sniffer.KDock.Length; i++)\r
749             {\r
750                 var timer = _sniffer.KDock[i];\r
751                 CheckAlarm("建造完了", timer, 0, $"第{i + 1:D}ドック");\r
752             }\r
753             NotifyCondTimers();\r
754             NotifyAkashiTimer();\r
755             _notificationManager.Flash();\r
756         }\r
757 \r
758         private void CheckAlarm(string key, AlarmTimer timer, int fleet, string subject)\r
759         {\r
760             if (timer.CheckAlarm(_prev, _now))\r
761             {\r
762                 SetNotification(key, fleet, subject);\r
763                 return;\r
764             }\r
765             var pre = TimeSpan.FromSeconds(_config.Notifications[key].PreliminaryPeriod);\r
766             if (pre == TimeSpan.Zero)\r
767                 return;\r
768             if (timer.CheckAlarm(_prev + pre, _now + pre))\r
769                 SetPreNotification(key, fleet, subject);\r
770         }\r
771 \r
772         private void SetTimerColor(Label label, AlarmTimer timer, DateTime now)\r
773         {\r
774             label.ForeColor = timer.IsFinished(now) ? CUDColor.Red : Color.Black;\r
775         }\r
776 \r
777         private void UpdateCondTimers()\r
778         {\r
779             DateTime timer;\r
780             if (_combinedFleet)\r
781             {\r
782                 var timer1 = _sniffer.GetConditionTimer(0);\r
783                 var timer2 = _sniffer.GetConditionTimer(1);\r
784                 timer = timer2 > timer1 ? timer2 : timer1;\r
785             }\r
786             else\r
787             {\r
788                 timer = _sniffer.GetConditionTimer(_currentFleet);\r
789             }\r
790             if (timer == DateTime.MinValue)\r
791             {\r
792                 labelCondTimerTitle.Text = "";\r
793                 labelCondTimer.Text = "";\r
794                 return;\r
795             }\r
796             var span = TimeSpan.FromSeconds(Ceiling((timer - _now).TotalSeconds));\r
797             if (span >= TimeSpan.FromMinutes(9))\r
798             {\r
799                 labelCondTimerTitle.Text = "cond40まで";\r
800                 labelCondTimer.Text = (span - TimeSpan.FromMinutes(9)).ToString(@"mm\:ss");\r
801                 labelCondTimer.ForeColor = DefaultForeColor;\r
802             }\r
803             else\r
804             {\r
805                 labelCondTimerTitle.Text = "cond49まで";\r
806                 labelCondTimer.Text = (span >= TimeSpan.Zero ? span : TimeSpan.Zero).ToString(@"mm\:ss");\r
807                 labelCondTimer.ForeColor = span <= TimeSpan.Zero ? CUDColor.Red : DefaultForeColor;\r
808             }\r
809         }\r
810 \r
811         private void NotifyCondTimers()\r
812         {\r
813             var notice = _sniffer.GetConditionNotice(_prev, _now);\r
814             var pre = TimeSpan.FromSeconds(_config.Notifications["疲労回復"].PreliminaryPeriod);\r
815             var preNotice = pre == TimeSpan.Zero\r
816                 ? new int[ShipInfo.FleetCount]\r
817                 : _sniffer.GetConditionNotice(_prev + pre, _now + pre);\r
818             for (var i = 0; i < ShipInfo.FleetCount; i++)\r
819             {\r
820                 if (_config.NotifyConditions.Contains(notice[i]))\r
821                 {\r
822                     SetNotification("疲労回復" + notice[i], i, "cond" + notice[i]);\r
823                 }\r
824                 else if (_config.NotifyConditions.Contains(preNotice[i]))\r
825                 {\r
826                     SetPreNotification("疲労回復" + preNotice[i], i, "cond" + notice[i]);\r
827                 }\r
828             }\r
829         }\r
830 \r
831         private void UpdateAkashiTimer()\r
832         {\r
833             if (_config.UsePresetAkashi)\r
834                 UpdatePresetAkashiTimer();\r
835             var statuses = _sniffer.GetShipStatuses(_currentFleet);\r
836             _shipLabels.SetAkashiTimer(statuses,\r
837                 _sniffer.AkashiTimer.GetTimers(_currentFleet));\r
838         }\r
839 \r
840         private void UpdatePresetAkashiTimer()\r
841         {\r
842             var akashi = _sniffer.AkashiTimer;\r
843             var span = akashi.PresetDeckTimer;\r
844             var color = span == TimeSpan.Zero && akashi.CheckPresetRepairing() ? CUDColor.Red : DefaultForeColor;\r
845             var text = span == TimeSpan.MinValue ? "" : span.ToString(@"mm\:ss");\r
846             labelAkashiRepairTimer.ForeColor = color;\r
847             labelAkashiRepairTimer.Text = text;\r
848             if (akashi.CheckPresetRepairing() && !akashi.CheckRepairing(_currentFleet))\r
849             {\r
850                 labelPresetAkashiTimer.ForeColor = color;\r
851                 labelPresetAkashiTimer.Text = text;\r
852             }\r
853             else\r
854             {\r
855                 labelPresetAkashiTimer.ForeColor = DefaultForeColor;\r
856                 labelPresetAkashiTimer.Text = "";\r
857             }\r
858         }\r
859 \r
860         private void NotifyAkashiTimer()\r
861         {\r
862             var akashi = _sniffer.AkashiTimer;\r
863             var msgs = akashi.GetNotice(_prev, _now);\r
864             if (msgs.Length == 0)\r
865             {\r
866                 _notificationManager.StopRepeat("泊地修理");\r
867                 return;\r
868             }\r
869             if (!akashi.CheckRepairing() && !(akashi.CheckPresetRepairing() && _config.UsePresetAkashi))\r
870             {\r
871                 _notificationManager.StopRepeat("泊地修理");\r
872                 return;\r
873             }\r
874             var skipPreliminary = false;\r
875             if (msgs[0].Proceeded == "20分経過しました。")\r
876             {\r
877                 SetNotification("泊地修理20分経過", msgs[0].Proceeded);\r
878                 msgs[0].Proceeded = "";\r
879                 skipPreliminary = true;\r
880                 // 修理完了がいるかもしれないので続ける\r
881             }\r
882             for (var i = 0; i < ShipInfo.FleetCount; i++)\r
883             {\r
884                 if (msgs[i].Proceeded != "")\r
885                     SetNotification("泊地修理進行", i, msgs[i].Proceeded);\r
886                 if (msgs[i].Completed != "")\r
887                     SetNotification("泊地修理完了", i, msgs[i].Completed);\r
888             }\r
889             var pre = TimeSpan.FromSeconds(_config.Notifications["泊地修理20分経過"].PreliminaryPeriod);\r
890             if (skipPreliminary || pre == TimeSpan.Zero)\r
891                 return;\r
892             if ((msgs = akashi.GetNotice(_prev + pre, _now + pre))[0].Proceeded == "20分経過しました。")\r
893                 SetPreNotification("泊地修理20分経過", 0, msgs[0].Proceeded);\r
894         }\r
895 \r
896         private void SetNotification(string key, string subject)\r
897         {\r
898             SetNotification(key, 0, subject);\r
899         }\r
900 \r
901         private void SetNotification(string key, int fleet, string subject)\r
902         {\r
903             var spec = _config.Notifications[_notificationManager.KeyToName(key)];\r
904             _notificationManager.Enqueue(key, fleet, subject,\r
905                 (spec.Flags & _config.NotificationFlags & NotificationType.Repeat) == 0 ? 0 : spec.RepeatInterval);\r
906         }\r
907 \r
908         private void SetPreNotification(string key, int fleet, string subject)\r
909         {\r
910             var spec = _config.Notifications[_notificationManager.KeyToName(key)];\r
911             if ((spec.Flags & NotificationType.Preliminary) != 0)\r
912                 _notificationManager.Enqueue(key, fleet, subject, 0, true);\r
913         }\r
914 \r
915         private void UpdateRepairList()\r
916         {\r
917             panelRepairList.SetRepairList(_sniffer.RepairList);\r
918         }\r
919 \r
920         private void UpdateQuestList()\r
921         {\r
922             var category = new[]\r
923             {\r
924                 labelQuestColor1, labelQuestColor2, labelQuestColor3, labelQuestColor4, labelQuestColor5,\r
925                 labelQuestColor6\r
926             };\r
927             var name = new[] {labelQuest1, labelQuest2, labelQuest3, labelQuest4, labelQuest5, labelQuest6};\r
928             var count = new[]\r
929             {\r
930                 labelQuestCount1, labelQuestCount2, labelQuestCount3, labelQuestCount4, labelQuestCount5,\r
931                 labelQuestCount6\r
932             };\r
933             var progress = new[]\r
934                 {labelProgress1, labelProgress2, labelProgress3, labelProgress4, labelProgress5, labelProgress6};\r
935             var quests = _sniffer.Quests;\r
936             for (var i = 0; i < name.Length; i++)\r
937             {\r
938                 if (i < quests.Length)\r
939                 {\r
940                     category[i].BackColor = quests[i].Color;\r
941                     name[i].Text = quests[i].Name;\r
942                     progress[i].Text = $"{quests[i].Progress:D}%";\r
943                     _toolTipQuest.SetToolTip(name[i], quests[i].ToToolTip());\r
944                     var c = quests[i].Count;\r
945                     if (c.Id == 0)\r
946                     {\r
947                         count[i].Text = "";\r
948                         count[i].ForeColor = Color.Black;\r
949                         _toolTipQuest.SetToolTip(count[i], "");\r
950                         continue;\r
951                     }\r
952                     count[i].Text = " " + c;\r
953                     count[i].ForeColor = c.Cleared ? CUDColor.Green : Color.Black;\r
954                     _toolTipQuest.SetToolTip(count[i], c.ToToolTip());\r
955                 }\r
956                 else\r
957                 {\r
958                     category[i].BackColor = DefaultBackColor;\r
959                     name[i].Text = count[i].Text = progress[i].Text = "";\r
960                     _toolTipQuest.SetToolTip(name[i], "");\r
961                     _toolTipQuest.SetToolTip(count[i], "");\r
962                 }\r
963             }\r
964         }\r
965 \r
966         private void Alarm(string balloonTitle, string balloonMessage, string name)\r
967         {\r
968             var flags = _config.Notifications[name].Flags;\r
969             var effective = _config.NotificationFlags & _config.Notifications[name].Flags;\r
970             if ((effective & NotificationType.FlashWindow) != 0)\r
971                 Win32API.FlashWindow(Handle);\r
972             if ((effective & NotificationType.ShowBaloonTip) != 0)\r
973                 notifyIconMain.ShowBalloonTip(20000, balloonTitle, balloonMessage, ToolTipIcon.Info);\r
974             if ((effective & NotificationType.PlaySound) != 0)\r
975                 PlaySound(_config.Sounds[name], _config.Sounds.Volume);\r
976             if (_config.Pushbullet.On && (flags & NotificationType.Push) != 0)\r
977             {\r
978                 Task.Run(() =>\r
979                 {\r
980                     PushNotification.PushToPushbullet(_config.Pushbullet.Token, balloonTitle, balloonMessage);\r
981                 });\r
982             }\r
983             if (_config.Pushover.On && (flags & NotificationType.Push) != 0)\r
984             {\r
985                 Task.Run(() =>\r
986                 {\r
987                     PushNotification.PushToPushover(_config.Pushover.ApiKey, _config.Pushover.UserKey,\r
988                         balloonTitle, balloonMessage);\r
989                 });\r
990             }\r
991         }\r
992 \r
993         [DllImport("winmm.dll")]\r
994         private static extern int mciSendString(String command,\r
995             StringBuilder buffer, int bufferSize, IntPtr hwndCallback);\r
996 \r
997 // ReSharper disable InconsistentNaming\r
998         private const int MM_MCINOTIFY = 0x3B9;\r
999 \r
1000         private const int MCI_NOTIFY_SUCCESSFUL = 1;\r
1001 // ReSharper restore InconsistentNaming\r
1002 \r
1003         public void PlaySound(string file, int volume)\r
1004         {\r
1005             if (!File.Exists(file))\r
1006                 return;\r
1007             mciSendString("close sound", null, 0, IntPtr.Zero);\r
1008             if (mciSendString("open \"" + file + "\" type mpegvideo alias sound", null, 0, IntPtr.Zero) != 0)\r
1009                 return;\r
1010             mciSendString("setaudio sound volume to " + volume * 10, null, 0, IntPtr.Zero);\r
1011             mciSendString("play sound notify", null, 0, Handle);\r
1012         }\r
1013 \r
1014         protected override void WndProc(ref Message m)\r
1015         {\r
1016             if (m.Msg == MM_MCINOTIFY && (int)m.WParam == MCI_NOTIFY_SUCCESSFUL)\r
1017                 mciSendString("close sound", null, 0, IntPtr.Zero);\r
1018             base.WndProc(ref m);\r
1019         }\r
1020 \r
1021         private void SetupFleetClick()\r
1022         {\r
1023             var labels = new[]\r
1024             {\r
1025                 new[] {labelFleet1, labelFleet2, labelFleet3, labelFleet4},\r
1026                 new[] {labelFuelSq1, labelFuelSq2, labelFuelSq3, labelFuelSq4},\r
1027                 new[] {labelBullSq1, labelBullSq2, labelBullSq3, labelBullSq4}\r
1028             };\r
1029             foreach (var a in labels)\r
1030             {\r
1031                 for (var fleet = 0; fleet < labels[0].Length; fleet++)\r
1032                 {\r
1033                     a[fleet].Tag = fleet;\r
1034                     a[fleet].Click += labelFleet_Click;\r
1035                 }\r
1036             }\r
1037         }\r
1038 \r
1039         private void labelFleet_Click(object sender, EventArgs e)\r
1040         {\r
1041             if (!_started)\r
1042                 return;\r
1043             var fleet = (int)((Label)sender).Tag;\r
1044             if (_currentFleet == fleet)\r
1045             {\r
1046                 if (fleet > 0)\r
1047                     return;\r
1048                 _combinedFleet = _sniffer.CombinedFleetType > 0 && !_combinedFleet;\r
1049                 UpdatePanelShipInfo();\r
1050                 return;\r
1051             }\r
1052             _combinedFleet = false;\r
1053             _currentFleet = fleet;\r
1054             foreach (var label in _labelCheckFleets)\r
1055                 label.Visible = false;\r
1056             _labelCheckFleets[fleet].Visible = true;\r
1057             UpdatePanelShipInfo();\r
1058         }\r
1059 \r
1060         private void labelFleet1_MouseHover(object sender, EventArgs e)\r
1061         {\r
1062             labelFleet1.Text = _currentFleet == 0 && _sniffer.CombinedFleetType > 0 && !_combinedFleet ? "連合" : "第一";\r
1063         }\r
1064 \r
1065         private void labelFleet1_MouseLeave(object sender, EventArgs e)\r
1066         {\r
1067             labelFleet1.Text = _combinedFleet ? "連合" : "第一";\r
1068         }\r
1069 \r
1070         private readonly Color _activeButtonColor = Color.FromArgb(152, 179, 208);\r
1071 \r
1072         private void labelBucketHistoryButton_Click(object sender, EventArgs e)\r
1073         {\r
1074             if (labelBucketHistory.Visible)\r
1075             {\r
1076                 labelBucketHistory.Visible = false;\r
1077                 labelBucketHistoryButton.BackColor = DefaultBackColor;\r
1078             }\r
1079             else\r
1080             {\r
1081                 labelBucketHistory.Visible = true;\r
1082                 labelBucketHistory.BringToFront();\r
1083                 labelBucketHistoryButton.BackColor = _activeButtonColor;\r
1084             }\r
1085         }\r
1086 \r
1087         private void labelBucketHistory_Click(object sender, EventArgs e)\r
1088         {\r
1089             labelBucketHistory.Visible = false;\r
1090             labelBucketHistoryButton.BackColor = DefaultBackColor;\r
1091         }\r
1092 \r
1093         private void labelMaterialHistoryButton_Click(object sender, EventArgs e)\r
1094         {\r
1095             if (panelMaterialHistory.Visible)\r
1096             {\r
1097                 panelMaterialHistory.Visible = false;\r
1098                 labelMaterialHistoryButton.BackColor = DefaultBackColor;\r
1099             }\r
1100             else\r
1101             {\r
1102                 panelMaterialHistory.Visible = true;\r
1103                 panelMaterialHistory.BringToFront();\r
1104                 labelMaterialHistoryButton.BackColor = _activeButtonColor;\r
1105             }\r
1106         }\r
1107 \r
1108         private void panelMaterialHistory_Click(object sender, EventArgs e)\r
1109         {\r
1110             panelMaterialHistory.Visible = false;\r
1111             labelMaterialHistoryButton.BackColor = DefaultBackColor;\r
1112         }\r
1113 \r
1114         public void ResetAchievemnt()\r
1115         {\r
1116             _sniffer.Achievement.Reset();\r
1117             UpdateItemInfo();\r
1118         }\r
1119 \r
1120         private void labelRepairListButton_Click(object sender, EventArgs e)\r
1121         {\r
1122             if (panelRepairList.Visible)\r
1123             {\r
1124                 panelRepairList.Visible = false;\r
1125                 labelRepairListButton.BackColor = DefaultBackColor;\r
1126             }\r
1127             else\r
1128             {\r
1129                 panelRepairList.Visible = true;\r
1130                 panelRepairList.BringToFront();\r
1131                 labelRepairListButton.BackColor = _activeButtonColor;\r
1132             }\r
1133         }\r
1134 \r
1135         private void panelRepairList_Click(object sender, EventArgs e)\r
1136         {\r
1137             panelRepairList.Visible = false;\r
1138             labelRepairListButton.BackColor = DefaultBackColor;\r
1139         }\r
1140 \r
1141         private void ShipListToolStripMenuItem_Click(object sender, EventArgs e)\r
1142         {\r
1143             _listForm.UpdateList();\r
1144             _listForm.Show();\r
1145             if (_listForm.WindowState == FormWindowState.Minimized)\r
1146                 _listForm.WindowState = FormWindowState.Normal;\r
1147             _listForm.Activate();\r
1148         }\r
1149 \r
1150         private void LogToolStripMenuItem_Click(object sender, EventArgs e)\r
1151         {\r
1152             Process.Start("http://localhost:" + _config.Proxy.Listen + "/");\r
1153         }\r
1154 \r
1155         private void labelClearQuest_Click(object sender, EventArgs e)\r
1156         {\r
1157             _sniffer.ClearQuests();\r
1158             UpdateQuestList();\r
1159         }\r
1160 \r
1161         private void labelClearQuest_MouseDown(object sender, MouseEventArgs e)\r
1162         {\r
1163             labelClearQuest.BackColor = _activeButtonColor;\r
1164         }\r
1165 \r
1166         private void labelClearQuest_MouseUp(object sender, MouseEventArgs e)\r
1167         {\r
1168             labelClearQuest.BackColor = DefaultBackColor;\r
1169         }\r
1170 \r
1171         private void labelQuest_DoubleClick(object sender, EventArgs e)\r
1172         {\r
1173             var label = (Label)sender;\r
1174             Clipboard.SetText(label.Text);\r
1175             _tooltipCopy.Active = true;\r
1176             _tooltipCopy.Show("コピーしました。", label);\r
1177             Task.Run(async () =>\r
1178             {\r
1179                 await Task.Delay(1000);\r
1180                 _tooltipCopy.Active = false;\r
1181             });\r
1182         }\r
1183 \r
1184         private void CaptureToolStripMenuItem_Click(object sender, EventArgs e)\r
1185         {\r
1186             try\r
1187             {\r
1188                 var proc = new ProcessStartInfo("BurageSnap.exe") {WorkingDirectory = "Capture"};\r
1189                 Process.Start(proc);\r
1190             }\r
1191             catch (FileNotFoundException)\r
1192             {\r
1193             }\r
1194         }\r
1195     }\r
1196 }