From 9db326ee5dba8cd24cb84fdde9558906ab0c5aa0 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Tue, 7 Apr 2026 15:16:15 -0400 Subject: [PATCH] refactor: extract ActionManager from PlateView Move action lifecycle (currentAction, previousAction, SetAction, ProcessEscapeKey, RestorePreviousAction, GetDisplayName) into a dedicated ActionManager class. PlateView retains public forwarding methods and exposes Actions property. Co-Authored-By: Claude Sonnet 4.6 --- OpenNest/Controls/ActionManager.cs | 118 +++++++++++++++++++++++++++++ OpenNest/Controls/PlateView.cs | 118 +++-------------------------- 2 files changed, 129 insertions(+), 107 deletions(-) create mode 100644 OpenNest/Controls/ActionManager.cs diff --git a/OpenNest/Controls/ActionManager.cs b/OpenNest/Controls/ActionManager.cs new file mode 100644 index 0000000..b7f8dde --- /dev/null +++ b/OpenNest/Controls/ActionManager.cs @@ -0,0 +1,118 @@ +using System; +using System.ComponentModel; +using Action = OpenNest.Actions.Action; + +namespace OpenNest.Controls +{ + internal class ActionManager + { + private readonly PlateView view; + private Action currentAction; + private Action previousAction; + + public ActionManager(PlateView view) + { + this.view = view; + } + + public Action CurrentAction => currentAction; + + public void SetAction(Type type) + { + var action = Activator.CreateInstance(type, view) as Action; + if (action == null) + return; + + if (currentAction != null) + { + if (type == typeof(Actions.ActionSelect) && !(currentAction is Actions.ActionSelect)) + previousAction = currentAction; + else + previousAction = null; + + currentAction.CancelAction(); + currentAction.DisconnectEvents(); + currentAction = null; + } + + currentAction = action; + view.Status = GetDisplayName(type); + } + + public void SetAction(Type type, params object[] args) + { + if (currentAction != null) + { + previousAction = null; + currentAction.CancelAction(); + currentAction.DisconnectEvents(); + currentAction = null; + } + + Array.Resize(ref args, args.Length + 1); + for (var i = args.Length - 2; i >= 0; i--) + args[i + 1] = args[i]; + args[0] = view; + + var action = Activator.CreateInstance(type, args) as Action; + if (action == null) + return; + + currentAction = action; + view.Status = GetDisplayName(type); + } + + public void ProcessEscapeKey() + { + if (currentAction.IsBusy()) + currentAction.CancelAction(); + else if (currentAction is Actions.ActionSelect && previousAction != null) + RestorePreviousAction(); + else + view.SetAction(typeof(Actions.ActionSelect)); + } + + public void RestorePreviousAction() + { + var action = previousAction; + previousAction = null; + + currentAction.CancelAction(); + currentAction.DisconnectEvents(); + + action.ConnectEvents(); + currentAction = action; + + view.Status = GetDisplayName(action.GetType()); + } + + public void OnPlateChanged() + { + if (currentAction == null || !currentAction.SurvivesPlateChange) + view.SetAction(typeof(Actions.ActionSelect)); + else + currentAction.OnPlateChanged(); + } + + public void Cleanup() + { + if (currentAction != null) + { + currentAction.CancelAction(); + currentAction.DisconnectEvents(); + currentAction = null; + } + } + + private string GetDisplayName(Type type) + { + var attributes = type.GetCustomAttributes(true); + foreach (var attr in attributes) + { + if (attr is DisplayNameAttribute displayNameAttr) + return displayNameAttr.DisplayName; + } + return type.Name; + } + } +} diff --git a/OpenNest/Controls/PlateView.cs b/OpenNest/Controls/PlateView.cs index b21747c..b39368a 100644 --- a/OpenNest/Controls/PlateView.cs +++ b/OpenNest/Controls/PlateView.cs @@ -28,8 +28,7 @@ namespace OpenNest.Controls private string status; private Plate plate; - private Action currentAction; - private Action previousAction; + private ActionManager actionManager; private CutOffSettings cutOffSettings = new CutOffSettings(); private SelectionManager selection; private CutOffHandler cutOffHandler; @@ -70,6 +69,7 @@ namespace OpenNest.Controls internal SelectionManager Selection => selection; internal CutOffHandler CutOffs => cutOffHandler; + internal ActionManager Actions => actionManager; public event EventHandler> PartAdded; public event EventHandler> PartRemoved; @@ -124,7 +124,8 @@ namespace OpenNest.Controls DrawOffset = false; FillParts = true; renderer = new PlateRenderer(this); - SetAction(typeof(ActionSelect)); + actionManager = new ActionManager(this); + actionManager.SetAction(typeof(ActionSelect)); UpdateMatrix(); } @@ -224,10 +225,7 @@ namespace OpenNest.Controls foreach (var part in plate.Parts) parts.Add(LayoutPart.Create(part, this)); - if (currentAction == null || !currentAction.SurvivesPlateChange) - SetAction(typeof(ActionSelect)); - else - currentAction.OnPlateChanged(); + actionManager.OnPlateChanged(); } public string Status @@ -272,7 +270,7 @@ namespace OpenNest.Controls if (e.Button == MouseButtons.Middle) middleMouseDownPoint = e.Location; - if (e.Button == MouseButtons.Left && currentAction is ActionSelect) + if (e.Button == MouseButtons.Left && actionManager.CurrentAction is ActionSelect) { var hitCutOff = cutOffHandler.TryStartDrag(CurrentPoint, 5.0 / ViewScale); if (hitCutOff != null) @@ -374,7 +372,7 @@ namespace OpenNest.Controls return; } - if (e.Button == MouseButtons.None && currentAction is ActionSelect) + if (e.Button == MouseButtons.None && actionManager.CurrentAction is ActionSelect) { var graphPt = PointControlToGraph(e.Location); LayoutPart hitPart = null; @@ -432,15 +430,7 @@ namespace OpenNest.Controls } } - public void ProcessEscapeKey() - { - if (currentAction.IsBusy()) - currentAction.CancelAction(); - else if (currentAction is ActionSelect && previousAction != null) - RestorePreviousAction(); - else - SetAction(typeof(ActionSelect)); - } + public void ProcessEscapeKey() => actionManager.ProcessEscapeKey(); protected override bool ProcessDialogKey(Keys keyData) { @@ -541,14 +531,7 @@ namespace OpenNest.Controls protected override void OnHandleDestroyed(EventArgs e) { base.OnHandleDestroyed(e); - - if (currentAction != null) - { - currentAction.CancelAction(); - currentAction.DisconnectEvents(); - currentAction = null; - } - + actionManager.Cleanup(); } public override void Refresh() @@ -566,72 +549,8 @@ namespace OpenNest.Controls public LayoutPart GetPartAtPoint(Vector pt) => selection.GetPartAtPoint(pt); public IList GetPartsFromWindow(RectangleF rect, SelectionType selectionType) => selection.GetPartsFromWindow(rect, selectionType); - public void SetAction(Type type) - { - var action = Activator.CreateInstance(type, this) as Action; - - if (action == null) - return; - - if (currentAction != null) - { - if (type == typeof(ActionSelect) && !(currentAction is ActionSelect)) - previousAction = currentAction; - else - previousAction = null; - - currentAction.CancelAction(); - currentAction.DisconnectEvents(); - currentAction = null; - } - - currentAction = action; - - Status = GetDisplayName(type); - } - - public void SetAction(Type type, params object[] args) - { - if (currentAction != null) - { - previousAction = null; - currentAction.CancelAction(); - currentAction.DisconnectEvents(); - currentAction = null; - } - - Array.Resize(ref args, args.Length + 1); - - // shift all elements to the right - for (int i = args.Length - 2; i >= 0; i--) - args[i + 1] = args[i]; - - // set the first argument to this. - args[0] = this; - - var action = Activator.CreateInstance(type, args) as Action; - - if (action == null) - return; - - currentAction = action; - - Status = GetDisplayName(type); - } - - private void RestorePreviousAction() - { - var action = previousAction; - previousAction = null; - - currentAction.CancelAction(); - currentAction.DisconnectEvents(); - - action.ConnectEvents(); - currentAction = action; - - Status = GetDisplayName(action.GetType()); - } + public void SetAction(Type type) => actionManager.SetAction(type); + public void SetAction(Type type, params object[] args) => actionManager.SetAction(type, args); public void AlignSelected(AlignType alignType) => selection.AlignSelected(alignType); public void AlignSelected(AlignType alignType, LayoutPart fixedPart) => selection.AlignSelected(alignType, fixedPart); @@ -826,21 +745,6 @@ namespace OpenNest.Controls public void PushSelected(PushDirection direction) => selection.PushSelected(direction); - private string GetDisplayName(Type type) - { - var attributes = type.GetCustomAttributes(true); - - foreach (var attr in attributes) - { - var displayNameAttr = attr as DisplayNameAttribute; - - if (displayNameAttr != null) - return displayNameAttr.DisplayName; - } - - return type.Name; - } - public void RotateSelectedParts(double angle) => selection.RotateSelectedParts(angle); protected override void UpdateMatrix()