linear-app-launcher/MainForm.cs

739 lines
21 KiB
C#

using FizzyLauncher.Models;
using RyzStudio.Drawing;
using RyzStudio.Text.Json;
using RyzStudio.Windows.Forms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
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();
tileContainer1.OnColumnSizeChanged += tileContainer1_OnSizeChanged;
notifyIcon1.Text = Application.ProductName;
this.AutoScaleMode = AutoScaleMode.None;
this.StartPosition = FormStartPosition.WindowsDefaultBounds;
this.Visible = false;
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.AutoScaleMode = AutoScaleMode.None;
UIControl.SetVisible(this, false);
UIControl.SetSize(this, this.MinimumSize);
}
protected async override void OnShown(EventArgs e)
{
base.OnShown(e);
UIControl.SetVisible(this, false);
string[] commandLineArgs = Environment.GetCommandLineArgs();
string jsonfigFilename = null;
if (string.IsNullOrWhiteSpace(jsonfigFilename)) jsonfigFilename = parseOpenFile_FromCMD(commandLineArgs);
if (string.IsNullOrWhiteSpace(jsonfigFilename)) jsonfigFilename = Path.ChangeExtension(Application.ExecutablePath, "jsonfig");
if (!string.IsNullOrWhiteSpace(jsonfigFilename) && File.Exists(jsonfigFilename))
{
await loadFile(jsonfigFilename);
}
else
{
this.CurrentSession = new LauncherSession();
UIControl.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;
public void Clear(int columnCount)
{
tileContainer1.Clear();
tileContainer1.Add(columnCount);
sessionFilename = null;
}
protected async Task collapseWindow(int width, int increment = 6)
{
await Task.Run(() =>
{
while (this.Width > width)
{
UIControl.SetWidth(this, (this.Width - increment));
Application.DoEvents();
}
UIControl.SetWidth(this, width);
});
}
protected async Task expandWindow(int width, int increment = 8)
{
await Task.Run(() =>
{
while (this.Width < width)
{
UIControl.SetWidth(this, (this.Width + increment));
Application.DoEvents();
}
UIControl.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 string parseOpenFile_FromCMD(string[] args)
{
if (args.Length <= 1)
{
return null;
}
int i = 1;
while (true)
{
if (i > (args.Length - 1))
{
break;
}
switch (args[i].Trim().ToLower())
{
case "-o":
case "-open":
if ((i + 1) > (args.Length - 1)) break;
string openFilename = args[(i + 1)];
if (string.IsNullOrWhiteSpace(openFilename)) break;
if (!File.Exists(openFilename)) break;
return openFilename;
//i++;
//break;
}
i++;
}
return null;
}
protected void newSession()
{
NewForm form = new NewForm(this);
form.ShowDialog();
}
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());
options.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
try
{
this.CurrentSession = JsonSerializer.Deserialize<LauncherSession>(sourceCode, options);
}
catch (Exception)
{
MessageBox.Show("Unable to read session", "Load session");
return;
}
if (this.CurrentSession == null)
{
this.CurrentSession = new LauncherSession();
}
// load tiles
tileContainer1.Load(this.CurrentSession.Groups);
// reposition
if (!this.CurrentSession.StartPosition.IsEmpty) UIControl.SetLocation(this, this.CurrentSession.StartPosition);
//
UIControl.SetTopMost(this, this.CurrentSession.AlwaysOnTop);
UIControl.SetVisible(this, true);
UIControl.SetChecked(enableAnimationsToolStripMenuItem, this.CurrentSession.EnableAnimation);
UIControl.SetChecked(showBigIconsToolStripMenuItem, this.CurrentSession.EnableBigIconInFolder);
UIControl.SetClientHeight(this, this.CurrentSession.DefaultHeight);
UIControl.SetFocus(this);
// hotkey
invalidateHotKey();
});
}
protected bool saveFile(string filename, bool showNotices = true)
{
if (isBusy)
{
return false;
}
if (string.IsNullOrWhiteSpace(filename))
{
return false;
}
if (tileContainer1.GroupCount <= 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;
this.CurrentSession.Groups = tileContainer1.GroupModels?.ToList() ?? new List<TileGroupModel>();
var options = new JsonSerializerOptions();
options.Converters.Add(new JsonPointConverter());
options.Converters.Add(new JsonSizeConverter());
options.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
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;
}
#region main menu
/// <summary>
/// New
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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();
}
}
else if (dr == DialogResult.No)
{
newSession();
}
else if (dr == DialogResult.Cancel)
{
return;
}
}
}
/// <summary>
/// Open
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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;
}
}
}
/// <summary>
/// Close
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void closeToolStripMenuItem_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(sessionFilename))
{
tileContainer1.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)
{
tileContainer1.Clear();
sessionFilename = null;
}
}
else if (dr == DialogResult.No)
{
tileContainer1.Clear();
sessionFilename = null;
}
else if (dr == DialogResult.Cancel)
{
return;
}
}
}
/// <summary>
/// Save
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(sessionFilename))
{
saveAsFile();
}
else
{
saveFile(sessionFilename, true);
}
}
/// <summary>
/// Save As
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
{
saveAsFile();
}
/// <summary>
/// Exit
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void exitToolStripMenuItem2_Click(object sender, EventArgs e)
{
requestExit = true;
this.Close();
}
/// <summary>
/// Add group
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void addGroupToolStripMenuItem_Click(object sender, EventArgs e)
{
tileContainer1.Add();
}
/// <summary>
/// Show big icons
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void showBigIconsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.CurrentSession == null)
{
return;
}
this.CurrentSession.EnableBigIconInFolder = !this.CurrentSession.EnableBigIconInFolder;
showBigIconsToolStripMenuItem.Checked = this.CurrentSession.EnableBigIconInFolder;
}
/// <summary>
/// Enable animations
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void enableAnimationsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.CurrentSession == null)
{
return;
}
this.CurrentSession.EnableAnimation = !this.CurrentSession.EnableAnimation;
enableAnimationsToolStripMenuItem.Checked = this.CurrentSession.EnableAnimation;
}
/// <summary>
/// Always on top
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void alwaysOnTopToolStripMenuItem_Click(object sender, EventArgs e)
{
this.TopMost = !this.TopMost;
}
/// <summary>
/// Options
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (optionsForm == null) optionsForm = new OptionsForm(this);
optionsForm.ShowDialog();
invalidateHotKey();
}
/// <summary>
/// View help
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void viewHelpToolStripMenuItem1_Click(object sender, EventArgs e)
{
try
{
System.Diagnostics.Process.Start(new ProcessStartInfo()
{
FileName = AppResource.AppHelpURL,
UseShellExecute = true
});
}
catch
{
// do nothing
}
}
/// <summary>
/// About
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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
private void tileContainer1_OnSizeChanged(object sender, EventArgs e)
{
int newWidth = this.Padding.Horizontal + SystemInformation.VerticalScrollBarWidth + tileContainer1.CalcWidth;
UIControl.SetClientWidth(this, newWidth);
}
}
}