Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mac: Add ability to auto attach/detach a control #2523

Merged
merged 1 commit into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions src/Eto.Mac/Forms/MacView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ public interface IMacViewHandler : IMacControlHandler
MouseEventArgs TriggerMouseDown(NSObject obj, IntPtr sel, NSEvent theEvent);
MouseEventArgs TriggerMouseUp(NSObject obj, IntPtr sel, NSEvent theEvent);
void UpdateTrackingAreas();
void OnViewDidMoveToWindow();
bool AutoAttachNative { get; set; }
}

static partial class MacView
Expand All @@ -128,6 +130,7 @@ static partial class MacView
public static readonly object AcceptsFirstMouse_Key = new object();
public static readonly object TextInputCancelled_Key = new object();
public static readonly object TextInputImplemented_Key = new object();
public static readonly object AutoAttachNative_Key = new object();
public static readonly IntPtr selMouseDown = Selector.GetHandle("mouseDown:");
public static readonly IntPtr selMouseUp = Selector.GetHandle("mouseUp:");
public static readonly IntPtr selMouseDragged = Selector.GetHandle("mouseDragged:");
Expand Down Expand Up @@ -556,6 +559,20 @@ static bool ValidateSystemUserInterfaceItem(IntPtr sender, IntPtr sel, IntPtr it
/// </summary>
public static bool InMouseTrackingLoop;

public static IntPtr selViewDidMoveToWindow = Selector.GetHandle("viewDidMoveToWindow");

internal static MarshalDelegates.Action_IntPtr_IntPtr TriggerViewDidMoveToWindow_Delegate = TriggerViewDidMoveToWindow;
static void TriggerViewDidMoveToWindow(IntPtr sender, IntPtr sel)
{
var obj = Runtime.GetNSObject(sender);

Messaging.void_objc_msgSendSuper(obj.SuperHandle, sel);

if (MacBase.GetHandler(obj) is IMacViewHandler handler)
{
handler.OnViewDidMoveToWindow();
}
}
}

public abstract partial class MacView<TControl, TWidget, TCallback> : MacObject<TControl, TWidget, TCallback>, Control.IHandler, IMacViewHandler
Expand Down Expand Up @@ -1575,6 +1592,31 @@ public virtual void UpdateLayout()
{
ContainerControl?.Window?.LayoutIfNeeded();
}

public bool AutoAttachNative
{
get => Widget.Properties.Get<bool>(MacView.AutoAttachNative_Key);
set
{
if (Widget.Properties.TrySet(MacView.AutoAttachNative_Key, value) && value)
{
// ensure method is added to the container control's class
AddMethod(MacView.selViewDidMoveToWindow, MacView.TriggerViewDidMoveToWindow_Delegate, "v@:@", ContainerControl);
}
}
}

public virtual void OnViewDidMoveToWindow()
{
if (!AutoAttachNative)
return;

// ensure load/unload get called appropriately.
if (ContainerControl.Window == null)
Widget.DetachNative();
else
Widget.AttachNative();
}
}
}

16 changes: 16 additions & 0 deletions src/Eto.Mac/MacHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,22 @@ public static NSView ToNative(this Control control, bool attach = false)
}
return control.GetContainerView();
}

/// <summary>
/// Sets a value indicating that the control should auto attach/detach when added to a native window.
/// </summary>
/// <remarks>
/// This is an alternative to using AttachNative/DetachNative manually, and will automatically be called when the view
/// is added/removed to/from a native Window. This ensures that both Load and UnLoad are triggered on the Eto control(s).
/// </remarks>
/// <param name="control">Control to auto attach</param>
/// <param name="autoAttach"><c>true</c> to auto attach, <c>false</c> otherwise.</param>
public static void SetAutoAttach(this Control control, bool autoAttach)
{
var handler = control.GetMacViewHandler();
if (handler != null)
handler.AutoAttachNative = true;
}

/// <summary>
/// Wraps the specified <paramref name="view"/> to an Eto control that can be used directly in Eto.Forms code.
Expand Down