using FizzyLauncher.Models; using FizzyLauncher.Text.Json; using FizzyLauncher.Windows.Forms; using RyzStudio.Windows.Forms; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; using System.Runtime.InteropServices; using System.Text.Json; using System.Threading.Tasks; using System.Windows.Forms; namespace FizzyLauncher { public partial class MainForm : Form { [DllImport("user32.dll")] protected static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk); [DllImport("user32.dll")] protected static extern bool UnregisterHotKey(IntPtr hWnd, int id); //protected const int MOD_ALT = 0x1; //protected const int MOD_CONTROL = 0x2; //protected const int MOD_SHIFT = 0x4; //protected const int MOD_WIN = 0x8; protected const int WM_HOTKEY = 0x312; protected const int WM_QUERYENDSESSION = 0x0011; protected OptionsForm optionsForm = null; protected string sessionFilename = null; protected bool isBusy = false; protected bool requestExit = false; public MainForm() : base() { InitializeComponent(); notifyIcon1.Text = Application.ProductName; this.StartPosition = FormStartPosition.WindowsDefaultBounds; this.Visible = false; } protected override void OnLoad(EventArgs e) { base.OnLoad(e); ThreadControl.SetVisible(this, false); ThreadControl.SetSize(this, this.MinimumSize); } protected async override void OnShown(EventArgs e) { base.OnShown(e); ThreadControl.SetVisible(this, false); string jsonfigFilename = Path.ChangeExtension(Application.ExecutablePath, "jsonfig"); if (File.Exists(jsonfigFilename)) { await loadFile(jsonfigFilename); } else { this.CurrentSession = new LauncherSession(); ThreadControl.SetVisible(this, true); } } protected override void OnClosing(CancelEventArgs e) { base.OnClosing(e); if (this.CurrentSession == null) this.CurrentSession = new LauncherSession(); if (this.CurrentSession.HideOnClose && !requestExit) { this.Visible = !this.Visible; e.Cancel = true; return; } requestExit = false; if (string.IsNullOrWhiteSpace(sessionFilename)) { // do nothing } else { if (this.CurrentSession.AutoSave == LauncherSession.AutoSaveOption.Prompt) { DialogResult dr = MessageBox.Show("Save existing session?", "Exit", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); if (dr == DialogResult.Yes) { bool rv = saveFile(sessionFilename, false); if (!rv) { e.Cancel = true; } } else if (dr == DialogResult.No) { // do nothing } else if (dr == DialogResult.Cancel) { e.Cancel = true; } } else if (this.CurrentSession.AutoSave == LauncherSession.AutoSaveOption.Yes) { saveFile(sessionFilename, false); } } if (this.CurrentSession.HotKey != null) { if (this.CurrentSession.HotKey.KeyCode != Keys.None) { #if !DEBUG UnregisterHotKey((IntPtr)Handle, 1); #endif } } } protected override void WndProc(ref Message m) { switch (m.Msg) { case WM_HOTKEY: if (m.WParam.ToInt32() == 1) { this.Visible = !this.Visible; } break; case WM_QUERYENDSESSION: requestExit = true; //this.Close(); Application.Exit(); break; default: break; } base.WndProc(ref m); } public LauncherSession CurrentSession { get; set; } = null; protected async Task collapseWindow(int width, int increment = 6) { await Task.Run(() => { while (this.Width > width) { ThreadControl.SetWidth(this, (this.Width - increment)); Application.DoEvents(); } ThreadControl.SetWidth(this, width); }); } protected async Task expandWindow(int width, int increment = 8) { await Task.Run(() => { while (this.Width < width) { ThreadControl.SetWidth(this, (this.Width + increment)); Application.DoEvents(); } ThreadControl.SetWidth(this, width); }); } protected void invalidateHotKey() { #if !DEBUG if (this.InvokeRequired) { this.Invoke(new MethodInvoker(() => { UnregisterHotKey((IntPtr)Handle, 1); })); } else { UnregisterHotKey((IntPtr)Handle, 1); } #endif if (this.CurrentSession.HotKey != null) { if (this.CurrentSession.HotKey.KeyCode != Keys.None) { #if !DEBUG if (this.InvokeRequired) { this.Invoke(new MethodInvoker(() => { RegisterHotKey((IntPtr)Handle, 1, this.CurrentSession.HotKey.ModifierCode, this.CurrentSession.HotKey.Key); })); } else { RegisterHotKey((IntPtr)Handle, 1, this.CurrentSession.HotKey.ModifierCode, this.CurrentSession.HotKey.Key); } #endif } } } protected void newSession() { flowLayoutPanel1.Controls.Clear(); flowLayoutPanel1.Controls.Add(new TilePanelLayout(new TileGroupModel() { Title = "New Group", IsExpanded = true, GridSize = new Size(6, 1) })); InvalidateWidth(6); } protected async Task loadFile(string filename) { await Task.Run(() => { if (isBusy) { return; } if (string.IsNullOrWhiteSpace(filename)) { return; } if (!File.Exists(filename)) { return; } string sourceCode = null; try { sessionFilename = filename; sourceCode = File.ReadAllText(sessionFilename); } catch (Exception exc) { MessageBox.Show(exc.Message, "Load session"); return; } if (string.IsNullOrWhiteSpace(sourceCode)) { return; } // load options var options = new JsonSerializerOptions(); options.Converters.Add(new JsonPointConverter()); options.Converters.Add(new JsonSizeConverter()); try { this.CurrentSession = JsonSerializer.Deserialize(sourceCode, options); } catch (Exception exc) { MessageBox.Show("Unable to read session", "Load session"); return; } if (this.CurrentSession == null) { this.CurrentSession = new LauncherSession(); } // load tiles int maxTileWidth = 0; ThreadControl.Clear(flowLayoutPanel1); if (this.CurrentSession.Groups != null) { foreach (TileGroupModel item in this.CurrentSession.Groups) { maxTileWidth = Math.Max(maxTileWidth, item.GridSize.Width); TilePanelLayout panel = new TilePanelLayout(item); ThreadControl.Add(flowLayoutPanel1, panel); } } // resize InvalidateSize(maxTileWidth); // reposition if (!this.CurrentSession.StartPosition.IsEmpty) ThreadControl.SetLocation(this, this.CurrentSession.StartPosition); // ThreadControl.SetTopMost(this, this.CurrentSession.AlwaysOnTop); ThreadControl.SetVisible(this, true); ThreadControl.SetChecked(enableAnimationsToolStripMenuItem, this.CurrentSession.EnableAnimation); ThreadControl.SetChecked(showBigIconsToolStripMenuItem, this.CurrentSession.EnableBigIconInFolder); ThreadControl.SetFocus(this); // hotkey invalidateHotKey(); }); } protected bool saveFile(string filename, bool showNotices = true) { if (isBusy) { return false; } if (string.IsNullOrWhiteSpace(filename)) { return false; } if (flowLayoutPanel1.Controls.Count <= 0) { return true; } isBusy = true; // update session if (this.CurrentSession == null) { this.CurrentSession = new LauncherSession(); } this.CurrentSession.DefaultHeight = this.Height; this.CurrentSession.AlwaysOnTop = this.TopMost; this.CurrentSession.StartPosition = this.Location; // save this.CurrentSession.Groups = new List(); for (int i = 0; i < flowLayoutPanel1.Controls.Count; i++) { if (flowLayoutPanel1.Controls[i].GetType() != typeof(TilePanelLayout)) { continue; } TilePanelLayout container = flowLayoutPanel1.Controls[i] as TilePanelLayout; this.CurrentSession.Groups.Add(container.Model); } var options = new JsonSerializerOptions(); options.Converters.Add(new JsonPointConverter()); options.Converters.Add(new JsonSizeConverter()); try { File.WriteAllText(filename, JsonSerializer.Serialize(this.CurrentSession, options)); if (showNotices) { MessageBox.Show("Session saved!", "Save session", MessageBoxButtons.OK, MessageBoxIcon.Information); } } catch (Exception exc) { MessageBox.Show(exc.Message, "Save session"); return false; } isBusy = false; return true; } protected bool saveAsFile() { if (isBusy) { return false; } if (saveFileDialog1.ShowDialog() == DialogResult.OK) { bool rv = saveFile(saveFileDialog1.FileName); if (rv) { sessionFilename = saveFileDialog1.FileName; } return rv; } return false; } protected void InvalidateSize(int columnWidth) { int newWidth = TilePanelLayout.CalcWidth(columnWidth); newWidth += SystemInformation.VerticalScrollBarWidth; newWidth += flowLayoutPanel1.Padding.Horizontal + flowLayoutPanel1.Margin.Horizontal; newWidth += panel1.Left + panel1.Padding.Horizontal + panel1.Margin.Horizontal; newWidth += this.Padding.Horizontal; ThreadControl.ClientSize(this, newWidth, this.CurrentSession.DefaultHeight); } protected void InvalidateWidth(int columnWidth) { int newWidth = TilePanelLayout.CalcWidth(columnWidth); newWidth += SystemInformation.VerticalScrollBarWidth; newWidth += panel1.Left + panel1.Padding.Horizontal + this.Padding.Horizontal + flowLayoutPanel1.Padding.Horizontal + flowLayoutPanel1.Left; ThreadControl.SetClientWidth(this, newWidth); } #region main menu private void newToolStripMenuItem_Click(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(sessionFilename)) { newSession(); } else { DialogResult dr = MessageBox.Show("Save existing session?", "New session", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); if (dr == DialogResult.Yes) { bool rv = saveFile(sessionFilename, false); if (rv) { newSession(); sessionFilename = null; } } else if (dr == DialogResult.No) { newSession(); sessionFilename = null; } else if (dr == DialogResult.Cancel) { return; } } } private async void openToolStripMenuItem_Click(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(sessionFilename)) { if (openFileDialog1.ShowDialog() == DialogResult.OK) { await loadFile(openFileDialog1.FileName); } } else { DialogResult dr = MessageBox.Show("Save existing session?", "Open session", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); if (dr == DialogResult.Yes) { bool rv = saveFile(sessionFilename, false); if (rv) { if (openFileDialog1.ShowDialog() == DialogResult.OK) { await loadFile(openFileDialog1.FileName); } } } else if (dr == DialogResult.No) { if (openFileDialog1.ShowDialog() == DialogResult.OK) { await loadFile(openFileDialog1.FileName); } } else if (dr == DialogResult.Cancel) { return; } } } private void closeToolStripMenuItem_Click(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(sessionFilename)) { flowLayoutPanel1.Controls.Clear(); } else { DialogResult dr = MessageBox.Show("Save existing session?", "Close session", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); if (dr == DialogResult.Yes) { bool rv = saveFile(sessionFilename, false); if (rv) { flowLayoutPanel1.Controls.Clear(); sessionFilename = null; } } else if (dr == DialogResult.No) { flowLayoutPanel1.Controls.Clear(); sessionFilename = null; } else if (dr == DialogResult.Cancel) { return; } } } private void saveToolStripMenuItem_Click(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(sessionFilename)) { saveAsFile(); } else { saveFile(sessionFilename, true); } } private void saveAsToolStripMenuItem_Click(object sender, EventArgs e) { saveAsFile(); } private void exitToolStripMenuItem2_Click(object sender, EventArgs e) { requestExit = true; this.Close(); } private void showBigIconsToolStripMenuItem_Click(object sender, EventArgs e) { if (this.CurrentSession == null) { return; } this.CurrentSession.EnableBigIconInFolder = !this.CurrentSession.EnableBigIconInFolder; showBigIconsToolStripMenuItem.Checked = this.CurrentSession.EnableBigIconInFolder; } private void enableAnimationsToolStripMenuItem_Click(object sender, EventArgs e) { if (this.CurrentSession == null) { return; } this.CurrentSession.EnableAnimation = !this.CurrentSession.EnableAnimation; enableAnimationsToolStripMenuItem.Checked = this.CurrentSession.EnableAnimation; } private void alwaysOnTopToolStripMenuItem_Click(object sender, EventArgs e) { this.TopMost = !this.TopMost; } private void optionsToolStripMenuItem_Click(object sender, EventArgs e) { if (optionsForm == null) optionsForm = new OptionsForm(this); optionsForm.ShowDialog(); invalidateHotKey(); } private void viewHelpToolStripMenuItem1_Click(object sender, EventArgs e) { try { System.Diagnostics.Process.Start("https://www.hiimray.co.uk/software-fizzy-launcher"); } catch { // do nothing } } private void aboutToolStripMenuItem1_Click(object sender, EventArgs e) { MessageBox.Show(Application.ProductName + " v" + Application.ProductVersion, "About", MessageBoxButtons.OK, MessageBoxIcon.Information); } private void menuStrip1_MenuActivate(object sender, EventArgs e) { alwaysOnTopToolStripMenuItem.Checked = this.TopMost; saveAsToolStripMenuItem.Enabled = !string.IsNullOrWhiteSpace(sessionFilename); } #endregion #region notification icon private void notifyIcon1_MouseClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { this.Visible = !this.Visible; } } private void exitToolStripMenuItem1_Click(object sender, EventArgs e) { requestExit = true; this.Close(); } #endregion } }