-
-
Notifications
You must be signed in to change notification settings - Fork 335
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2589 from cwensley/curtis/nativecontrolhost
Add NativeControlHost
- Loading branch information
Showing
21 changed files
with
464 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,43 @@ | ||
namespace Eto.GtkSharp.Forms.Controls | ||
| ||
namespace Eto.GtkSharp.Forms.Controls | ||
{ | ||
public class NativeControlHandler : GtkControl<Gtk.Widget, Control, Control.ICallback> | ||
public class NativeControlHandler : GtkControl<Gtk.Widget, Control, Control.ICallback>, NativeControlHost.IHandler | ||
{ | ||
|
||
Gtk.EventBox _eventBox = new Gtk.EventBox(); | ||
public override Gtk.Widget ContainerControl => _eventBox; | ||
|
||
public NativeControlHandler(Gtk.Widget nativeControl) | ||
{ | ||
Control = nativeControl; | ||
} | ||
|
||
public NativeControlHandler() | ||
{ | ||
} | ||
|
||
public void Create(object controlObject) | ||
{ | ||
if (controlObject == null) | ||
{ | ||
Control = _eventBox; | ||
} | ||
else if (controlObject is Gtk.Widget widget) | ||
{ | ||
Control = widget; | ||
_eventBox.Child = widget; | ||
} | ||
else if (controlObject 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; | ||
} | ||
else | ||
throw new NotSupportedException($"controlObject of type {controlObject.GetType()} is not supported by this platform"); | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,56 @@ | ||
namespace Eto.WinForms.Forms.Controls | ||
| ||
|
||
namespace Eto.WinForms.Forms.Controls | ||
{ | ||
public class NativeControlHandler : WindowsControl<swf.Control, Control, Control.ICallback> | ||
public class NativeControlHandler : WindowsControl<swf.Control, Control, Control.ICallback>, NativeControlHost.IHandler | ||
{ | ||
swf.IWin32Window _win32Window; | ||
public NativeControlHandler(swf.Control nativeControl) | ||
{ | ||
Control = nativeControl; | ||
} | ||
|
||
public NativeControlHandler() | ||
{ | ||
} | ||
|
||
|
||
public void Create(object controlObject) | ||
{ | ||
if (controlObject == null) | ||
{ | ||
Control = new swf.UserControl(); | ||
} | ||
else if (controlObject is swf.Control control) | ||
{ | ||
Control = control; | ||
} | ||
else if (controlObject is IntPtr handle) | ||
{ | ||
CreateWithHandle(handle); | ||
} | ||
else if (controlObject is swf.IWin32Window win32Window) | ||
{ | ||
// keep a reference so it doesn't get GC'd | ||
_win32Window = win32Window; | ||
CreateWithHandle(win32Window.Handle); | ||
} | ||
else | ||
throw new NotSupportedException($"controlObject of type {controlObject.GetType()} is not supported by this platform"); | ||
} | ||
|
||
private void CreateWithHandle(IntPtr handle) | ||
{ | ||
Control = new swf.Control(); | ||
Win32.GetWindowRect(handle, out var rect); | ||
Win32.SetParent(handle, Control.Handle); | ||
Control.Size = rect.ToSD().Size; | ||
Widget.SizeChanged += (sender, e) => | ||
{ | ||
var size = Control.Size; | ||
Win32.SetWindowPos(handle, IntPtr.Zero, 0, 0, size.Width, size.Height, Win32.SWP.NOZORDER); | ||
}; | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
165 changes: 152 additions & 13 deletions
165
src/Eto.Wpf/Forms/Controls/NativeControlHandler.cs
100644 → 100755
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,161 @@ | ||
namespace Eto.Wpf.Forms.Controls | ||
using Eto.Forms; | ||
using System.Windows.Interop; | ||
using IWin32WindowWinForms = System.Windows.Forms.IWin32Window; | ||
using IWin32WindowInterop = System.Windows.Interop.IWin32Window; | ||
|
||
namespace Eto.Wpf.Forms.Controls; | ||
public class NativeControlHandler : WpfFrameworkElement<sw.FrameworkElement, Control, Control.ICallback>, NativeControlHost.IHandler | ||
{ | ||
public class NativeControlHandler : WpfFrameworkElement<sw.FrameworkElement, Control, Control.ICallback> | ||
public override IntPtr NativeHandle | ||
{ | ||
get | ||
{ | ||
if (Control is EtoHwndHost host) | ||
return host.Handle; | ||
return base.NativeHandle; | ||
} | ||
} | ||
|
||
public NativeControlHandler() | ||
{ | ||
} | ||
|
||
public NativeControlHandler(sw.FrameworkElement nativeControl) | ||
{ | ||
Control = nativeControl; | ||
} | ||
|
||
public override Color BackgroundColor | ||
{ | ||
public NativeControlHandler(sw.FrameworkElement nativeControl) | ||
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) | ||
{ | ||
if (controlObject == null) | ||
{ | ||
var host = new EtoHwndHost(null); | ||
host.GetPreferredSize += () => Size.Round(UserPreferredSize.ToEto() * (Widget.ParentWindow?.Screen?.LogicalPixelSize ?? 1)); | ||
Control = host; | ||
} | ||
else if (controlObject is sw.FrameworkElement element) | ||
{ | ||
Control = element; | ||
} | ||
else if (controlObject is IntPtr handle) | ||
{ | ||
Control = new EtoHwndHost(new HandleRef(this, handle)); | ||
} | ||
else if (controlObject 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; | ||
} | ||
else if (controlObject is IWin32WindowInterop win32WindowWpf) | ||
{ | ||
Control = nativeControl; | ||
// 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; | ||
} | ||
else | ||
throw new NotSupportedException($"controlObject of type {controlObject.GetType()} is not supported by this platform"); | ||
} | ||
} | ||
|
||
sealed class EtoHwndHost : HwndHost | ||
{ | ||
HandleRef? _hwnd; | ||
swc.ScrollViewer _parentScrollViewer; | ||
sd.Rectangle _regionRect = sd.Rectangle.Empty; | ||
|
||
public Func<Size> GetPreferredSize { get; set; } | ||
|
||
public override Eto.Drawing.Color BackgroundColor | ||
public EtoHwndHost(HandleRef? hwnd) | ||
{ | ||
_hwnd = hwnd; | ||
} | ||
|
||
protected override HandleRef BuildWindowCore(HandleRef hwndParent) | ||
{ | ||
if (_hwnd == null) | ||
{ | ||
get | ||
{ | ||
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "You cannot get this property for native controls")); | ||
} | ||
set | ||
{ | ||
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "You cannot set this property for native controls")); | ||
} | ||
// create a new WinForms Usercontrol to host whatever we want | ||
var size = GetPreferredSize?.Invoke() ?? new Size(100, 100); | ||
var ctl = new swf.UserControl(); | ||
ctl.Size = size.ToSD(); | ||
_hwnd = new HandleRef(ctl, ctl.Handle); | ||
} | ||
Win32.SetParent(_hwnd.Value.Handle, hwndParent.Handle); | ||
HookParentScrollViewer(); | ||
return _hwnd.Value; | ||
} | ||
|
||
protected override void OnVisualParentChanged(sw.DependencyObject oldParent) | ||
{ | ||
base.OnVisualParentChanged(oldParent); | ||
HookParentScrollViewer(); | ||
} | ||
|
||
void HookParentScrollViewer() | ||
{ | ||
if (_parentScrollViewer != null) | ||
_parentScrollViewer.ScrollChanged -= ParentScrollViewerScrollChanged; | ||
_regionRect = sd.Rectangle.Empty; | ||
_parentScrollViewer = this.GetVisualParent<swc.ScrollViewer>(); | ||
if (_parentScrollViewer != null) | ||
_parentScrollViewer.ScrollChanged += ParentScrollViewerScrollChanged; | ||
} | ||
|
||
protected override void DestroyWindowCore(HandleRef hwnd) | ||
{ | ||
} | ||
|
||
private void ParentScrollViewerScrollChanged(object sender, swc.ScrollChangedEventArgs e) | ||
{ | ||
UpdateRegion(); | ||
} | ||
|
||
double LogicalPixelSize => sw.PresentationSource.FromVisual(this)?.CompositionTarget.TransformToDevice.M11 ?? 1.0; | ||
|
||
sd.Size ScaledSize(double w, double h) | ||
{ | ||
var pixelSize = LogicalPixelSize; | ||
return new sd.Size((int)Math.Round(w * pixelSize), (int)Math.Round(h * pixelSize)); | ||
} | ||
|
||
void UpdateRegion() | ||
{ | ||
if (_parentScrollViewer == null || !IsVisible) | ||
return; | ||
|
||
if (_parentScrollViewer.Content is not sw.FrameworkElement content) | ||
return; | ||
|
||
var transform = content.TransformToDescendant(this); | ||
var offset = transform.Transform(new sw.Point(_parentScrollViewer.HorizontalOffset, _parentScrollViewer.VerticalOffset)); | ||
|
||
|
||
var loc = ScaledSize(offset.X, offset.Y); | ||
var size = ScaledSize(_parentScrollViewer.ViewportWidth, _parentScrollViewer.ViewportHeight); | ||
|
||
var rect = new sd.Rectangle(new sd.Point(loc), size); | ||
if (rect != _regionRect) | ||
{ | ||
SetRegion(rect); | ||
_regionRect = rect; | ||
} | ||
} | ||
|
||
private void SetRegion(sd.Rectangle rect) | ||
{ | ||
using (var graphics = sd.Graphics.FromHwnd(Handle)) | ||
Win32.SetWindowRgn(Handle, new sd.Region(rect).GetHrgn(graphics), true); | ||
} | ||
|
||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.