Spring – Diff between revs 1 and 2

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 1 Rev 2
1 using System; 1 using System;
2 using System.Collections.Generic; 2 using System.Collections.Generic;
3 using System.Collections.Specialized; 3 using System.Collections.Specialized;
4 using System.ComponentModel; 4 using System.ComponentModel;
5 using System.Drawing; 5 using System.Drawing;
6 using System.IO; 6 using System.IO;
7 using System.Linq; 7 using System.Linq;
8 using System.Net; 8 using System.Net;
9 using System.Reflection; 9 using System.Reflection;
10 using System.Threading.Tasks; 10 using System.Threading.Tasks;
11 using System.Threading.Tasks.Dataflow; 11 using System.Threading.Tasks.Dataflow;
12 using System.Windows.Forms; 12 using System.Windows.Forms;
13 using Gma.System.MouseKeyHook; 13 using Gma.System.MouseKeyHook;
14 using NetSparkleUpdater; 14 using NetSparkleUpdater;
15 using NetSparkleUpdater.Enums; 15 using NetSparkleUpdater.Enums;
16 using NetSparkleUpdater.SignatureVerifiers; 16 using NetSparkleUpdater.SignatureVerifiers;
17 using NetSparkleUpdater.UI.WinForms; 17 using NetSparkleUpdater.UI.WinForms;
18 using QRCoder; 18 using QRCoder;
19 using Spring.About; 19 using Spring.About;
20 using Spring.Charging; 20 using Spring.Charging;
21 using Spring.Discharging; 21 using Spring.Discharging;
22 using Spring.Editing; 22 using Spring.Editing;
23 using Spring.HUD; 23 using Spring.HUD;
24 using Spring.MouseKeyboard; 24 using Spring.MouseKeyboard;
25 using Spring.Properties; 25 using Spring.Properties;
26 using Spring.Serialization; 26 using Spring.Serialization;
27 using Spring.Serialization.Combos; 27 using Spring.Serialization.Combos;
28 using Spring.Serialization.Configuration; 28 using Spring.Serialization.Configuration;
29 using Spring.Settings; 29 using Spring.Settings;
30 using Spring.Utilities; 30 using Spring.Utilities;
31 using Spring.Utilities.Collections.RangeTree; 31 using Spring.Utilities.Collections.RangeTree;
32 using SpringCombos; 32 using SpringCombos;
33   33  
34 namespace Spring.Main 34 namespace Spring.Main
35 { 35 {
36 public partial class MainForm : Form 36 public partial class MainForm : Form
37 { 37 {
38 #region Public Events & Delegates 38 #region Public Events & Delegates
39   39  
40 public event EventHandler<EventArgs> SpringKeyButtonClicked; 40 public event EventHandler<EventArgs> SpringKeyButtonClicked;
41   41  
42 public event EventHandler<EventArgs> SpringSlowButtonClicked; 42 public event EventHandler<EventArgs> SpringSlowButtonClicked;
43   43  
44 public event EventHandler<EventArgs> SpringSpeedButtonClicked; 44 public event EventHandler<EventArgs> SpringSpeedButtonClicked;
45   45  
46 public event EventHandler<SpeedbarValueChangedEventArgs> SpeedbarValueChanged; 46 public event EventHandler<SpeedbarValueChangedEventArgs> SpeedbarValueChanged;
47   47  
48 public event EventHandler<ConfigurationRestoredEventArgs> ConfigurationRestored; 48 public event EventHandler<ConfigurationRestoredEventArgs> ConfigurationRestored;
49   49  
50 #endregion 50 #endregion
51   51  
52 #region Private Delegates, Events, Enums, Properties, Indexers and Fields 52 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
53   53  
54 private Configuration.Configuration Configuration { get; set; } 54 private Configuration.Configuration Configuration { get; set; }
55   55  
56 private OSD OSD { get; set; } 56 private OSD OSD { get; set; }
57   57  
58 private Key Key { get; set; } 58 private Key Key { get; set; }
59   59  
60 private KeyWatch WatchKey { get; set; } 60 private KeyWatch WatchKey { get; set; }
61   61  
62 private Charge Charge { get; set; } 62 private Charge Charge { get; set; }
63   63  
64 private Discharge Discharge { get; set; } 64 private Discharge Discharge { get; set; }
65   65  
66 private IKeyboardMouseEvents KeyboardMouseEvents { get; } 66 private IKeyboardMouseEvents KeyboardMouseEvents { get; }
67   67  
68 private EditorForm EditorForm { get; set; } 68 private EditorForm EditorForm { get; set; }
69   69  
70 private SettingsForm SettingsForm { get; set; } 70 private SettingsForm SettingsForm { get; set; }
71   71  
72 private BufferBlock<ComboQueueItem> ComboQueue { get; } 72 private BufferBlock<ComboQueueItem> ComboQueue { get; }
73   73  
74 private ActionBlock<ComboQueueItem> ComboQueueAction { get; } 74 private ActionBlock<ComboQueueItem> ComboQueueAction { get; }
75   75  
76 private static QRCodeGenerator QrGenerator { get; set; } 76 private static QRCodeGenerator QrGenerator { get; set; }
77   77  
78 private readonly IDisposable _comboQueueLink; 78 private readonly IDisposable _comboQueueLink;
79   79  
80 private RangeTreeAction<TimeSpan, int> _rangeTree; 80 private RangeTreeAction<TimeSpan, int> _rangeTree;
81 private readonly SparkleUpdater _sparkle; 81 private readonly SparkleUpdater _sparkle;
82   82  
83 #endregion 83 #endregion
84   84  
85 #region Constructors, Destructors and Finalizers 85 #region Constructors, Destructors and Finalizers
86   86  
87 public MainForm() 87 public MainForm()
88 { 88 {
89 InitializeComponent(); 89 InitializeComponent();
90 Utilities.WindowState.FormTracker.Track(this); -  
91   90  
92 // Start application update. 91 // Start application update.
93 var manifestModuleName = Assembly.GetEntryAssembly().ManifestModule.FullyQualifiedName; 92 var manifestModuleName = Assembly.GetEntryAssembly().ManifestModule.FullyQualifiedName;
94 var icon = Icon.ExtractAssociatedIcon(manifestModuleName); 93 var icon = Icon.ExtractAssociatedIcon(manifestModuleName);
95   94  
96 _sparkle = new SparkleUpdater("https://spring.grimore.org/update/appcast.xml", 95 _sparkle = new SparkleUpdater("https://spring.grimore.org/update/appcast.xml",
97 new Ed25519Checker(SecurityMode.Strict, "LonrgxVjSF0GnY4hzwlRJnLkaxnDn2ikdmOifILzLJY=")) 96 new Ed25519Checker(SecurityMode.Strict, "LonrgxVjSF0GnY4hzwlRJnLkaxnDn2ikdmOifILzLJY="))
98 { 97 {
99 UIFactory = new UIFactory(icon), 98 UIFactory = new UIFactory(icon),
100 RelaunchAfterUpdate = true, 99 RelaunchAfterUpdate = true,
101 SecurityProtocolType = SecurityProtocolType.Tls12 100 SecurityProtocolType = SecurityProtocolType.Tls12
102 }; 101 };
103 _sparkle.StartLoop(true, true); 102 _sparkle.StartLoop(true, true);
104   103  
105 Directory.CreateDirectory(Constants.UserApplicationDirectory); 104 Directory.CreateDirectory(Constants.UserApplicationDirectory);
106   105  
107 QrGenerator = new QRCodeGenerator(); 106 QrGenerator = new QRCodeGenerator();
108   107  
109 ComboQueue = 108 ComboQueue =
110 new BufferBlock<ComboQueueItem>(new DataflowBlockOptions 109 new BufferBlock<ComboQueueItem>(new DataflowBlockOptions
111 { BoundedCapacity = 4, EnsureOrdered = true }); 110 { BoundedCapacity = 4, EnsureOrdered = true });
112   111  
113 ComboQueueAction = new ActionBlock<ComboQueueItem>(DoComboQueueAction, 112 ComboQueueAction = new ActionBlock<ComboQueueItem>(DoComboQueueAction,
114 new ExecutionDataflowBlockOptions { EnsureOrdered = true, BoundedCapacity = 4 }); 113 new ExecutionDataflowBlockOptions { EnsureOrdered = true, BoundedCapacity = 4 });
115   114  
116 _comboQueueLink = ComboQueue.LinkTo(ComboQueueAction); 115 _comboQueueLink = ComboQueue.LinkTo(ComboQueueAction);
117   116  
118 toolStripStatusLabel1.Text = Strings.Welcome_to_Spring; 117 toolStripStatusLabel1.Text = Strings.Welcome_to_Spring;
119   118  
120 ConfigurationRestored += MainForm_ConfigurationRestored; 119 ConfigurationRestored += MainForm_ConfigurationRestored;
121   120  
122 KeyboardMouseEvents = Hook.GlobalEvents(); 121 KeyboardMouseEvents = Hook.GlobalEvents();
123 } 122 }
124   123  
125 /// <summary> 124 /// <summary>
126 /// Clean up any resources being used. 125 /// Clean up any resources being used.
127 /// </summary> 126 /// </summary>
128 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 127 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
129 protected override void Dispose(bool disposing) 128 protected override void Dispose(bool disposing)
130 { 129 {
131 if (disposing && components != null) 130 if (disposing && components != null)
132 { 131 {
133 ConfigurationRestored -= MainForm_ConfigurationRestored; 132 ConfigurationRestored -= MainForm_ConfigurationRestored;
134   133  
135 _comboQueueLink?.Dispose(); 134 _comboQueueLink?.Dispose();
136 Discharge?.Dispose(); 135 Discharge?.Dispose();
137 Charge?.Dispose(); 136 Charge?.Dispose();
138 WatchKey?.Dispose(); 137 WatchKey?.Dispose();
139 Key?.Dispose(); 138 Key?.Dispose();
140   139  
141 components.Dispose(); 140 components.Dispose();
142 } 141 }
143   142  
144 OSD?.Dispose(); 143 OSD?.Dispose();
145 OSD = null; 144 OSD = null;
146   145  
147 base.Dispose(disposing); 146 base.Dispose(disposing);
148 } 147 }
149   148  
150 #endregion 149 #endregion
151   150  
152 #region Event Handlers 151 #region Event Handlers
153   152  
154 private void ComboQueuePictureBox_Click(object sender, EventArgs e) 153 private void ComboQueuePictureBox_Click(object sender, EventArgs e)
155 { 154 {
156 var pictureBox = (PictureBox) sender; 155 var pictureBox = (PictureBox) sender;
157   156  
158 Charge.Load((Combos) pictureBox.Tag); 157 Charge.Load((Combos) pictureBox.Tag);
159 } 158 }
160   159  
161 private void AboutToolStripMenuItem_Click(object sender, EventArgs e) 160 private void AboutToolStripMenuItem_Click(object sender, EventArgs e)
162 { 161 {
163 var aboutForm = new AboutForm(); 162 var aboutForm = new AboutForm();
164 aboutForm.Show(); 163 aboutForm.Show();
165 } 164 }
166   165  
167 private void TutorialToolStripMenuItem_Click(object sender, EventArgs e) 166 private void TutorialToolStripMenuItem_Click(object sender, EventArgs e)
168 { 167 {
169 new Tutorial.Tutorial(this, KeyboardMouseEvents).Show(); 168 new Tutorial.Tutorial(this, KeyboardMouseEvents).Show();
170 } 169 }
171   170  
172 private async void MainForm_ConfigurationRestored(object sender, ConfigurationRestoredEventArgs e) 171 private async void MainForm_ConfigurationRestored(object sender, ConfigurationRestoredEventArgs e)
173 { 172 {
174 await Initialize(e.Combos); 173 await Initialize(e.Combos);
175 } 174 }
176   175  
177 private void SpeedBar_ValueChanged(object sender, EventArgs e) 176 private void SpeedBar_ValueChanged(object sender, EventArgs e)
178 { 177 {
179 var trackBar = (TrackBar) sender; 178 var trackBar = (TrackBar) sender;
180 SpeedbarValueChanged?.Invoke(sender, new SpeedbarValueChangedEventArgs(trackBar.Value)); 179 SpeedbarValueChanged?.Invoke(sender, new SpeedbarValueChangedEventArgs(trackBar.Value));
181 } 180 }
182   181  
183 private void QuitToolStripMenuItem_Click(object sender, EventArgs e) 182 private void QuitToolStripMenuItem_Click(object sender, EventArgs e)
184 { 183 {
185 Application.Exit(); 184 Application.Exit();
186 } 185 }
187   186  
188 private void BindSpeedButton_Click(object sender, EventArgs e) 187 private void BindSpeedButton_Click(object sender, EventArgs e)
189 { 188 {
190 SpringSpeedButtonClicked?.Invoke(this, e); 189 SpringSpeedButtonClicked?.Invoke(this, e);
191 } 190 }
192   191  
193 private void BindSlowButton_Click(object sender, EventArgs e) 192 private void BindSlowButton_Click(object sender, EventArgs e)
194 { 193 {
195 SpringSlowButtonClicked?.Invoke(this, e); 194 SpringSlowButtonClicked?.Invoke(this, e);
196 } 195 }
197   196  
198 private void BindKeyButton_Click(object sender, EventArgs e) 197 private void BindKeyButton_Click(object sender, EventArgs e)
199 { 198 {
200 SpringKeyButtonClicked?.Invoke(this, e); 199 SpringKeyButtonClicked?.Invoke(this, e);
201 } 200 }
202   201  
203 private async void SaveFileDialog1_FileOk(object sender, CancelEventArgs e) 202 private async void SaveFileDialog1_FileOk(object sender, CancelEventArgs e)
204 { 203 {
205 switch (await Charge.Combos.Serialize(saveFileDialog1.FileName)) 204 switch (await Charge.Combos.Serialize(saveFileDialog1.FileName))
206 { 205 {
207 case SerializationSuccess<Combos> serializationSuccess: 206 case SerializationSuccess<Combos> serializationSuccess:
208 toolStripStatusLabel1.Text = $"{Strings.Combos_wrote_successfully}"; 207 toolStripStatusLabel1.Text = $"{Strings.Combos_wrote_successfully}";
209   208  
210 Charge.StartCharge(serializationSuccess.Result); 209 Charge.StartCharge(serializationSuccess.Result);
211   210  
212 Configuration.Spring.Store = saveFileDialog1.FileName; 211 Configuration.Spring.Store = saveFileDialog1.FileName;
213   212  
214 if (!Configuration.Spring.History.Contains(saveFileDialog1.FileName)) 213 if (!Configuration.Spring.History.Contains(saveFileDialog1.FileName))
215 { 214 {
216 Configuration.Spring.History.Add(saveFileDialog1.FileName); 215 Configuration.Spring.History.Add(saveFileDialog1.FileName);
217 } 216 }
218   217  
219 break; 218 break;
220   219  
221 case SerializationFailure serializationFailed: 220 case SerializationFailure serializationFailed:
222 toolStripStatusLabel1.Text = 221 toolStripStatusLabel1.Text =
223 $"{Strings.Failed_to_write_combos}: {serializationFailed.Exception.Message}"; 222 $"{Strings.Failed_to_write_combos}: {serializationFailed.Exception.Message}";
224   223  
225 break; 224 break;
226 } 225 }
227 } 226 }
228   227  
229 private async void OpenFileDialog1_FileOk(object sender, CancelEventArgs e) 228 private async void OpenFileDialog1_FileOk(object sender, CancelEventArgs e)
230 { 229 {
231 var fileInfo = new FileInfo(openFileDialog1.FileName); 230 var fileInfo = new FileInfo(openFileDialog1.FileName);
232   231  
233 var combos = await LoadCombos(fileInfo); 232 var combos = await LoadCombos(fileInfo);
234   233  
235 if (combos == null) 234 if (combos == null)
236 { 235 {
237 return; 236 return;
238 } 237 }
239   238  
240 Charge.StartCharge(combos); 239 Charge.StartCharge(combos);
241   240  
242 Configuration.Spring.Store = openFileDialog1.FileName; 241 Configuration.Spring.Store = openFileDialog1.FileName;
243   242  
244 if (!Configuration.Spring.History.Contains(openFileDialog1.FileName)) 243 if (!Configuration.Spring.History.Contains(openFileDialog1.FileName))
245 { 244 {
246 Configuration.Spring.History.Add(openFileDialog1.FileName); 245 Configuration.Spring.History.Add(openFileDialog1.FileName);
247 } 246 }
248 } 247 }
249   248  
250 private void ExportToolStripMenuItem_Click(object sender, EventArgs e) 249 private void ExportToolStripMenuItem_Click(object sender, EventArgs e)
251 { 250 {
252 saveFileDialog1.ShowDialog(); 251 saveFileDialog1.ShowDialog();
253 } 252 }
254   253  
255 private void ImportToolStripMenuItem_Click(object sender, EventArgs e) 254 private void ImportToolStripMenuItem_Click(object sender, EventArgs e)
256 { 255 {
257 openFileDialog1.ShowDialog(); 256 openFileDialog1.ShowDialog();
258 } 257 }
259   258  
260 private async void MainForm_Load(object sender, EventArgs e) 259 private async void MainForm_Load(object sender, EventArgs e)
261 { 260 {
-   261 Utilities.WindowState.FormTracker.Track(this);
-   262  
262 var configurationFileInfo = new FileInfo(Constants.ConfigurationFilePath); 263 var configurationFileInfo = new FileInfo(Constants.ConfigurationFilePath);
263   264  
264 // Load configuration. 265 // Load configuration.
265 switch (ConfigurationSerialization.Deserialize(configurationFileInfo)) 266 switch (ConfigurationSerialization.Deserialize(configurationFileInfo))
266 { 267 {
267 case SerializationSuccess<Configuration.Configuration> serializationSuccess: 268 case SerializationSuccess<Configuration.Configuration> serializationSuccess:
268 Configuration = serializationSuccess.Result; 269 Configuration = serializationSuccess.Result;
269 toolStripStatusLabel1.Text = $"{Strings.Read_configuration_successfully}"; 270 toolStripStatusLabel1.Text = $"{Strings.Read_configuration_successfully}";
270   271  
271 break; 272 break;
272   273  
273 case SerializationFailure serializationFailed: 274 case SerializationFailure serializationFailed:
274 toolStripStatusLabel1.Text = 275 toolStripStatusLabel1.Text =
275 $"{Strings.Failed_to_read_configuration}: {serializationFailed.Exception.Message}"; 276 $"{Strings.Failed_to_read_configuration}: {serializationFailed.Exception.Message}";
276   277  
277 // Attempt to load default configuration 278 // Attempt to load default configuration
278 var fileInfo = new FileInfo("Configuration.xml.default"); 279 var fileInfo = new FileInfo("Configuration.xml.default");
279   280  
280 switch (ConfigurationSerialization.Deserialize(fileInfo)) 281 switch (ConfigurationSerialization.Deserialize(fileInfo))
281 { 282 {
282 case SerializationSuccess<Configuration.Configuration> serializationSuccess: 283 case SerializationSuccess<Configuration.Configuration> serializationSuccess:
283 toolStripStatusLabel1.Text = 284 toolStripStatusLabel1.Text =
284 $"{Strings.Read_default_configuration_successfully}"; 285 $"{Strings.Read_default_configuration_successfully}";
285   286  
286 Configuration = serializationSuccess.Result; 287 Configuration = serializationSuccess.Result;
287   288  
288 break; 289 break;
289   290  
290 case SerializationFailure defaultSerializationFailure: 291 case SerializationFailure defaultSerializationFailure:
291 toolStripStatusLabel1.Text = 292 toolStripStatusLabel1.Text =
292 $"{Strings.Failed_to_read_default_configuration}: {defaultSerializationFailure.Exception.Message}"; 293 $"{Strings.Failed_to_read_default_configuration}: {defaultSerializationFailure.Exception.Message}";
293   294  
294 Configuration = new Configuration.Configuration(); 295 Configuration = new Configuration.Configuration();
295   296  
296 break; 297 break;
297 } 298 }
298   299  
299 break; 300 break;
300 } 301 }
301   302  
302 // Load combos. 303 // Load combos.
303 if (string.IsNullOrEmpty(Configuration.Spring.Store)) 304 if (string.IsNullOrEmpty(Configuration.Spring.Store))
304 { 305 {
305 ConfigurationRestored?.Invoke(this, new ConfigurationRestoredEventArgs(new Combos())); 306 ConfigurationRestored?.Invoke(this, new ConfigurationRestoredEventArgs(new Combos()));
306   307  
307 return; 308 return;
308 } 309 }
309   310  
310 var storeFileInfo = new FileInfo(Configuration.Spring.Store); 311 var storeFileInfo = new FileInfo(Configuration.Spring.Store);
311   312  
312 var combos = await LoadCombos(storeFileInfo); 313 var combos = await LoadCombos(storeFileInfo);
313   314  
314 if (combos == null) 315 if (combos == null)
315 { 316 {
316 ConfigurationRestored?.Invoke(this, new ConfigurationRestoredEventArgs(new Combos())); 317 ConfigurationRestored?.Invoke(this, new ConfigurationRestoredEventArgs(new Combos()));
317   318  
318 return; 319 return;
319 } 320 }
320   321  
321 await ComboQueue.SendAsync(new ComboQueueItem(comboQueuePictureBox1, combos)); 322 await ComboQueue.SendAsync(new ComboQueueItem(comboQueuePictureBox1, combos));
322   323  
323 ConfigurationRestored?.Invoke(this, new ConfigurationRestoredEventArgs(combos)); 324 ConfigurationRestored?.Invoke(this, new ConfigurationRestoredEventArgs(combos));
324 } 325 }
325   326  
326 private void WatchKey_SpeedAdjusted(object sender, KeySpeedAdjustedEventArgs e) 327 private void WatchKey_SpeedAdjusted(object sender, KeySpeedAdjustedEventArgs e)
327 { 328 {
328 this.InvokeIfRequired(form => 329 this.InvokeIfRequired(form =>
329 { 330 {
330 switch (e.Multiplier) 331 switch (e.Multiplier)
331 { 332 {
332 case -1: 333 case -1:
333 form.SpeedBar.Value = Math.Max(form.SpeedBar.Value - 1, form.SpeedBar.Minimum); 334 form.SpeedBar.Value = Math.Max(form.SpeedBar.Value - 1, form.SpeedBar.Minimum);
334   335  
335 break; 336 break;
336   337  
337 case 1: 338 case 1:
338 form.SpeedBar.Value = Math.Min(form.SpeedBar.Value + 1, form.SpeedBar.Maximum); 339 form.SpeedBar.Value = Math.Min(form.SpeedBar.Value + 1, form.SpeedBar.Maximum);
339   340  
340 break; 341 break;
341 } 342 }
342 }); 343 });
343 } 344 }
344   345  
345 private void Key_KeyMessage(object sender, KeyMessageEventArgs e) 346 private void Key_KeyMessage(object sender, KeyMessageEventArgs e)
346 { 347 {
347 this.InvokeIfRequired(form => { form.toolStripStatusLabel1.Text = e.Message; }); 348 this.InvokeIfRequired(form => { form.toolStripStatusLabel1.Text = e.Message; });
348 } 349 }
349   350  
350 private void Loading_PropertyChanged(object sender, PropertyChangedEventArgs e) 351 private void Loading_PropertyChanged(object sender, PropertyChangedEventArgs e)
351 { 352 {
352 _rangeTree = new RangeTreeAction<TimeSpan, int> 353 _rangeTree = new RangeTreeAction<TimeSpan, int>
353 { 354 {
354 { 355 {
355 TimeSpan.FromSeconds(0), 356 TimeSpan.FromSeconds(0),
356 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), 357 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
357 ActionNoCharge 358 ActionNoCharge
358 }, 359 },
359 { 360 {
360 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), 361 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
361 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), 362 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
362 ActionNoCharge 363 ActionNoCharge
363 }, 364 },
364 { 365 {
365 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), 366 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
366 TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats + 367 TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats +
367 Configuration.Spring.Charge.ChargeSeconds), 368 Configuration.Spring.Charge.ChargeSeconds),
368 ActionCharge 369 ActionCharge
369 }, 370 },
370 { 371 {
371 TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats + 372 TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats +
372 Configuration.Spring.Charge.ChargeSeconds), 373 Configuration.Spring.Charge.ChargeSeconds),
373 TimeSpan.MaxValue, ActionNoCharge 374 TimeSpan.MaxValue, ActionNoCharge
374 } 375 }
375 }; 376 };
376 } 377 }
377   378  
378 private void WatchKey_KeyUp(object sender, KeyUpEventArgs e) 379 private void WatchKey_KeyUp(object sender, KeyUpEventArgs e)
379 { 380 {
380 OSD.Text = OSD.Symbols.KeyReleased(); 381 OSD.Text = OSD.Symbols.KeyReleased();
381 } 382 }
382   383  
383 private void Charge_ChargeLoaded(object sender, ChargeLoadedEventArgs e) 384 private void Charge_ChargeLoaded(object sender, ChargeLoadedEventArgs e)
384 { 385 {
385 this.InvokeIfRequired(form => { form.toolStripStatusLabel1.Text = Strings.Spring_charged; }); 386 this.InvokeIfRequired(form => { form.toolStripStatusLabel1.Text = Strings.Spring_charged; });
386   387  
387 if (e.Combos == null) 388 if (e.Combos == null)
388 { 389 {
389 return; 390 return;
390 } 391 }
391   392  
392 switch (e.Combos.ComboRepeat) 393 switch (e.Combos.ComboRepeat)
393 { 394 {
394 case 0: 395 case 0:
395 OSD.Text = OSD.Symbols.ChargeStop(Resources.Infinity); 396 OSD.Text = OSD.Symbols.ChargeStop(Resources.Infinity);
396   397  
397 break; 398 break;
398   399  
399 default: 400 default:
400 OSD.Text = OSD.Symbols.ChargeStop(e.Combos.ComboRepeat.ToString()); 401 OSD.Text = OSD.Symbols.ChargeStop(e.Combos.ComboRepeat.ToString());
401   402  
402 break; 403 break;
403 } 404 }
404 } 405 }
405   406  
406 private async void ChargeChanged(object sender, ChargeChangedEventArgs e) 407 private async void ChargeChanged(object sender, ChargeChangedEventArgs e)
407 { 408 {
408 this.InvokeIfRequired(form => { form.toolStripStatusLabel1.Text = Strings.Spring_charged; }); 409 this.InvokeIfRequired(form => { form.toolStripStatusLabel1.Text = Strings.Spring_charged; });
409   410  
410 if (e.Combos == null) 411 if (e.Combos == null)
411 { 412 {
412 return; 413 return;
413 } 414 }
414   415  
415 var combos = Charge.Combos; 416 var combos = Charge.Combos;
416   417  
417 await ComboQueue.SendAsync(new ComboQueueItem(comboQueuePictureBox1, combos)); 418 await ComboQueue.SendAsync(new ComboQueueItem(comboQueuePictureBox1, combos));
418   419  
419 switch (e.Combos.ComboRepeat) 420 switch (e.Combos.ComboRepeat)
420 { 421 {
421 case 0: 422 case 0:
422 OSD.Text = OSD.Symbols.ChargeStop(Resources.Infinity); 423 OSD.Text = OSD.Symbols.ChargeStop(Resources.Infinity);
423   424  
424 break; 425 break;
425   426  
426 default: 427 default:
427 OSD.Text = OSD.Symbols.ChargeStop(e.Combos.ComboRepeat.ToString()); 428 OSD.Text = OSD.Symbols.ChargeStop(e.Combos.ComboRepeat.ToString());
428   429  
429 break; 430 break;
430 } 431 }
431 } 432 }
432   433  
433 private void ChargeStart(object sender, ChargeStartEventArgs e) 434 private void ChargeStart(object sender, ChargeStartEventArgs e)
434 { 435 {
435 if (Charge.Combos == null) 436 if (Charge.Combos == null)
436 { 437 {
437 return; 438 return;
438 } 439 }
439   440  
440 this.InvokeIfRequired(form => { form.toolStripStatusLabel1.Text = Strings.Spring_is_charging; }); 441 this.InvokeIfRequired(form => { form.toolStripStatusLabel1.Text = Strings.Spring_is_charging; });
441   442  
442 OSD.Text = OSD.Symbols.ChargeStart(); 443 OSD.Text = OSD.Symbols.ChargeStart();
443 } 444 }
444   445  
445 private void Discharge_DischargeStart(object sender, DischargeStartEventArgs e) 446 private void Discharge_DischargeStart(object sender, DischargeStartEventArgs e)
446 { 447 {
447 this.InvokeIfRequired(form => 448 this.InvokeIfRequired(form =>
448 { 449 {
449 form.toolStripStatusLabel1.Text = Strings.Spring_is_discharging; 450 form.toolStripStatusLabel1.Text = Strings.Spring_is_discharging;
450 form.toolStripProgressBar1.Value = 0; 451 form.toolStripProgressBar1.Value = 0;
451   452  
452 switch (e.Repeat) 453 switch (e.Repeat)
453 { 454 {
454 case 0: 455 case 0:
455 form.label5.Text = Resources.Infinity; 456 form.label5.Text = Resources.Infinity;
456 form.toolStripProgressBar1.Visible = false; 457 form.toolStripProgressBar1.Visible = false;
457   458  
458 OSD.Text = OSD.Symbols.DischargeProgress(Resources.Infinity); 459 OSD.Text = OSD.Symbols.DischargeProgress(Resources.Infinity);
459   460  
460 break; 461 break;
461   462  
462 default: 463 default:
463 form.label5.Text = e.Repeat.ToString(); 464 form.label5.Text = e.Repeat.ToString();
464 form.toolStripProgressBar1.Visible = true; 465 form.toolStripProgressBar1.Visible = true;
465   466  
466 OSD.Text = OSD.Symbols.DischargeProgress(e.Repeat.ToString()); 467 OSD.Text = OSD.Symbols.DischargeProgress(e.Repeat.ToString());
467   468  
468 break; 469 break;
469 } 470 }
470 }); 471 });
471 } 472 }
472   473  
473 private void Discharge_DischargeStop(object sender, DischargeStopEventArgs e) 474 private void Discharge_DischargeStop(object sender, DischargeStopEventArgs e)
474 { 475 {
475 OSD.Text = string.Empty; 476 OSD.Text = string.Empty;
476   477  
477 this.InvokeIfRequired(form => 478 this.InvokeIfRequired(form =>
478 { 479 {
479 form.toolStripStatusLabel1.Text = Strings.Spring_discharge_cancelled; 480 form.toolStripStatusLabel1.Text = Strings.Spring_discharge_cancelled;
480 form.toolStripProgressBar1.Visible = false; 481 form.toolStripProgressBar1.Visible = false;
481   482  
482 switch (e.Repeat) 483 switch (e.Repeat)
483 { 484 {
484 case 0: 485 case 0:
485 form.label5.Text = Resources.Infinity; 486 form.label5.Text = Resources.Infinity;
486   487  
487 OSD.Text = OSD.Symbols.DischargeStop(Resources.Infinity); 488 OSD.Text = OSD.Symbols.DischargeStop(Resources.Infinity);
488   489  
489 break; 490 break;
490   491  
491 default: 492 default:
492 form.label5.Text = e.Repeat.ToString(); 493 form.label5.Text = e.Repeat.ToString();
493   494  
494 OSD.Text = OSD.Symbols.DischargeStop(e.Repeat.ToString()); 495 OSD.Text = OSD.Symbols.DischargeStop(e.Repeat.ToString());
495   496  
496 break; 497 break;
497 } 498 }
498 }); 499 });
499 } 500 }
500   501  
501 private void Discharge_DischargeProgress(object sender, DischargeProgressEventArgs e) 502 private void Discharge_DischargeProgress(object sender, DischargeProgressEventArgs e)
502 { 503 {
503 this.InvokeIfRequired(form => 504 this.InvokeIfRequired(form =>
504 { 505 {
505 switch (e.Repeat) 506 switch (e.Repeat)
506 { 507 {
507 case 0: 508 case 0:
508 break; 509 break;
509   510  
510 default: 511 default:
511 var progress = (int) (100f - 100f * e.Current / (e.Total * e.Repeat)); 512 var progress = (int) (100f - 100f * e.Current / (e.Total * e.Repeat));
512   513  
513 if (progress < 0 || progress > 100) 514 if (progress < 0 || progress > 100)
514 { 515 {
515 break; 516 break;
516 } 517 }
517   518  
518 form.toolStripProgressBar1.Value = progress; 519 form.toolStripProgressBar1.Value = progress;
519   520  
520 var repeats = (int) (1f * e.Current / e.Total); 521 var repeats = (int) (1f * e.Current / e.Total);
521   522  
522 form.label5.Text = $@"{repeats}"; 523 form.label5.Text = $@"{repeats}";
523   524  
524 OSD.Text = OSD.Symbols.DischargeProgress(repeats.ToString()); 525 OSD.Text = OSD.Symbols.DischargeProgress(repeats.ToString());
525   526  
526 break; 527 break;
527 } 528 }
528 }); 529 });
529 } 530 }
530   531  
531 private void WatchKey_KeyDown(object sender, KeyDownEventArgs e) 532 private void WatchKey_KeyDown(object sender, KeyDownEventArgs e)
532 { 533 {
533 _rangeTree.Query(e.Elapsed); 534 _rangeTree.Query(e.Elapsed);
534 } 535 }
535   536  
536 private async void MainForm_FormClosing(object sender, FormClosingEventArgs e) 537 private async void MainForm_FormClosing(object sender, FormClosingEventArgs e)
537 { 538 {
538 // Save combos. 539 // Save combos.
539 await SaveCombos(Configuration.Spring.Store); 540 await SaveCombos(Configuration.Spring.Store);
540   541  
541 // Save configuration file. 542 // Save configuration file.
542 switch (await Configuration.Serialize(Constants.ConfigurationFilePath)) 543 switch (await Configuration.Serialize(Constants.ConfigurationFilePath))
543 { 544 {
544 case SerializationSuccess _: 545 case SerializationSuccess _:
545 toolStripStatusLabel1.Text = $"{Strings.Wrote_configuration_successfully}"; 546 toolStripStatusLabel1.Text = $"{Strings.Wrote_configuration_successfully}";
546   547  
547 break; 548 break;
548   549  
549 case SerializationFailure serializationFailed: 550 case SerializationFailure serializationFailed:
550 toolStripStatusLabel1.Text = 551 toolStripStatusLabel1.Text =
551 $"{Strings.Failed_to_write_configuration}: {serializationFailed.Exception.Message}"; 552 $"{Strings.Failed_to_write_configuration}: {serializationFailed.Exception.Message}";
552   553  
553 break; 554 break;
554 } 555 }
555 } 556 }
556   557  
557 private void EditorButton_Click(object sender, EventArgs e) 558 private void EditorButton_Click(object sender, EventArgs e)
558 { 559 {
559 if (EditorForm != null) 560 if (EditorForm != null)
560 { 561 {
561 return; 562 return;
562 } 563 }
563   564  
564 EditorForm = new EditorForm(Configuration, Charge.Combos); 565 EditorForm = new EditorForm(Configuration, Charge.Combos);
565 EditorForm.Closing += EditorForm_Closing; 566 EditorForm.Closing += EditorForm_Closing;
566 EditorForm.Edited += EditorForm_Edited; 567 EditorForm.Edited += EditorForm_Edited;
567 EditorForm.Show(); 568 EditorForm.Show();
568 } 569 }
569   570  
570 private void EditorForm_Edited(object sender, EditEventArgs e) 571 private void EditorForm_Edited(object sender, EditEventArgs e)
571 { 572 {
572 switch (e) 573 switch (e)
573 { 574 {
574 case EditSuccessEventArgs editSuccessEventArgs: 575 case EditSuccessEventArgs editSuccessEventArgs:
575 Charge.StartCharge(editSuccessEventArgs.Combos); 576 Charge.StartCharge(editSuccessEventArgs.Combos);
576   577  
577 break; 578 break;
578   579  
579 case EditFailureEventArgs editFailureEventArgs: 580 case EditFailureEventArgs editFailureEventArgs:
580 break; 581 break;
581 } 582 }
582 } 583 }
583   584  
584 private void EditorForm_Closing(object sender, CancelEventArgs e) 585 private void EditorForm_Closing(object sender, CancelEventArgs e)
585 { 586 {
586 if (EditorForm == null) 587 if (EditorForm == null)
587 { 588 {
588 return; 589 return;
589 } 590 }
590   591  
591 EditorForm.Closing -= EditorForm_Closing; 592 EditorForm.Closing -= EditorForm_Closing;
592 EditorForm.Edited -= EditorForm_Edited; 593 EditorForm.Edited -= EditorForm_Edited;
593 EditorForm.Dispose(); 594 EditorForm.Dispose();
594 EditorForm = null; 595 EditorForm = null;
595   596  
596 toolStripStatusLabel1.Text = $"{Strings.Combos_read_successfully}"; 597 toolStripStatusLabel1.Text = $"{Strings.Combos_read_successfully}";
597 } 598 }
598   599  
599 private void SettingsButton_Click(object sender, EventArgs e) 600 private void SettingsButton_Click(object sender, EventArgs e)
600 { 601 {
601 if (SettingsForm != null) 602 if (SettingsForm != null)
602 { 603 {
603 return; 604 return;
604 } 605 }
605   606  
606 SettingsForm = new SettingsForm(Configuration); 607 SettingsForm = new SettingsForm(Configuration);
607 SettingsForm.FormClosing += SettingsForm_FormClosing; 608 SettingsForm.FormClosing += SettingsForm_FormClosing;
608 SettingsForm.Show(); 609 SettingsForm.Show();
609 } 610 }
610   611  
611 private void SettingsForm_FormClosing(object sender, FormClosingEventArgs e) 612 private void SettingsForm_FormClosing(object sender, FormClosingEventArgs e)
612 { 613 {
613 if (SettingsForm == null) 614 if (SettingsForm == null)
614 { 615 {
615 return; 616 return;
616 } 617 }
617   618  
618 SettingsForm.FormClosing -= SettingsForm_FormClosing; 619 SettingsForm.FormClosing -= SettingsForm_FormClosing;
619 SettingsForm.Dispose(); 620 SettingsForm.Dispose();
620 SettingsForm = null; 621 SettingsForm = null;
621 } 622 }
622   623  
623 private void History_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 624 private void History_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
624 { 625 {
625 RecreateHistoryMenu(e.NewItems.OfType<string>()); 626 RecreateHistoryMenu(e.NewItems.OfType<string>());
626 } 627 }
627   628  
628 private void Spring_PropertyChanged(object sender, PropertyChangedEventArgs e) 629 private void Spring_PropertyChanged(object sender, PropertyChangedEventArgs e)
629 { 630 {
630 var springHistory = ((Configuration.Spring) sender).History; 631 var springHistory = ((Configuration.Spring) sender).History;
631   632  
632 RecreateHistoryMenu(springHistory); 633 RecreateHistoryMenu(springHistory);
633 } 634 }
634   635  
635 private async void HistoryToolStripMenu_Click(object sender, EventArgs e) 636 private async void HistoryToolStripMenu_Click(object sender, EventArgs e)
636 { 637 {
637 var selectedFile = ((ToolStripMenuItem) sender).Text; 638 var selectedFile = ((ToolStripMenuItem) sender).Text;
638   639  
639 if (string.IsNullOrEmpty(selectedFile)) 640 if (string.IsNullOrEmpty(selectedFile))
640 { 641 {
641 return; 642 return;
642 } 643 }
643   644  
644 var fileInfo = new FileInfo(selectedFile); 645 var fileInfo = new FileInfo(selectedFile);
645   646  
646 var combos = await LoadCombos(fileInfo); 647 var combos = await LoadCombos(fileInfo);
647   648  
648 if (combos == null) 649 if (combos == null)
649 { 650 {
650 return; 651 return;
651 } 652 }
652   653  
653 Charge.StartCharge(combos); 654 Charge.StartCharge(combos);
654   655  
655 Configuration.Spring.Store = openFileDialog1.FileName; 656 Configuration.Spring.Store = openFileDialog1.FileName;
656   657  
657 if (!Configuration.Spring.History.Contains(openFileDialog1.FileName)) 658 if (!Configuration.Spring.History.Contains(openFileDialog1.FileName))
658 { 659 {
659 Configuration.Spring.History.Add(openFileDialog1.FileName); 660 Configuration.Spring.History.Add(openFileDialog1.FileName);
660 } 661 }
661 } 662 }
662   663  
663 private async void CheckForUpdatesToolStripMenuItem_Click(object sender, EventArgs e) 664 private async void CheckForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
664 { 665 {
665 // Manually check for updates, this will not show a ui 666 // Manually check for updates, this will not show a ui
666 var result = await _sparkle.CheckForUpdatesQuietly(); 667 var result = await _sparkle.CheckForUpdatesQuietly();
667 var updates = result.Updates; 668 var updates = result.Updates;
668 if (result.Status == UpdateStatus.UpdateAvailable) 669 if (result.Status == UpdateStatus.UpdateAvailable)
669 { 670 {
670 // if update(s) are found, then we have to trigger the UI to show it gracefully 671 // if update(s) are found, then we have to trigger the UI to show it gracefully
671 _sparkle.ShowUpdateNeededUI(); 672 _sparkle.ShowUpdateNeededUI();
672 return; 673 return;
673 } 674 }
674   675  
675 MessageBox.Show("No updates available at this time.", "Spring", MessageBoxButtons.OK, 676 MessageBox.Show("No updates available at this time.", "Spring", MessageBoxButtons.OK,
676 MessageBoxIcon.Asterisk, 677 MessageBoxIcon.Asterisk,
677 MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, false); 678 MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, false);
678 } 679 }
679   680  
680 #endregion 681 #endregion
681   682  
682 #region Private Methods 683 #region Private Methods
683   684  
684 private async void DoComboQueueAction(ComboQueueItem springComboQueueItem) 685 private async void DoComboQueueAction(ComboQueueItem springComboQueueItem)
685 { 686 {
686 var serialization = await springComboQueueItem.Combos.Serialize(); 687 var serialization = await springComboQueueItem.Combos.Serialize();
687   688  
688 switch (serialization) 689 switch (serialization)
689 { 690 {
690 case SerializationSuccess<Combos> serializationSuccess: 691 case SerializationSuccess<Combos> serializationSuccess:
691 var comboText = serializationSuccess.Text; 692 var comboText = serializationSuccess.Text;
692   693  
693 var qrCodeData = QrGenerator.CreateQrCode(Helpers.Sha1Hash(comboText), 694 var qrCodeData = QrGenerator.CreateQrCode(Helpers.Sha1Hash(comboText),
694 QRCodeGenerator.ECCLevel.L, 695 QRCodeGenerator.ECCLevel.L,
695 false, 696 false,
696 false, 697 false,
697 QRCodeGenerator.EciMode.Default, 698 QRCodeGenerator.EciMode.Default,
698 1); 699 1);
699   700  
700 var qrCode = new QRCode(qrCodeData); 701 var qrCode = new QRCode(qrCodeData);
701 var qrCodeImage = qrCode.GetGraphic(20); 702 var qrCodeImage = qrCode.GetGraphic(20);
702 var image = Helpers.Crop(qrCodeImage); 703 var image = Helpers.Crop(qrCodeImage);
703   704  
704 // Set the QR code hash and the combos. 705 // Set the QR code hash and the combos.
705 comboQueuePictureBox4.BackgroundImage = comboQueuePictureBox3.BackgroundImage; 706 comboQueuePictureBox4.BackgroundImage = comboQueuePictureBox3.BackgroundImage;
706 comboQueuePictureBox4.Tag = comboQueuePictureBox3.Tag; 707 comboQueuePictureBox4.Tag = comboQueuePictureBox3.Tag;
707 comboQueuePictureBox3.BackgroundImage = comboQueuePictureBox2.BackgroundImage; 708 comboQueuePictureBox3.BackgroundImage = comboQueuePictureBox2.BackgroundImage;
708 comboQueuePictureBox3.Tag = comboQueuePictureBox2.Tag; 709 comboQueuePictureBox3.Tag = comboQueuePictureBox2.Tag;
709 comboQueuePictureBox2.BackgroundImage = comboQueuePictureBox1.BackgroundImage; 710 comboQueuePictureBox2.BackgroundImage = comboQueuePictureBox1.BackgroundImage;
710 comboQueuePictureBox2.Tag = comboQueuePictureBox1.Tag; 711 comboQueuePictureBox2.Tag = comboQueuePictureBox1.Tag;
711 comboQueuePictureBox1.BackgroundImage = image; 712 comboQueuePictureBox1.BackgroundImage = image;
712 comboQueuePictureBox1.Tag = serializationSuccess.Result; 713 comboQueuePictureBox1.Tag = serializationSuccess.Result;
713   714  
714 break; 715 break;
715   716  
716 case SerializationFailure serializationFailure: 717 case SerializationFailure serializationFailure:
717 break; 718 break;
718 } 719 }
719 } 720 }
720   721  
721 private async Task<Combos> LoadCombos(FileInfo file) 722 private async Task<Combos> LoadCombos(FileInfo file)
722 { 723 {
723 switch (await ComboSerialization.Deserialize(file, 0)) 724 switch (await ComboSerialization.Deserialize(file, 0))
724 { 725 {
725 case SerializationSuccess<Combos> serializationSuccess: 726 case SerializationSuccess<Combos> serializationSuccess:
726 toolStripStatusLabel1.Text = $"{Strings.Combos_read_successfully}"; 727 toolStripStatusLabel1.Text = $"{Strings.Combos_read_successfully}";
727   728  
728 return serializationSuccess.Result; 729 return serializationSuccess.Result;
729   730  
730 case SerializationFailure deserializationFailure: 731 case SerializationFailure deserializationFailure:
731 toolStripStatusLabel1.Text = 732 toolStripStatusLabel1.Text =
732 $"{Strings.Failed_to_read_combos}: {deserializationFailure.Exception.Message}"; 733 $"{Strings.Failed_to_read_combos}: {deserializationFailure.Exception.Message}";
733   734  
734 break; 735 break;
735 } 736 }
736   737  
737 return null; 738 return null;
738 } 739 }
739   740  
740 /// <summary> 741 /// <summary>
741 /// Serialize combos to file. 742 /// Serialize combos to file.
742 /// </summary> 743 /// </summary>
743 /// <param name="file">the file to which the combos will be serialized</param> 744 /// <param name="file">the file to which the combos will be serialized</param>
744 /// <returns>an awaitable task</returns> 745 /// <returns>an awaitable task</returns>
745 private async Task SaveCombos(string file) 746 private async Task SaveCombos(string file)
746 { 747 {
747 switch (await Charge.Combos.Serialize(file)) 748 switch (await Charge.Combos.Serialize(file))
748 { 749 {
749 case SerializationSuccess<Combos> serializationSuccess: 750 case SerializationSuccess<Combos> serializationSuccess:
750 toolStripStatusLabel1.Text = $"{Strings.Combos_wrote_successfully}"; 751 toolStripStatusLabel1.Text = $"{Strings.Combos_wrote_successfully}";
751   752  
752 break; 753 break;
753   754  
754 case SerializationFailure deserializationFailure: 755 case SerializationFailure deserializationFailure:
755 toolStripStatusLabel1.Text = 756 toolStripStatusLabel1.Text =
756 $"{Strings.Failed_to_write_combos}: {deserializationFailure.Exception.Message}"; 757 $"{Strings.Failed_to_write_combos}: {deserializationFailure.Exception.Message}";
757   758  
758 break; 759 break;
759 } 760 }
760 } 761 }
761   762  
762 private void ActionCharge(TimeSpan x) 763 private void ActionCharge(TimeSpan x)
763 { 764 {
764 this.InvokeIfRequired(form => 765 this.InvokeIfRequired(form =>
765 { 766 {
766 switch (x.Seconds - Configuration.Spring.Charge.ChargeSeconds) 767 switch (x.Seconds - Configuration.Spring.Charge.ChargeSeconds)
767 { 768 {
768 case 0: 769 case 0:
769 form.label5.Text = Resources.Infinity; 770 form.label5.Text = Resources.Infinity;
770 OSD.Text = OSD.Symbols.KeyDown(Resources.Infinity); 771 OSD.Text = OSD.Symbols.KeyDown(Resources.Infinity);
771   772  
772 break; 773 break;
773   774  
774 default: 775 default:
775 var comboText = (x.Seconds - Configuration.Spring.Charge.ChargeSeconds).ToString(); 776 var comboText = (x.Seconds - Configuration.Spring.Charge.ChargeSeconds).ToString();
776   777  
777 form.label5.Text = comboText; 778 form.label5.Text = comboText;
778   779  
779 OSD.Text = OSD.Symbols.KeyDown(comboText); 780 OSD.Text = OSD.Symbols.KeyDown(comboText);
780   781  
781 break; 782 break;
782 } 783 }
783 }); 784 });
784 } 785 }
785   786  
786 private void ActionNoCharge(TimeSpan x) 787 private void ActionNoCharge(TimeSpan x)
787 { 788 {
788 this.InvokeIfRequired(form => 789 this.InvokeIfRequired(form =>
789 { 790 {
790 switch (x.Seconds < Configuration.Spring.Charge.ChargeSeconds) 791 switch (x.Seconds < Configuration.Spring.Charge.ChargeSeconds)
791 { 792 {
792 case true: 793 case true:
793 form.label5.Text = string.Empty; 794 form.label5.Text = string.Empty;
794 OSD.Text = OSD.Symbols.KeyPressed(); 795 OSD.Text = OSD.Symbols.KeyPressed();
795   796  
796 break; 797 break;
797   798  
798 default: 799 default:
799 form.label5.Text = Resources.Infinity; 800 form.label5.Text = Resources.Infinity;
800 OSD.Text = OSD.Symbols.KeyDown(Resources.Infinity); 801 OSD.Text = OSD.Symbols.KeyDown(Resources.Infinity);
801   802  
802 break; 803 break;
803 } 804 }
804 }); 805 });
805 } 806 }
806   807  
807 private async Task Initialize(Combos springCombos) 808 private async Task Initialize(Combos springCombos)
808 { 809 {
809 Key = new Key(this, Configuration, KeyboardMouseEvents); 810 Key = new Key(this, Configuration, KeyboardMouseEvents);
810 Key.KeyMessage += Key_KeyMessage; 811 Key.KeyMessage += Key_KeyMessage;
811 WatchKey = new KeyWatch(KeyboardMouseEvents, Key); 812 WatchKey = new KeyWatch(KeyboardMouseEvents, Key);
812 WatchKey.SpeedAdjusted += WatchKey_SpeedAdjusted; 813 WatchKey.SpeedAdjusted += WatchKey_SpeedAdjusted;
813 WatchKey.KeyDown += WatchKey_KeyDown; 814 WatchKey.KeyDown += WatchKey_KeyDown;
814 WatchKey.KeyUp += WatchKey_KeyUp; 815 WatchKey.KeyUp += WatchKey_KeyUp;
815   816  
816 Charge = new Charge(springCombos, Configuration, KeyboardMouseEvents, Key, WatchKey); 817 Charge = new Charge(springCombos, Configuration, KeyboardMouseEvents, Key, WatchKey);
817 Charge.ChargeStart += ChargeStart; 818 Charge.ChargeStart += ChargeStart;
818 Charge.ChargeChanged += ChargeChanged; 819 Charge.ChargeChanged += ChargeChanged;
819 Charge.ChargeLoaded += Charge_ChargeLoaded; 820 Charge.ChargeLoaded += Charge_ChargeLoaded;
820   821  
821 Discharge = new Discharge(this, Configuration, Key, WatchKey, Charge, SpeedBar.Value); 822 Discharge = new Discharge(this, Configuration, Key, WatchKey, Charge, SpeedBar.Value);
822 Discharge.SpringDischargeStart += Discharge_DischargeStart; 823 Discharge.SpringDischargeStart += Discharge_DischargeStart;
823 Discharge.SpringDischargeStop += Discharge_DischargeStop; 824 Discharge.SpringDischargeStop += Discharge_DischargeStop;
824 Discharge.SpringDischargeProgress += Discharge_DischargeProgress; 825 Discharge.SpringDischargeProgress += Discharge_DischargeProgress;
825   826  
826 Configuration.Spring.Charge.PropertyChanged += Loading_PropertyChanged; 827 Configuration.Spring.Charge.PropertyChanged += Loading_PropertyChanged;
827 Configuration.Spring.PropertyChanged += Spring_PropertyChanged; 828 Configuration.Spring.PropertyChanged += Spring_PropertyChanged;
828 Configuration.Spring.History.CollectionChanged += History_CollectionChanged; 829 Configuration.Spring.History.CollectionChanged += History_CollectionChanged;
829   830  
830 OSD = new OSD(Configuration, KeyboardMouseEvents); 831 OSD = new OSD(Configuration, KeyboardMouseEvents);
831   832  
832 if (OSD.Configuration.HUD.Enable) 833 if (OSD.Configuration.HUD.Enable)
833 { 834 {
834 OSD.Text = OSD.Symbols.HUDShown(); 835 OSD.Text = OSD.Symbols.HUDShown();
835 } 836 }
836   837  
837 _rangeTree = new RangeTreeAction<TimeSpan, int> 838 _rangeTree = new RangeTreeAction<TimeSpan, int>
838 { 839 {
839 { 840 {
840 TimeSpan.FromSeconds(0), 841 TimeSpan.FromSeconds(0),
841 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), 842 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
842 ActionNoCharge 843 ActionNoCharge
843 }, 844 },
844 { 845 {
845 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), 846 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
846 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), 847 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
847 ActionNoCharge 848 ActionNoCharge
848 }, 849 },
849 { 850 {
850 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds), 851 TimeSpan.FromSeconds(Configuration.Spring.Charge.ChargeSeconds),
851 TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats + 852 TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats +
852 Configuration.Spring.Charge.ChargeSeconds), 853 Configuration.Spring.Charge.ChargeSeconds),
853 ActionCharge 854 ActionCharge
854 }, 855 },
855 { 856 {
856 TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats + 857 TimeSpan.FromSeconds(Configuration.Spring.Charge.MaximumRepeats +
857 Configuration.Spring.Charge.ChargeSeconds), 858 Configuration.Spring.Charge.ChargeSeconds),
858 TimeSpan.MaxValue, ActionNoCharge 859 TimeSpan.MaxValue, ActionNoCharge
859 } 860 }
860 }; 861 };
861   862  
862 RecreateHistoryMenu(Configuration.Spring.History); 863 RecreateHistoryMenu(Configuration.Spring.History);
863   864  
864 await Key.Load(); 865 await Key.Load();
865 } 866 }
866   867  
867 private void RecreateHistoryMenu(IEnumerable<string> springHistory) 868 private void RecreateHistoryMenu(IEnumerable<string> springHistory)
868 { 869 {
869 var history = springHistory.ToList(); 870 var history = springHistory.ToList();
870   871  
871 foreach (var toolStripMenuItem in 872 foreach (var toolStripMenuItem in
872 historyToolStripMenuItem.DropDownItems.OfType<ToolStripMenuItem>()) 873 historyToolStripMenuItem.DropDownItems.OfType<ToolStripMenuItem>())
873 { 874 {
874 toolStripMenuItem.Click -= HistoryToolStripMenu_Click; 875 toolStripMenuItem.Click -= HistoryToolStripMenu_Click;
875   876  
876 history.Add(toolStripMenuItem.Text); 877 history.Add(toolStripMenuItem.Text);
877 } 878 }
878   879  
879 historyToolStripMenuItem.DropDownItems.Clear(); 880 historyToolStripMenuItem.DropDownItems.Clear();
880   881  
881 foreach (var item in history.Distinct()) 882 foreach (var item in history.Distinct())
882 { 883 {
883 if (string.IsNullOrEmpty(item)) 884 if (string.IsNullOrEmpty(item))
884 { 885 {
885 continue; 886 continue;
886 } 887 }
887   888  
888 historyToolStripMenuItem.DropDownItems.Add(item, null, HistoryToolStripMenu_Click); 889 historyToolStripMenuItem.DropDownItems.Add(item, null, HistoryToolStripMenu_Click);
889 } 890 }
890 } 891 }
891   892  
892 #endregion 893 #endregion
893 } 894 }
894 } 895 }
895   896