Skip to content

Commit

Permalink
Merge pull request #2590 from cwensley/curtis/nativecontrolhost-subclass
Browse files Browse the repository at this point in the history
Add ability to set up native control when subclassing NativeControlHost
  • Loading branch information
cwensley authored Dec 6, 2023
2 parents 7a11c1b + 7cb4b9e commit ab88733
Show file tree
Hide file tree
Showing 10 changed files with 235 additions and 61 deletions.
35 changes: 27 additions & 8 deletions src/Eto.Gtk/Forms/Controls/NativeControlHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,46 @@ public NativeControlHandler()
{
}

public void Create(object controlObject)
protected override void Initialize()
{
if (controlObject == null)
// don't call any initialize routines as we are hosting a native control
// base.Initialize();
}

protected override Gtk.Widget CreateControl()
{
if (Widget is NativeControlHost host && Callback is NativeControlHost.ICallback callback)
{
var args = new CreateNativeControlArgs();
callback.OnCreateNativeControl(host, args);
return CreateHost(args.NativeControl);
}
return base.CreateControl();
}

public void Create(object nativeControl) => CreateHost(nativeControl);

Gtk.Widget CreateHost(object nativeControl)
{
if (nativeControl == null)
{
Control = _eventBox;
return _eventBox;
}
else if (controlObject is Gtk.Widget widget)
else if (nativeControl is Gtk.Widget widget)
{
Control = widget;
_eventBox.Child = widget;
return _eventBox;
}
else if (controlObject is IntPtr handle)
else if (nativeControl is IntPtr handle)
{
widget = GLib.Object.GetObject(handle) as Gtk.Widget;
if (widget == null)
throw new InvalidOperationException("Could not convert handle to Gtk.Widget");
Control = widget;
_eventBox.Child = widget;
return _eventBox;
}
else
throw new NotSupportedException($"controlObject of type {controlObject.GetType()} is not supported by this platform");
throw new NotSupportedException($"Native control of type {nativeControl.GetType()} is not supported by this platform");
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Eto.Gtk/GtkHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static Control ToEto(this Gtk.Widget nativeWidget)
{
if (nativeWidget == null)
return null;
return new Control(new NativeControlHandler(nativeWidget));
return new NativeControlHost(nativeWidget);
}

/// <summary>
Expand Down
47 changes: 37 additions & 10 deletions src/Eto.Mac/Forms/Controls/NativeControlHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,26 @@ public NativeControlHandler()
{
}

protected override void Initialize()
{
// don't call any initialize routines as we are hosting a native control
base.Initialize();
}

protected override NSView CreateControl()
{
if (Widget is NativeControlHost host && Callback is NativeControlHost.ICallback callback)
{
var args = new CreateNativeControlArgs();
callback.OnCreateNativeControl(host, args);
return CreateHost(args.NativeControl);
}
return base.CreateControl();
}

public override SizeF GetPreferredSize(SizeF availableSize)
{
return Control.FittingSize.ToEto();
return Control?.FittingSize.ToEto() ?? SizeF.Empty;
}

public NativeControlHandler(NSViewController nativeControl)
Expand All @@ -24,27 +41,37 @@ public NativeControlHandler(NSViewController nativeControl)
Control = controller.View;
}

public override NSView ContainerControl { get { return Control; } }
public override NSView ContainerControl => Control;

public void Create(object controlObject)
public void Create(object nativeControl)
{
Control = CreateHost(nativeControl);
}

NSView CreateHost(object nativeControl)
{
if (controlObject == null)
if (nativeControl == null)
{
return new NSView();
}
else if (nativeControl is NSView view)
{
Control = new NSView();
return view;
}
else if (controlObject is NSView view)
else if (nativeControl is NSViewController viewController)
{
Control = view;
controller = viewController;
return controller.View;
}
else if (controlObject is IntPtr handle)
else if (nativeControl is IntPtr handle)
{
view = Runtime.GetNSObject(handle) as NSView;
if (view == null)
throw new InvalidOperationException("supplied handle is invalid or does not refer to an object derived from NSView");
Control = view;
return view;
}
else
throw new NotSupportedException($"controlObject of type {controlObject.GetType()} is not supported by this platform");
throw new NotSupportedException($"Native control of type {nativeControl.GetType()} is not supported by this platform");
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Eto.Mac/MacHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public static Control ToEto(this NSView view)
{
if (view == null)
return null;
return new Control(new NativeControlHandler(view));
return new NativeControlHost(view);
}

/// <summary>
Expand All @@ -78,7 +78,7 @@ public static Control ToEto(this NSViewController viewController)
{
if (viewController == null)
return null;
return new Control(new NativeControlHandler(viewController));
return new NativeControlHost(viewController);
}

/// <summary>
Expand Down
52 changes: 37 additions & 15 deletions src/Eto.WinForms/Forms/Controls/NativeControlHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,42 +14,64 @@ public NativeControlHandler()
{
}

protected override void Initialize()
{
// don't call any initialize routines as we are hosting a native control
//base.Initialize();
}

protected override swf.Control CreateControl()
{
if (Widget is NativeControlHost host && Callback is NativeControlHost.ICallback callback)
{
var args = new CreateNativeControlArgs();
callback.OnCreateNativeControl(host, args);
return CreateHost(args.NativeControl);
}
return base.CreateControl();
}


public void Create(object controlObject)
public void Create(object nativeControl)
{
Control = CreateHost(nativeControl);
}
swf.Control CreateHost(object nativeControl)
{
if (controlObject == null)
if (nativeControl == null)
{
Control = new swf.UserControl();
return new swf.UserControl();
}
else if (controlObject is swf.Control control)
else if (nativeControl is swf.Control control)
{
Control = control;
return control;
}
else if (controlObject is IntPtr handle)
else if (nativeControl is IntPtr handle)
{
CreateWithHandle(handle);
return CreateWithHandle(handle);
}
else if (controlObject is swf.IWin32Window win32Window)
else if (nativeControl is swf.IWin32Window win32Window)
{
// keep a reference so it doesn't get GC'd
_win32Window = win32Window;
CreateWithHandle(win32Window.Handle);
return CreateWithHandle(win32Window.Handle);
}
else
throw new NotSupportedException($"controlObject of type {controlObject.GetType()} is not supported by this platform");
throw new NotSupportedException($"Native control of type {nativeControl.GetType()} is not supported by this platform");
}

private void CreateWithHandle(IntPtr handle)
private swf.Control CreateWithHandle(IntPtr handle)
{
Control = new swf.Control();
var control = new swf.Control();
Win32.GetWindowRect(handle, out var rect);
Win32.SetParent(handle, Control.Handle);
Control.Size = rect.ToSD().Size;
Win32.SetParent(handle, control.Handle);
control.Size = rect.ToSD().Size;
Widget.SizeChanged += (sender, e) =>
{
var size = Control.Size;
var size = control.Size;
Win32.SetWindowPos(handle, IntPtr.Zero, 0, 0, size.Width, size.Height, Win32.SWP.NOZORDER);
};
return control;
}
}
}
Expand Down
6 changes: 2 additions & 4 deletions src/Eto.WinForms/Forms/WindowsControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,9 @@ protected override void OnParentBackColorChanged(EventArgs e)

Control.ICallback IWindowsControl.Callback { get { return Callback; } }

public bool XScale { get; set; }
public bool XScale { get; set; } = true;

public bool YScale { get; set; }
public bool YScale { get; set; } = true;

public virtual Size? GetDefaultSize(Size availableSize) { return null; }// Control.GetPreferredSize(availableSize.ToSD()).ToEto(); }

Expand Down Expand Up @@ -276,8 +276,6 @@ public bool MouseCaptured
protected override void Initialize()
{
base.Initialize();
XScale = true;
YScale = true;
Control.Margin = swf.Padding.Empty;
Control.Tag = this;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Eto.WinForms/WinFormsHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static Control ToEto(this swf.Control nativeControl)
{
if (nativeControl == null)
return null;
return new Control(new NativeControlHandler(nativeControl));
return new NativeControlHost(nativeControl);
}

/// <summary>
Expand Down
46 changes: 34 additions & 12 deletions src/Eto.Wpf/Forms/Controls/NativeControlHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,44 +25,66 @@ public NativeControlHandler(sw.FrameworkElement nativeControl)
Control = nativeControl;
}

protected override void Initialize()
{
// don't call any initialize routines as we are hosting a native control
// base.Initialize();
}

protected override sw.FrameworkElement CreateControl()
{
if (Widget is NativeControlHost host && Callback is NativeControlHost.ICallback callback)
{
var args = new CreateNativeControlArgs();
callback.OnCreateNativeControl(host, args);
return CreateHost(args.NativeControl);
}
return base.CreateControl();
}

public override Color BackgroundColor
{
get => throw new NotSupportedException("You cannot get this property for native controls");
set => throw new NotSupportedException("You cannot set this property for native controls");
}

public void Create(object controlObject)
public void Create(object nativeControl)
{
Control = CreateHost(nativeControl);
}

public sw.FrameworkElement CreateHost(object nativeControl)
{
if (controlObject == null)
if (nativeControl == null)
{
var host = new EtoHwndHost(null);
host.GetPreferredSize += () => Size.Round(UserPreferredSize.ToEto() * (Widget.ParentWindow?.Screen?.LogicalPixelSize ?? 1));
Control = host;
return host;
}
else if (controlObject is sw.FrameworkElement element)
else if (nativeControl is sw.FrameworkElement element)
{
Control = element;
return element;
}
else if (controlObject is IntPtr handle)
else if (nativeControl is IntPtr handle)
{
Control = new EtoHwndHost(new HandleRef(this, handle));
return new EtoHwndHost(new HandleRef(this, handle));
}
else if (controlObject is IWin32WindowWinForms win32Window)
else if (nativeControl is IWin32WindowWinForms win32Window)
{
// keep a reference to the win32window object
var host = new EtoHwndHost(new HandleRef(win32Window, win32Window.Handle));
host.GetPreferredSize += () => Size.Round(UserPreferredSize.ToEto() * (Widget.ParentWindow?.Screen?.LogicalPixelSize ?? 1));
Control = host;
return host;
}
else if (controlObject is IWin32WindowInterop win32WindowWpf)
else if (nativeControl is IWin32WindowInterop win32WindowWpf)
{
// keep a reference to the win32window object
var host = new EtoHwndHost(new HandleRef(win32WindowWpf, win32WindowWpf.Handle));
host.GetPreferredSize += () => Size.Round(UserPreferredSize.ToEto() * (Widget.ParentWindow?.Screen?.LogicalPixelSize ?? 1));
Control = host;
return host;
}
else
throw new NotSupportedException($"controlObject of type {controlObject.GetType()} is not supported by this platform");
throw new NotSupportedException($"Native control of type {nativeControl.GetType()} is not supported by this platform");
}
}

Expand Down
Loading

0 comments on commit ab88733

Please sign in to comment.