diff --git a/Ui/LauncherForm.Designer.cs b/Ui/LauncherForm.Designer.cs index 8b75316..7805cb7 100644 --- a/Ui/LauncherForm.Designer.cs +++ b/Ui/LauncherForm.Designer.cs @@ -18,15 +18,17 @@ namespace PolyTraderSharp.Ui private void InitializeComponent() { menuStrip = new MenuStrip(); - miDatei = new ToolStripMenuItem(); - miBeenden = new ToolStripMenuItem(); + miFenster = new ToolStripMenuItem(); toolstrip_windows = new ToolStrip(); btn_dashboard = new ToolStripButton(); btn_settings = new ToolStripButton(); btn_terminal = new ToolStripButton(); btn_jobs = new ToolStripButton(); - btn_accounting = new ToolStripButton(); toolStripSeparator1 = new ToolStripSeparator(); + btn_copytrading = new ToolStripButton(); + btn_resolutionfarming = new ToolStripButton(); + btn_supervisor = new ToolStripButton(); + btn_accounting = new ToolStripButton(); toolstrip_quickbar = new ToolStrip(); btn_liveTrading = new ToolStripButton(); btn_demoTrading = new ToolStripButton(); @@ -52,31 +54,24 @@ namespace PolyTraderSharp.Ui // menuStrip // menuStrip.ImageScalingSize = new Size(24, 24); - menuStrip.Items.AddRange(new ToolStripItem[] { miDatei }); + menuStrip.Items.AddRange(new ToolStripItem[] { miFenster }); menuStrip.Location = new Point(0, 0); menuStrip.Name = "menuStrip"; menuStrip.Padding = new Padding(9, 3, 0, 3); menuStrip.Size = new Size(2599, 35); menuStrip.TabIndex = 0; - // - // miDatei - // - miDatei.DropDownItems.AddRange(new ToolStripItem[] { miBeenden }); - miDatei.Name = "miDatei"; - miDatei.Size = new Size(69, 29); - miDatei.Text = "Datei"; - // - // miBeenden - // - miBeenden.Name = "miBeenden"; - miBeenden.Size = new Size(182, 34); - miBeenden.Text = "Beenden"; - // + // + // miFenster + // + miFenster.Name = "miFenster"; + miFenster.Size = new Size(69, 29); + miFenster.Text = "Fenster"; + // // toolstrip_windows // toolstrip_windows.AutoSize = false; toolstrip_windows.ImageScalingSize = new Size(64, 64); - toolstrip_windows.Items.AddRange(new ToolStripItem[] { btn_dashboard, btn_settings, btn_terminal, btn_jobs, btn_accounting, toolStripSeparator1 }); + toolstrip_windows.Items.AddRange(new ToolStripItem[] { btn_dashboard, btn_settings, btn_terminal, btn_jobs, toolStripSeparator1, btn_copytrading, btn_resolutionfarming, btn_supervisor, btn_accounting }); toolstrip_windows.Location = new Point(0, 35); toolstrip_windows.Name = "toolstrip_windows"; toolstrip_windows.Size = new Size(2599, 70); @@ -121,9 +116,39 @@ namespace PolyTraderSharp.Ui btn_jobs.Size = new Size(106, 65); btn_jobs.Text = "Server Jobs"; btn_jobs.TextImageRelation = TextImageRelation.ImageAboveText; - // + // + // btn_copytrading + // + btn_copytrading.Image = Properties.Resources.money_dollar; + btn_copytrading.ImageScaling = ToolStripItemImageScaling.None; + btn_copytrading.ImageTransparentColor = Color.Magenta; + btn_copytrading.Name = "btn_copytrading"; + btn_copytrading.Size = new Size(120, 65); + btn_copytrading.Text = "CopyTrading"; + btn_copytrading.TextImageRelation = TextImageRelation.ImageAboveText; + // + // btn_resolutionfarming + // + btn_resolutionfarming.Image = Properties.Resources.refresh_all; + btn_resolutionfarming.ImageScaling = ToolStripItemImageScaling.None; + btn_resolutionfarming.ImageTransparentColor = Color.Magenta; + btn_resolutionfarming.Name = "btn_resolutionfarming"; + btn_resolutionfarming.Size = new Size(150, 65); + btn_resolutionfarming.Text = "ResolutionFarming"; + btn_resolutionfarming.TextImageRelation = TextImageRelation.ImageAboveText; + // + // btn_supervisor + // + btn_supervisor.Image = Properties.Resources.token_quantifier; + btn_supervisor.ImageScaling = ToolStripItemImageScaling.None; + btn_supervisor.ImageTransparentColor = Color.Magenta; + btn_supervisor.Name = "btn_supervisor"; + btn_supervisor.Size = new Size(110, 65); + btn_supervisor.Text = "Supervisor"; + btn_supervisor.TextImageRelation = TextImageRelation.ImageAboveText; + // // btn_accounting - // + // btn_accounting.Image = Properties.Resources.coins_in_hand; btn_accounting.ImageScaling = ToolStripItemImageScaling.None; btn_accounting.ImageTransparentColor = Color.Magenta; @@ -131,7 +156,7 @@ namespace PolyTraderSharp.Ui btn_accounting.Size = new Size(106, 65); btn_accounting.Text = "Accounting"; btn_accounting.TextImageRelation = TextImageRelation.ImageAboveText; - // + // // toolStripSeparator1 // toolStripSeparator1.Name = "toolStripSeparator1"; @@ -208,25 +233,25 @@ namespace PolyTraderSharp.Ui dgv_accountlist.TabIndex = 6; // // colAccName - // + // colAccName.DataPropertyName = "Name"; colAccName.HeaderText = "Account"; colAccName.MinimumWidth = 8; colAccName.Name = "colAccName"; colAccName.ReadOnly = true; - colAccName.Width = 200; - // + colAccName.Width = 113; + // // colAccModules - // + // colAccModules.DataPropertyName = "Modules"; colAccModules.HeaderText = "Module"; colAccModules.MinimumWidth = 8; colAccModules.Name = "colAccModules"; colAccModules.ReadOnly = true; - colAccModules.Width = 220; - // + colAccModules.Width = 109; + // // colAccPoly - // + // colAccPoly.HeaderText = "Polymarket"; colAccPoly.MinimumWidth = 8; colAccPoly.Name = "colAccPoly"; @@ -234,42 +259,41 @@ namespace PolyTraderSharp.Ui colAccPoly.Text = "Öffnen"; colAccPoly.UseColumnTextForButtonValue = true; colAccPoly.Width = 106; - // + // // colAccBalance - // + // colAccBalance.DataPropertyName = "Balance"; colAccBalance.HeaderText = "Wallet (USDC)"; colAccBalance.MinimumWidth = 8; colAccBalance.Name = "colAccBalance"; colAccBalance.ReadOnly = true; - colAccBalance.Width = 130; - // + colAccBalance.Width = 157; + // // colAccPnl3d - // + // colAccPnl3d.DataPropertyName = "Pnl3d"; colAccPnl3d.HeaderText = "3T PnL"; colAccPnl3d.MinimumWidth = 8; colAccPnl3d.Name = "colAccPnl3d"; colAccPnl3d.ReadOnly = true; - colAccPnl3d.Width = 110; - // + // // colAccWin3d - // + // colAccWin3d.DataPropertyName = "WinRate3d"; colAccWin3d.HeaderText = "3T Winrate %"; colAccWin3d.MinimumWidth = 8; colAccWin3d.Name = "colAccWin3d"; colAccWin3d.ReadOnly = true; - colAccWin3d.Width = 110; - // + colAccWin3d.Width = 153; + // // colAccOverall - // + // colAccOverall.DataPropertyName = "OverallPnl"; colAccOverall.HeaderText = "Overall P/L"; colAccOverall.MinimumWidth = 8; colAccOverall.Name = "colAccOverall"; colAccOverall.ReadOnly = true; - colAccOverall.Width = 130; + colAccOverall.Width = 133; // // LauncherForm // @@ -281,12 +305,14 @@ namespace PolyTraderSharp.Ui Controls.Add(toolstrip_quickbar); Controls.Add(toolstrip_windows); Controls.Add(menuStrip); - FormBorderStyle = FormBorderStyle.FixedSingle; + FormBorderStyle = FormBorderStyle.Sizable; MainMenuStrip = menuStrip; Margin = new Padding(4, 5, 4, 5); + MinimumSize = new Size(1280, 720); Name = "LauncherForm"; StartPosition = FormStartPosition.CenterScreen; Text = "PolyTrader"; + WindowState = FormWindowState.Maximized; menuStrip.ResumeLayout(false); menuStrip.PerformLayout(); toolstrip_windows.ResumeLayout(false); @@ -303,13 +329,15 @@ namespace PolyTraderSharp.Ui #endregion private System.Windows.Forms.MenuStrip menuStrip; - private System.Windows.Forms.ToolStripMenuItem miDatei; - private System.Windows.Forms.ToolStripMenuItem miBeenden; + private System.Windows.Forms.ToolStripMenuItem miFenster; private ToolStrip toolstrip_windows; private ToolStripButton btn_settings; private ToolStripButton btn_terminal; private ToolStripButton btn_jobs; private ToolStripButton btn_dashboard; + private ToolStripButton btn_copytrading; + private ToolStripButton btn_resolutionfarming; + private ToolStripButton btn_supervisor; private ToolStrip toolstrip_quickbar; private ToolStripButton btn_liveTrading; private ToolStripButton btn_demoTrading; diff --git a/Ui/LauncherForm.cs b/Ui/LauncherForm.cs index 5d31ec1..e0c24f2 100644 --- a/Ui/LauncherForm.cs +++ b/Ui/LauncherForm.cs @@ -35,46 +35,36 @@ namespace PolyTraderSharp.Ui InitializeComponent(); - // Fenster-Buttons an stabile View-IDs binden (Views werden per DI registriert). + _uiHost.SetMainWindow(this); + + // Fenster-Buttons: ALLE statisch im Designer, an stabile View-IDs gebunden. Ist eine View + // nicht registriert (Modul fehlt), wird der Button deaktiviert – nichts wird zur Laufzeit angehängt. _viewButtons = new Dictionary { ["core.dashboard"] = btn_dashboard, ["core.settings"] = btn_settings, ["core.terminal"] = btn_terminal, ["core.jobs"] = btn_jobs, + ["copytrading.main"] = btn_copytrading, + ["resolutionfarming.main"] = btn_resolutionfarming, + ["supervisor.main"] = btn_supervisor, + ["accounting.main"] = btn_accounting, }; + var registered = _uiHost.Views.Select(v => v.Id).ToHashSet(); foreach (var (id, btn) in _viewButtons) { var viewId = id; - btn.Click += (_, _) => _uiHost.OpenView(viewId); + if (registered.Contains(viewId)) + btn.Click += (_, _) => _uiHost.OpenView(viewId); + else + btn.Enabled = false; // Modul/View nicht verfügbar } - // Modul-Views dynamisch anhängen (der Launcher kennt keine Modulnamen; er bindet - // nur an registrierte View-IDs). Core-Views sind bereits fest verdrahtet. - var moduleViews = _uiHost.Views - .Where(v => !_viewButtons.ContainsKey(v.Id)) - .OrderBy(v => v.Order) - .ToList(); - if (moduleViews.Count > 0) - toolstrip_windows.Items.Add(new ToolStripSeparator()); - foreach (var view in moduleViews) - { - var btn = new ToolStripButton(view.Title) - { - Name = "btn_" + view.Id, - Overflow = ToolStripItemOverflow.AsNeeded, - TextImageRelation = TextImageRelation.ImageAboveText, - AutoSize = true - }; - var viewId = view.Id; - btn.Click += (_, _) => _uiHost.OpenView(viewId); - toolstrip_windows.Items.Add(btn); - _viewButtons[view.Id] = btn; - } + // Gemeinsames „Fenster"-Menü (Launcher ist das aktuelle Fenster → currentViewId null). + PolyTrader.Core.Modularity.WindowMenu.Wire(miFenster, _uiHost, null); btn_liveTrading.Click += (_, _) => CycleLiveTrading(); btn_demoTrading.Click += (_, _) => CycleDemoTrading(); - miBeenden.Click += (_, _) => Close(); // Offen-Status der Fenster spiegeln (Button „checked", wenn Fenster offen). _uiHost.OpenStateChanged += UpdateWindowButtonStates; diff --git a/Ui/ShellUiHost.cs b/Ui/ShellUiHost.cs index 98faf55..eae185d 100644 --- a/Ui/ShellUiHost.cs +++ b/Ui/ShellUiHost.cs @@ -16,6 +16,7 @@ namespace PolyTraderSharp.Ui { private readonly List _views = new(); private readonly Dictionary _open = new(); + private Form? _mainWindow; /// Wird ausgelöst, wenn sich der Offen-Status irgendeiner View ändert. public event Action? OpenStateChanged; @@ -24,6 +25,18 @@ namespace PolyTraderSharp.Ui public void RegisterView(ModuleView view) => _views.Add(view); + /// Setzt das Hauptfenster (Launcher) – Ziel für . + public void SetMainWindow(Form main) => _mainWindow = main; + + public void ActivateMain() + { + if (_mainWindow == null || _mainWindow.IsDisposed) return; + if (_mainWindow.WindowState == FormWindowState.Minimized) + _mainWindow.WindowState = FormWindowState.Maximized; + _mainWindow.BringToFront(); + _mainWindow.Activate(); + } + public bool IsOpen(string viewId) => _open.TryGetValue(viewId, out var form) && !form.IsDisposed; @@ -48,6 +61,10 @@ namespace PolyTraderSharp.Ui if (string.IsNullOrEmpty(form.Text) || form.Text == form.Name) form.Text = view.Title; + // Alle Fenster maximiert (Vorgabe): Full-HD-Ziel, skaliert auf größere Auflösungen. + form.StartPosition = FormStartPosition.CenterScreen; + form.WindowState = FormWindowState.Maximized; + _open[view.Id] = form; form.FormClosed += (_, _) => { diff --git a/src/PolyTrader.Core/Modularity/ModuleUi.cs b/src/PolyTrader.Core/Modularity/ModuleUi.cs index 1aafffd..146a747 100644 --- a/src/PolyTrader.Core/Modularity/ModuleUi.cs +++ b/src/PolyTrader.Core/Modularity/ModuleUi.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Windows.Forms; namespace PolyTrader.Core.Modularity @@ -23,6 +24,9 @@ namespace PolyTrader.Core.Modularity /// Optionale Sortierreihenfolge. public int Order { get; init; } = 0; + /// Optionales Icon (16x16) für Menü/Buttons. Wird von der Shell/den Menüs genutzt. + public System.Drawing.Image? Icon { get; init; } + /// Erzeugt das anzuzeigende Fenster (frische Instanz je Öffnung). public Func
CreateForm { get; init; } = () => new Form(); } @@ -30,9 +34,26 @@ namespace PolyTrader.Core.Modularity /// /// Wird der Shell beim Start übergeben; Core und Module registrieren hier ihre Ansichten. /// Die Shell (Launcher) öffnet die Fenster auf Anforderung und verwaltet den Offen-Status. + /// Über die Navigations-Mitglieder kann JEDES Fenster (auch Modul-Fenster, die nur den Core + /// kennen) das gemeinsame „Fenster"-Menü bauen (siehe ). /// public interface IModuleUiHost { void RegisterView(ModuleView view); + + /// Alle registrierten Ansichten (Core + Module). + IReadOnlyList Views { get; } + + /// Ist das Fenster dieser View gerade offen? + bool IsOpen(string viewId); + + /// Öffnet die View bzw. holt ein bereits offenes Fenster in den Vordergrund (maximiert). + void OpenView(string viewId); + + /// Holt das Hauptfenster (Launcher) in den Vordergrund. + void ActivateMain(); + + /// Feuert, wenn sich der Offen-Status irgendeiner View ändert. + event Action? OpenStateChanged; } } diff --git a/src/PolyTrader.Core/Modularity/WindowMenu.cs b/src/PolyTrader.Core/Modularity/WindowMenu.cs new file mode 100644 index 0000000..63e5376 --- /dev/null +++ b/src/PolyTrader.Core/Modularity/WindowMenu.cs @@ -0,0 +1,53 @@ +using System; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +namespace PolyTrader.Core.Modularity +{ + /// + /// Baut das gemeinsame „Fenster"-Menü, das auf JEDEM PolyTrader-Fenster erscheint und das Wechseln + /// zwischen allen Fenstern (Launcher + Core + Module) erlaubt. Da es nur den Core-Contract + /// nutzt, funktioniert es auch aus Modul-Fenstern (die die App nicht kennen). + /// + /// Der Menü-Container liegt im Designer jedes Fensters (ein „Fenster"); + /// die dynamische Liste (Offen-Status ändert sich) wird hier beim Aufklappen frisch gefüllt: + /// offene Fenster sind angehakt, das aktuelle Fenster ist fett + angehakt markiert. + /// + public static class WindowMenu + { + /// Verdrahtet ein Designer-„Fenster"-Menüelement mit der Fensterliste (Neuaufbau beim Aufklappen). + public static void Wire(ToolStripMenuItem fensterMenu, IModuleUiHost host, string? currentViewId) + { + fensterMenu.DropDownOpening += (_, _) => Populate(fensterMenu, host, currentViewId); + Populate(fensterMenu, host, currentViewId); + } + + public static void Populate(ToolStripMenuItem fensterMenu, IModuleUiHost host, string? currentViewId) + { + fensterMenu.DropDownItems.Clear(); + + var launcher = new ToolStripMenuItem("Launcher") { Checked = currentViewId == null }; + if (currentViewId == null) launcher.Font = new Font(launcher.Font, FontStyle.Bold); + launcher.Click += (_, _) => host.ActivateMain(); + fensterMenu.DropDownItems.Add(launcher); + fensterMenu.DropDownItems.Add(new ToolStripSeparator()); + + foreach (var view in host.Views.OrderBy(v => v.Order).ThenBy(v => v.Title)) + { + bool isCurrent = view.Id == currentViewId; + var item = new ToolStripMenuItem(view.Title) { Image = view.Icon }; + item.Checked = isCurrent || host.IsOpen(view.Id); + if (isCurrent) item.Font = new Font(item.Font, FontStyle.Bold); + string id = view.Id; + item.Click += (_, _) => host.OpenView(id); + fensterMenu.DropDownItems.Add(item); + } + + fensterMenu.DropDownItems.Add(new ToolStripSeparator()); + var exit = new ToolStripMenuItem("Beenden"); + exit.Click += (_, _) => Application.Exit(); + fensterMenu.DropDownItems.Add(exit); + } + } +}