using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; using System.Linq; using System.Reflection; using System.Text.Json; using System.Threading.Tasks; using System.Windows.Forms; using RokettoLaunch.Models; using RokettoLaunch.Windows.Forms; using RyzStudio; using RyzStudio.Windows.Forms; using RyzStudio.Windows.ThemedForms; using RyzStudio.Windows.ThemedForms.ButtonTextBox; using RyzStudio.Windows.TileForms; namespace RokettoLaunch { public partial class MainForm : Form { private readonly FileSessionManager _fileSessionManager; private bool _isBusy = false; private bool _requestExit = false; public MainForm() { InitializeComponent(); this.AutoScaleMode = AutoScaleMode.None; this.Text = Application.ProductName; newToolStripMenuItem.Image = RyzStudio.Windows.ThemedForms.DefaultVisualStyle.GetImage("a", Color.Black, 2); openToolStripMenuItem.Image = RyzStudio.Windows.ThemedForms.DefaultVisualStyle.GetImage("b", Color.Black, 2); saveToolStripMenuItem.Image = RyzStudio.Windows.ThemedForms.DefaultVisualStyle.GetImage("c", Color.Black, 2); optionsToolStripMenuItem.Image = RyzStudio.Windows.ThemedForms.DefaultVisualStyle.GetImage("i", Color.Black, 2); viewHelpToolStripMenuItem1.Image = RyzStudio.Windows.ThemedForms.DefaultVisualStyle.GetImage("j", Color.Black, 2); _fileSessionManager = new FileSessionManager(); _fileSessionManager.OpenFileDialog = openFileDialog1; _fileSessionManager.SaveFileDialog = saveFileDialog1; _fileSessionManager.OnNewing += fileSessionManager_OnNewSession; _fileSessionManager.OnLoading += fileSessionManager_OnLoadSession; _fileSessionManager.OnSaving += fileSessionManager_OnSaveSession; _fileSessionManager.OnClearing += fileSessionManager_OnClearSession; _fileSessionManager.OnFilenameChanged += fileSessionManager_OnFilenameChanged; notifyIcon1.Text = Application.ProductName; } protected async override void OnShown(EventArgs e) { base.OnShown(e); var args = WinApplication.GetCommandLine(); string jsonfigFilename = args.Where(x => (x.Key.Equals("o") || x.Key.Equals("open"))).Select(x => x.Value).FirstOrDefault(); if (string.IsNullOrWhiteSpace(jsonfigFilename)) { jsonfigFilename = Path.ChangeExtension(Application.ExecutablePath, "jsonfig"); } if (!string.IsNullOrWhiteSpace(jsonfigFilename) && File.Exists(jsonfigFilename)) { await _fileSessionManager.OpenSession(jsonfigFilename); } else { this.CurrentSession = new AppOptions(); InvalidateOptions(); } } protected async override void OnClosing(CancelEventArgs e) { base.OnClosing(e); if (this.CurrentSession == null) { this.CurrentSession = new AppOptions(); } if (this.CurrentSession.HideOnClose && !_requestExit) { this.Visible = !this.Visible; e.Cancel = true; return; } _requestExit = false; await _fileSessionManager.CloseSession(); if ((this.CurrentSession?.ShowToggleHotkey ?? new ThKeyCodeTextBox.Results()).Key != Keys.None) { #if !DEBUG RyzStudio.Runtime.InteropServices.User32.UnregisterHotKey((IntPtr)Handle, 1); #endif } } protected override void WndProc(ref Message m) { switch (m.Msg) { case RyzStudio.Runtime.InteropServices.User32.WM_HOTKEY: if (m.WParam.ToInt32() == 1) { this.Visible = !this.Visible; } break; case RyzStudio.Runtime.InteropServices.User32.WM_QUERYENDSESSION: _requestExit = true; Application.Exit(); break; default: break; } base.WndProc(ref m); } public AppOptions CurrentSession { get; set; } = null; private void InvalidateOptions() { /// todo: big icons #if !DEBUG UIControl.Invoke(this, (x) => { RyzStudio.Runtime.InteropServices.User32.UnregisterHotKey((IntPtr)Handle, 1); }); if ((this.CurrentSession?.ShowToggleHotkey ?? new ThKeyCodeTextBox.Results()).Key != Keys.None) { UIControl.Invoke(this, (x) => { RyzStudio.Runtime.InteropServices.User32.RegisterHotKey((IntPtr)Handle, 1, this.CurrentSession.ShowToggleHotkey.ModifierCode, this.CurrentSession.ShowToggleHotkey.KeyCode); }); } #endif UIControl.SetTopMost(this, this.CurrentSession.AlwaysOnTop); } private void menuStrip1_MenuActivate(object sender, EventArgs e) { closeToolStripMenuItem.Enabled = (_fileSessionManager.SessionState != FileSessionManager.SessionStateEnum.Close); saveToolStripMenuItem.Enabled = (_fileSessionManager.SessionState == FileSessionManager.SessionStateEnum.Open) && _fileSessionManager.HasChanged; saveAsToolStripMenuItem.Enabled = (_fileSessionManager.SessionState != FileSessionManager.SessionStateEnum.Close); addGroupToolStripMenuItem.Enabled = (_fileSessionManager.SessionState != FileSessionManager.SessionStateEnum.Close); showBigIconsToolStripMenuItem.Checked = this.CurrentSession?.ShowBigIcons ?? true; alwaysOnTopToolStripMenuItem.Checked = this.CurrentSession?.AlwaysOnTop ?? false; } private void tileContainer_MouseClick(object sender, MouseEventArgs e) { if (e.Button != MouseButtons.Middle) { return; } var control = (sender as Control); if (control == null) { return; } var container = UIControl.GetParentsUntil(sender as Control); if (container == null) { return; } var newCoord = container.GetNextCoord(); var tileModel = new TileModel() { Title = "New Tile", IsGroup = false }; var newTile = new RokettoLaunch.Windows.Forms.TilePanel(); newTile.ContextMenuStrip = tileMenu1; newTile.LoadInfo(tileModel); container.Add(newTile, newCoord.X, newCoord.Y); _fileSessionManager.HasChanged = true; } #region Main Menu /// /// New /// /// /// private async void newToolStripMenuItem_Click(object sender, EventArgs e) { if (_isBusy) { return; } await _fileSessionManager.NewSession(); } /// /// Open /// /// /// private async void openToolStripMenuItem_Click(object sender, EventArgs e) { if (_isBusy) { return; } await _fileSessionManager.OpenSession(); } /// /// Close /// /// /// private async void closeToolStripMenuItem_Click(object sender, EventArgs e) { if (_isBusy) { return; } await _fileSessionManager.CloseSession(); } /// /// Save /// /// /// private async void saveToolStripMenuItem_Click(object sender, EventArgs e) { if (_isBusy) { return; } await _fileSessionManager.SaveSession(); } /// /// Save As /// /// /// private async void saveAsToolStripMenuItem_Click(object sender, EventArgs e) { if (_isBusy) { return; } await _fileSessionManager.SaveAsSession(); } /// /// Exit /// /// /// private void exitToolStripMenuItem2_Click(object sender, EventArgs e) { if (_isBusy) { return; } _requestExit = true; this.Close(); } /// /// Add group /// /// /// private async void addGroupToolStripMenuItem_Click(object sender, EventArgs e) { await AddNewTileGroup(); } /// /// Show big icons /// /// /// private void showBigIconsToolStripMenuItem_Click(object sender, EventArgs e) { if (this.CurrentSession == null) { return; } this.CurrentSession.ShowBigIcons = !this.CurrentSession.ShowBigIcons; } /// /// Always on top /// /// /// private void alwaysOnTopToolStripMenuItem_Click(object sender, EventArgs e) { if (this.CurrentSession == null) { return; } this.CurrentSession.AlwaysOnTop = !this.CurrentSession.AlwaysOnTop; this.TopMost = this.CurrentSession.AlwaysOnTop; } /// /// Options /// /// /// private void optionsToolStripMenuItem_Click(object sender, EventArgs e) { var form = new OptionsForm(this.CurrentSession); if (form.ShowDialog() == DialogResult.OK) { this.CurrentSession = form.Result; InvalidateOptions(); } } /// /// View help /// /// /// private void viewHelpToolStripMenuItem1_Click(object sender, EventArgs e) { RyzStudio.Diagnostics.Process.Execute(AppResource.AppHelpURL); } /// /// About /// /// /// private void aboutToolStripMenuItem1_Click(object sender, EventArgs e) { var form = new RyzStudio.Windows.ThemedForms.AboutForm(); form.ProductURL = AppResource.AppProductURL; form.AuthorURL = AppResource.AppAuthorURL; form.CompanyURL = AppResource.AppCompanyURL; form.ProductCopyrightStartYear = 2020; form.ProductLogo = AppResource.icon_64; form.ShowDialog(); } #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 #region File Session Manager private async Task fileSessionManager_OnNewSession(FileSessionManager sender) { return await Task.Run(async () => { var form = new NewForm(); if (form.ShowDialog() == DialogResult.OK) { var result = form.Result; UIControl.Clear(flowLayoutPanel1); this.CurrentSession.TilesPerRow = result.ColumnCount; for (var i = 0; i < result.GroupCount; i++) { await AddNewTileGroup(); } } AutoResize(); return true; }); } private async Task fileSessionManager_OnLoadSession(FileSessionManager sender, string filename, int formatType) { return await Task.Run(async () => { var result = GenericResult.Create(); switch (Path.GetExtension(filename?.ToLower()?.Trim() ?? string.Empty)) { case ".json": case ".jsonfig": this.CurrentSession = RyzStudio.Text.Json.JsonSerialiser.DeserialiseFile(filename); break; case ".jsnx": this.CurrentSession = await RyzStudio.IO.Compression.ZFile.ReadFile(filename, "Document.json"); break; default: this.CurrentSession = null; break; } if (this.CurrentSession == null) { ThMessageBox.Show(this, "Unable to read session", "Load session"); return false; } if (this.CurrentSession == null) { this.CurrentSession = new AppOptions(); } // Reposition + resize if (!this.CurrentSession.StartPosition.IsEmpty) { UIControl.SetLocation(this, this.CurrentSession.StartPosition); } if (this.CurrentSession.Height > 0) { UIControl.SetClientHeight(this, this.CurrentSession.Height); } InvalidateOptions(); // Load tiles await LoadTileGroups(this.CurrentSession.Groups); AutoResize(); UIControl.SetFocus(this); return true; }); } private async Task fileSessionManager_OnSaveSession(FileSessionManager sender, string filename, int formatType, bool showNotices) { if (string.IsNullOrWhiteSpace(filename)) { return false; } if (!flowLayoutPanel1.Controls.OfType().Any()) { return true; } return await Task.Run(async () => { if (_isBusy) { return false; } _isBusy = true; // update session if (this.CurrentSession == null) { this.CurrentSession = new AppOptions(); } this.CurrentSession.StartPosition = this.Location; this.CurrentSession.Height = this.Height; this.CurrentSession.Groups = new List(); foreach (var container in flowLayoutPanel1.Controls.OfType()) { var newTag = (TileGroupModel)container.Tag; if (newTag == null) { continue; } newTag.Items = new List(); foreach (var tile in container.Controls.OfType()) { tile.ModelInfo.Position = container.GetCoord(tile); newTag.Items.Add(tile.ModelInfo); } this.CurrentSession.Groups.Add(newTag); } var result = GenericResult.Create(); switch (Path.GetExtension(filename?.ToLower()?.Trim() ?? string.Empty)) { case ".json": case ".jsonfig": result = RyzStudio.Text.Json.JsonSerialiser.SerialiseFile(filename, this.CurrentSession); break; case ".jsnx": try { System.IO.File.Delete(filename); } catch(Exception) { // do nothing } result = await RyzStudio.IO.Compression.ZFile.WriteFile(filename, "Document.json", this.CurrentSession); break; default: result = GenericResult.Fault("Format not supported"); break; } if (result.IsSuccess) { if (showNotices) { ThMessageBox.Show(this, "Session saved!", "Save session", MessageBoxButtons.OK, MessageBoxIcon.Information); } } else { if (showNotices) { ThMessageBox.Show(this, "Session saved!", "Save session"); } } _isBusy = false; return result.IsSuccess; }); } private async Task fileSessionManager_OnClearSession(FileSessionManager sender) { await Task.Run(() => { UIControl.Clear(flowLayoutPanel1); }); return true; } private async Task fileSessionManager_OnFilenameChanged(FileSessionManager sender, string filename) { await Task.Run(() => { switch (sender.SessionState) { case FileSessionManager.SessionStateEnum.New: UIControl.SetText(this, "New Session - " + Application.ProductName); break; case FileSessionManager.SessionStateEnum.Open: UIControl.SetText(this, Path.GetFileNameWithoutExtension(filename) + " - " + Application.ProductName); break; case FileSessionManager.SessionStateEnum.Close: UIControl.SetText(this, Application.ProductName); break; default: break; } }); } #endregion #region Tile Container /// /// Add Tile /// /// /// private void addGroupToolStripMenuItem1_Click(object sender, EventArgs e) { var container = UIControl.GetOwner((ToolStripMenuItem)sender); if (container == null) { return; } var form = new EditTileForm(); if (form.ShowDialog() == DialogResult.OK) { var result = form.Result; var newCoord = container.GetNextCoord(); var newTile = new RokettoLaunch.Windows.Forms.TilePanel(); newTile.ContextMenuStrip = tileMenu1; newTile.LoadInfo(result); container.Add(newTile, newCoord.X, newCoord.Y); _fileSessionManager.HasChanged = true; }; } /// /// Add Tile Group /// /// /// private void toolStripMenuItem4_Click(object sender, EventArgs e) { var container = UIControl.GetOwner((ToolStripMenuItem)sender); if (container == null) { return; } var form = new EditTileFolderForm(); if (form.ShowDialog() == DialogResult.OK) { var result = form.Result; var newCoord = container.GetNextCoord(); var newTile = new RokettoLaunch.Windows.Forms.TilePanel(); newTile.ContextMenuStrip = tileMenu1; newTile.LoadInfo(result); container.Add(newTile, newCoord.X, newCoord.Y); _fileSessionManager.HasChanged = true; }; } /// /// Edit /// /// /// private void editToolStripMenuItem_Click(object sender, EventArgs e) { var container = UIControl.GetOwner((ToolStripMenuItem)sender); if (container == null) { return; } var model = UIControl.GetTag(container); var form = new EditGroupForm(model); if (form.ShowDialog() == DialogResult.OK) { var result = form.Result; container.Title = result.Title; container.Tag = result; container.Invalidate(); _fileSessionManager.HasChanged = true; }; } /// /// Duplicate /// /// /// private async void toolStripMenuItem5_Click(object sender, EventArgs e) { var container = UIControl.GetOwner((ToolStripMenuItem)sender); if (container == null) { return; } var model = UIControl.GetTag(container); model.IsExpanded = true; try { var newModel = JsonSerializer.Deserialize(JsonSerializer.Serialize(model)); await AddTileGroups(newModel); } catch (Exception) { return; } _fileSessionManager.HasChanged = true; } /// /// Row - Add Row /// /// /// private void addRowToolStripMenuItem_Click(object sender, EventArgs e) { var container = UIControl.GetOwner((ToolStripDropDownItem)sender); if (container == null) { return; } container.AddRow(); _fileSessionManager.HasChanged = true; } /// /// Row - Remove Row /// /// /// private void removeRowToolStripMenuItem_Click(object sender, EventArgs e) { var container = UIControl.GetOwner((ToolStripDropDownItem)sender); if (container == null) { return; } container.RemoveRow(); _fileSessionManager.HasChanged = true; } /// /// Move Top /// /// /// private void topToolStripMenuItem_Click(object sender, EventArgs e) { var container = UIControl.GetOwner((ToolStripDropDownItem)sender); if (container == null) { return; } UIControl.MoveTop(flowLayoutPanel1, container); _fileSessionManager.HasChanged = true; } /// /// Move Up /// /// /// private void upToolStripMenuItem_Click(object sender, EventArgs e) { var container = UIControl.GetOwner((ToolStripDropDownItem)sender); if (container == null) { return; } UIControl.MoveUp(flowLayoutPanel1, container); _fileSessionManager.HasChanged = true; } /// /// Move Down /// /// /// private void downToolStripMenuItem_Click(object sender, EventArgs e) { var container = UIControl.GetOwner((ToolStripDropDownItem)sender); if (container == null) { return; } UIControl.MoveDown(flowLayoutPanel1, container); _fileSessionManager.HasChanged = true; } /// /// Move Bottom /// /// /// private void bottomToolStripMenuItem_Click(object sender, EventArgs e) { var container = UIControl.GetOwner((ToolStripDropDownItem)sender); if (container == null) { return; } UIControl.MoveBottom(flowLayoutPanel1, container); _fileSessionManager.HasChanged = true; } /// /// Remove /// /// /// private void removeToolStripMenuItem_Click(object sender, EventArgs e) { var container = UIControl.GetOwner((ToolStripMenuItem)sender); if (container == null) { return; } flowLayoutPanel1.Controls.Remove(container); _fileSessionManager.HasChanged = true; } #endregion #region Tile /// /// Edit /// /// /// private void editToolStripMenuItem1_Click(object sender, EventArgs e) { var tile = UIControl.GetOwner((ToolStripMenuItem)sender); if (tile == null) { return; } if (tile.ModelInfo.IsGroup) { var form = new EditTileFolderForm(tile.ModelInfo); if (form.ShowDialog() == DialogResult.OK) { tile.LoadInfo(form.Result); _fileSessionManager.HasChanged = true; }; } else { var form = new EditTileForm(tile.ModelInfo); if (form.ShowDialog() == DialogResult.OK) { tile.LoadInfo(form.Result); _fileSessionManager.HasChanged = true; }; } } /// /// Duplicate /// /// /// private void toolStripMenuItem6_Click(object sender, EventArgs e) { var tile = UIControl.GetOwner((ToolStripMenuItem)sender); if (tile == null) { return; } var container = UIControl.GetParentsUntil(tile); if (container == null) { return; } var newModel = new TileModel(); try { newModel = JsonSerializer.Deserialize(JsonSerializer.Serialize(tile.ModelInfo)); } catch (Exception) { return; } var newCoord = container.GetNextCoord(); var newTile = new RokettoLaunch.Windows.Forms.TilePanel(); newTile.ContextMenuStrip = tileMenu1; newTile.LoadInfo(newModel); container.Add(newTile, newCoord.X, newCoord.Y); _fileSessionManager.HasChanged = true; } /// /// Remove /// /// /// private void removeToolStripMenuItem1_Click(object sender, EventArgs e) { var tile = UIControl.GetOwner((ToolStripMenuItem)sender); if (tile == null) { return; } var container = UIControl.GetParentsUntil(tile); if (container == null) { return; } container.Controls?.Remove(tile); _fileSessionManager.HasChanged = true; } #endregion private async Task AddNewTileGroup() { var group = new TileGroupModel(); group.Title = "New Group"; group.IsExpanded = true; group.GridSize = new System.Drawing.Size(this.CurrentSession.TilesPerRow, 1); await AddTileGroups(group); _fileSessionManager.HasChanged = true; } private async Task AddTileGroups(TileGroupModel model) { await Task.Run(() => { var panel = new RyzStudio.Windows.TileForms.TileContainer(); panel.Title = model.Title; panel.IsOpen = model.IsExpanded; panel.TitleContextMenuStrip = tileContainerMenu1; panel.PaddingBottom = 0; panel.AutoSizeHeight = true; panel.Tag = model; panel.AutoSize(model.GridSize.Width, model.GridSize.Height); panel.Height += 4; panel.MouseClick += tileContainer_MouseClick; UIControl.Add(flowLayoutPanel1, panel); // Load tiles foreach (var item2 in model.Items ?? new List()) { var newTile = new RokettoLaunch.Windows.Forms.TilePanel(); newTile.ContextMenuStrip = tileMenu1; newTile.LoadInfo(item2); panel.Add(newTile, item2.Position.X, item2.Position.Y); } }); } private void AutoResize() { if (flowLayoutPanel1.Controls.Count <= 0) { return; } var width = 0; foreach (var item in flowLayoutPanel1.Controls.OfType()) { width = Math.Max(width, item.Width); } UIControl.SetClientWidth(this, width + panel1.Padding.Horizontal + this.Padding.Horizontal + SystemInformation.VerticalScrollBarWidth); } private async Task LoadTileGroups(List groupList) { UIControl.Clear(flowLayoutPanel1); foreach (var item in groupList ?? new List()) { await AddTileGroups(item); } } } }