merge frame part of DispUtil to DispFrameUtil.

This commit is contained in:
iamboss 2026-02-15 16:08:00 +08:00
parent 688762ab70
commit c1f3fefdc0
3 changed files with 548 additions and 490 deletions

View File

@ -11,464 +11,463 @@ using System.Collections.Generic;
using Hi.Geom;
using Microsoft.Win32; // Add this for SystemEvents
namespace Hi.WpfPlus.Disp
namespace Hi.WpfPlus.Disp;
#region WPF Rendering Canvas
/// <summary>
/// Provides a WPF rendering canvas for 3D visualization of HiAPI components.
/// Handles user interactions, rendering, and integration with the DispEngine system.
/// </summary>
/// <remarks>
/// This canvas provides the core rendering capabilities for WPF applications using HiAPI.
/// It manages mouse, keyboard, and touch events, and transforms them into appropriate
/// actions in the 3D environment.
/// </remarks>
public class RenderingCanvas : UserControl, IDisposable
{
#region WPF Rendering Canvas
/// <summary>
/// Provides a WPF rendering canvas for 3D visualization of HiAPI components.
/// Handles user interactions, rendering, and integration with the DispEngine system.
/// </summary>
/// <remarks>
/// This canvas provides the core rendering capabilities for WPF applications using HiAPI.
/// It manages mouse, keyboard, and touch events, and transforms them into appropriate
/// actions in the 3D environment.
/// </remarks>
public class RenderingCanvas : UserControl, IDisposable
{
#region Core_Properties
/// <summary>
/// The DispEngine instance that handles rendering and user interactions
/// </summary>
public DispEngine DispEngine { get; } = new DispEngine();
#region Core_Properties
/// <summary>
/// The DispEngine instance that handles rendering and user interactions
/// </summary>
public DispEngine DispEngine { get; } = new DispEngine();
/// <summary>
/// Internal container for rendering content
/// </summary>
private UserControl DisplayerPane { get; }
/// <summary>
/// Internal container for rendering content
/// </summary>
private UserControl DisplayerPane { get; }
/// <summary>
/// Dictionary to store touch point information
/// </summary>
private Dictionary<int, Point> TouchingPointsMap { get; } = new Dictionary<int, Point>();
/// <summary>
/// Dictionary to store touch point information
/// </summary>
private Dictionary<int, Point> TouchingPointsMap { get; } = new Dictionary<int, Point>();
/// <summary>
/// Dictionary to store previous positions of touch points
/// </summary>
private Dictionary<int, Point> PreviousTouchingPointsMap { get; } = new Dictionary<int, Point>();
#endregion
/// <summary>
/// Dictionary to store previous positions of touch points
/// </summary>
private Dictionary<int, Point> PreviousTouchingPointsMap { get; } = new Dictionary<int, Point>();
#endregion
#region Power_Management
/// <summary>
/// Handles system power mode changes
/// </summary>
private void InitializePowerManagement()
{
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
}
#region Power_Management
/// <summary>
/// Handles system power mode changes
/// </summary>
private void InitializePowerManagement()
{
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
}
/// <summary>
/// Handles power mode change events
/// </summary>
private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
switch (e.Mode)
{
case PowerModes.Suspend:
DispEngine.IsVisible = false;
break;
case PowerModes.Resume:
DispEngine.IsVisible = IsVisible;
break;
}
}
#endregion
/// <summary>
/// Handles power mode change events
/// </summary>
private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
switch (e.Mode)
{
case PowerModes.Suspend:
DispEngine.IsVisible = false;
break;
case PowerModes.Resume:
DispEngine.IsVisible = IsVisible;
break;
}
}
#endregion
#region Initialization
/// <summary>
/// Initializes a new instance of the RenderingCanvas
/// </summary>
public RenderingCanvas()
{
DispEngine.BackgroundColor = new Vec3d(0.1, 0.1, 0.5);
DispEngine.BackgroundOpacity = 0.1;
#region Initialization
/// <summary>
/// Initializes a new instance of the RenderingCanvas
/// </summary>
public RenderingCanvas()
{
DispEngine.BackgroundColor = new Vec3d(0.1, 0.1, 0.5);
DispEngine.BackgroundOpacity = 0.1;
// Configure the main control properties
HorizontalAlignment = HorizontalAlignment.Stretch;
VerticalAlignment = VerticalAlignment.Stretch;
Focusable = true;
KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Cycle);
DataContextChanged += CanvasDataContextChanged;
// Configure the main control properties
HorizontalAlignment = HorizontalAlignment.Stretch;
VerticalAlignment = VerticalAlignment.Stretch;
Focusable = true;
KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Cycle);
DataContextChanged += CanvasDataContextChanged;
// Create and configure the display pane
DisplayerPane = new UserControl();
DisplayerPane.HorizontalAlignment = HorizontalAlignment.Stretch;
DisplayerPane.VerticalAlignment = VerticalAlignment.Stretch;
DisplayerPane.Focusable = true;
DisplayerPane.IsTabStop = true;
// Create and configure the display pane
DisplayerPane = new UserControl();
DisplayerPane.HorizontalAlignment = HorizontalAlignment.Stretch;
DisplayerPane.VerticalAlignment = VerticalAlignment.Stretch;
DisplayerPane.Focusable = true;
DisplayerPane.IsTabStop = true;
// Connect event handlers for user input and window events
DisplayerPane.SizeChanged += RenderingCanvas_SizeChanged;
DisplayerPane.MouseMove += RenderingCanvas_MouseMove;
DisplayerPane.MouseDown += RenderingCanvas_MouseDown;
DisplayerPane.MouseUp += RenderingCanvas_MouseUp;
DisplayerPane.MouseWheel += RenderingCanvas_MouseWheel;
DisplayerPane.KeyDown += RenderingCanvas_KeyDown;
DisplayerPane.KeyUp += RenderingCanvas_KeyUp;
DisplayerPane.Loaded += RenderingCanvas_Loaded;
DisplayerPane.Unloaded += RenderingCanvas_Unloaded;
DisplayerPane.IsVisibleChanged += DisplayerPane_IsVisibleChanged;
// Connect event handlers for user input and window events
DisplayerPane.SizeChanged += RenderingCanvas_SizeChanged;
DisplayerPane.MouseMove += RenderingCanvas_MouseMove;
DisplayerPane.MouseDown += RenderingCanvas_MouseDown;
DisplayerPane.MouseUp += RenderingCanvas_MouseUp;
DisplayerPane.MouseWheel += RenderingCanvas_MouseWheel;
DisplayerPane.KeyDown += RenderingCanvas_KeyDown;
DisplayerPane.KeyUp += RenderingCanvas_KeyUp;
DisplayerPane.Loaded += RenderingCanvas_Loaded;
DisplayerPane.Unloaded += RenderingCanvas_Unloaded;
DisplayerPane.IsVisibleChanged += DisplayerPane_IsVisibleChanged;
// Add touch event handlers
DisplayerPane.TouchDown += RenderingCanvas_TouchDown;
DisplayerPane.TouchMove += RenderingCanvas_TouchMove;
DisplayerPane.TouchUp += RenderingCanvas_TouchUp;
// Add touch event handlers
DisplayerPane.TouchDown += RenderingCanvas_TouchDown;
DisplayerPane.TouchMove += RenderingCanvas_TouchMove;
DisplayerPane.TouchUp += RenderingCanvas_TouchUp;
// Enable touch support
this.IsManipulationEnabled = true;
// Enable touch support
this.IsManipulationEnabled = true;
// Initialize power management
InitializePowerManagement();
// Initialize power management
InitializePowerManagement();
// Add the display pane to this control's content
Content = DisplayerPane;
}
#endregion
// Add the display pane to this control's content
Content = DisplayerPane;
}
#endregion
#region Touch_Events
/// <summary>
/// Handles the touch down event
/// </summary>
private void RenderingCanvas_TouchDown(object sender, TouchEventArgs e)
{
// Add touch point to dictionary
Point touchPoint = e.GetTouchPoint(DisplayerPane).Position;
DispEngine.TouchDown(e.TouchDevice.Id,
(int)touchPoint.X, (int)touchPoint.Y);
#region Touch_Events
/// <summary>
/// Handles the touch down event
/// </summary>
private void RenderingCanvas_TouchDown(object sender, TouchEventArgs e)
{
// Add touch point to dictionary
Point touchPoint = e.GetTouchPoint(DisplayerPane).Position;
DispEngine.TouchDown(e.TouchDevice.Id,
(int)touchPoint.X, (int)touchPoint.Y);
// Ensure control gets focus
DisplayerPane.Focus();
e.TouchDevice.Capture(DisplayerPane);
// Ensure control gets focus
DisplayerPane.Focus();
e.TouchDevice.Capture(DisplayerPane);
e.Handled = true;
}
e.Handled = true;
}
/// <summary>
/// Handles the touch move event
/// </summary>
private void RenderingCanvas_TouchMove(object sender, TouchEventArgs e)
{
Point touchPoint = e.GetTouchPoint(DisplayerPane).Position;
DispEngine.TouchMove(e.TouchDevice.Id,
(int)touchPoint.X, (int)touchPoint.Y);
e.Handled = true;
}
/// <summary>
/// Handles the touch move event
/// </summary>
private void RenderingCanvas_TouchMove(object sender, TouchEventArgs e)
{
Point touchPoint = e.GetTouchPoint(DisplayerPane).Position;
DispEngine.TouchMove(e.TouchDevice.Id,
(int)touchPoint.X, (int)touchPoint.Y);
e.Handled = true;
}
/// <summary>
/// Handles the touch up event
/// </summary>
private void RenderingCanvas_TouchUp(object sender, TouchEventArgs e)
{
DispEngine.TouchUp(e.TouchDevice.Id);
e.Handled = true;
}
#endregion
/// <summary>
/// Handles the touch up event
/// </summary>
private void RenderingCanvas_TouchUp(object sender, TouchEventArgs e)
{
DispEngine.TouchUp(e.TouchDevice.Id);
e.Handled = true;
}
#endregion
#region Window_Events
/// <summary>
/// Handles window state changes (maximize, minimize, etc.)
/// </summary>
private unsafe void RenderingCanvas_StateChanged(object sender, EventArgs e)
{
switch ((sender as Window).WindowState)
{
case WindowState.Maximized:
DispEngine.IsVisible = true;
break;
case WindowState.Minimized:
DispEngine.IsVisible = false;
break;
case WindowState.Normal:
DispEngine.IsVisible = true;
break;
}
}
#region Window_Events
/// <summary>
/// Handles window state changes (maximize, minimize, etc.)
/// </summary>
private unsafe void RenderingCanvas_StateChanged(object sender, EventArgs e)
{
switch ((sender as Window).WindowState)
{
case WindowState.Maximized:
DispEngine.IsVisible = true;
break;
case WindowState.Minimized:
DispEngine.IsVisible = false;
break;
case WindowState.Normal:
DispEngine.IsVisible = true;
break;
}
}
/// <summary>
/// Handles data context changes
/// </summary>
private unsafe void CanvasDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
DispEngine pre = e.OldValue as DispEngine;
DispEngine cur = e.NewValue as DispEngine;
/// <summary>
/// Handles data context changes
/// </summary>
private unsafe void CanvasDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
DispEngine pre = e.OldValue as DispEngine;
DispEngine cur = e.NewValue as DispEngine;
//child's binding event is triggered after IsVisible event and Load event.
if (pre != null) //this section will never occur if the datacontext not set twice.
{
pre.Terminate();
pre.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
}
if (cur != null)
{
cur.ImageRequestAfterBufferSwapped += RenderingCanvas_BufferSwapped;
cur.Start((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
//child's binding event is triggered after IsVisible event and Load event.
if (pre != null) //this section will never occur if the datacontext not set twice.
{
pre.Terminate();
pre.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
}
if (cur != null)
{
cur.ImageRequestAfterBufferSwapped += RenderingCanvas_BufferSwapped;
cur.Start((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
cur.IsVisible = IsVisible;
}
}
cur.IsVisible = IsVisible;
}
}
/// <summary>
/// Reference to the current window containing this control
/// </summary>
private Window currentWindow;
/// <summary>
/// Reference to the current window containing this control
/// </summary>
private Window currentWindow;
/// <summary>
/// Gets or sets the current window, connecting or disconnecting state change events
/// </summary>
Window CurrentWindow
{
get => currentWindow; set
{
if (currentWindow != null)
currentWindow.StateChanged -= RenderingCanvas_StateChanged;
currentWindow = value;
if (currentWindow != null)
currentWindow.StateChanged += RenderingCanvas_StateChanged;
}
}
/// <summary>
/// Gets or sets the current window, connecting or disconnecting state change events
/// </summary>
Window CurrentWindow
{
get => currentWindow; set
{
if (currentWindow != null)
currentWindow.StateChanged -= RenderingCanvas_StateChanged;
currentWindow = value;
if (currentWindow != null)
currentWindow.StateChanged += RenderingCanvas_StateChanged;
}
}
/// <summary>
/// Handles the loaded event
/// </summary>
private unsafe void RenderingCanvas_Loaded(object sender, RoutedEventArgs e)
{
// Get the window containing this control
CurrentWindow = Window.GetWindow(this);
/// <summary>
/// Handles the loaded event
/// </summary>
private unsafe void RenderingCanvas_Loaded(object sender, RoutedEventArgs e)
{
// Get the window containing this control
CurrentWindow = Window.GetWindow(this);
// Set up DispEngine rendering
DispEngine.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
DispEngine.ImageRequestAfterBufferSwapped += RenderingCanvas_BufferSwapped;
DispEngine.Start((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
DispEngine.IsVisible = IsVisible;
}
// Set up DispEngine rendering
DispEngine.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
DispEngine.ImageRequestAfterBufferSwapped += RenderingCanvas_BufferSwapped;
DispEngine.Start((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
DispEngine.IsVisible = IsVisible;
}
/// <summary>
/// Handles the unloaded event
/// </summary>
private unsafe void RenderingCanvas_Unloaded(object sender, RoutedEventArgs e)
{
DispEngine.IsVisible = IsVisible;
DispEngine.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
CurrentWindow = null;
}
#endregion
/// <summary>
/// Handles the unloaded event
/// </summary>
private unsafe void RenderingCanvas_Unloaded(object sender, RoutedEventArgs e)
{
DispEngine.IsVisible = IsVisible;
DispEngine.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
CurrentWindow = null;
}
#endregion
#region DispEngine_Rendering
/// <summary>
/// Handles the buffer swapped event from DispEngine
/// </summary>
private unsafe void RenderingCanvas_BufferSwapped(byte* data, int w, int h)
{
if (data == null)
return;
#region DispEngine_Rendering
/// <summary>
/// Handles the buffer swapped event from DispEngine
/// </summary>
private unsafe void RenderingCanvas_BufferSwapped(byte* data, int w, int h)
{
if (data == null)
return;
Span<byte> bgra = new Span<byte>(data, w * h * 4);
Span<byte> bgra = new Span<byte>(data, w * h * 4);
// Copy pixel data from DispEngine
int n = w * h * 4;
byte[] arr = new byte[n];
for (int i = 0; i < n; i++)
arr[i] = data[i];
// Copy pixel data from DispEngine
int n = w * h * 4;
byte[] arr = new byte[n];
for (int i = 0; i < n; i++)
arr[i] = data[i];
// Update UI on the UI thread
DisplayerPane.Dispatcher.InvokeAsync(() =>
{
BitmapSource bitmap = BitmapSource.Create(w, h, 1, 1, PixelFormats.Bgra32, null, arr, w * 4);
DisplayerPane.Background = new ImageBrush(bitmap);
});
}
// Update UI on the UI thread
DisplayerPane.Dispatcher.InvokeAsync(() =>
{
BitmapSource bitmap = BitmapSource.Create(w, h, 1, 1, PixelFormats.Bgra32, null, arr, w * 4);
DisplayerPane.Background = new ImageBrush(bitmap);
});
}
/// <summary>
/// Handles the size changed event
/// </summary>
private void RenderingCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
{
// Notify DispEngine of size changes
DispEngine.Resize((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
}
/// <summary>
/// Handles the size changed event
/// </summary>
private void RenderingCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
{
// Notify DispEngine of size changes
DispEngine.Resize((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
}
/// <summary>
/// Handles visibility changes
/// </summary>
private unsafe void DisplayerPane_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
// Update visibility state in DispEngine
DispEngine.IsVisible = IsVisible;
}
#endregion
/// <summary>
/// Handles visibility changes
/// </summary>
private unsafe void DisplayerPane_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
// Update visibility state in DispEngine
DispEngine.IsVisible = IsVisible;
}
#endregion
#region Keyboard_Events
/// <summary>
/// Convert WPF Key to W3C KeyboardEvent.key string.
/// </summary>
static string WpfKeyToW3C(Key key) => key switch
{
Key.Home => "Home",
Key.End => "End",
Key.PageUp => "PageUp",
Key.PageDown => "PageDown",
Key.Left => "ArrowLeft",
Key.Right => "ArrowRight",
Key.Up => "ArrowUp",
Key.Down => "ArrowDown",
Key.LeftShift or Key.RightShift => "Shift",
Key.LeftCtrl or Key.RightCtrl => "Control",
Key.LeftAlt or Key.RightAlt => "Alt",
Key.Return => "Enter",
Key.Escape => "Escape",
Key.Back => "Backspace",
Key.Tab => "Tab",
Key.Delete => "Delete",
Key.Insert => "Insert",
Key.Space => " ",
Key.F1 => "F1",
Key.F2 => "F2",
Key.F3 => "F3",
Key.F4 => "F4",
Key.F5 => "F5",
Key.F6 => "F6",
Key.F7 => "F7",
Key.F8 => "F8",
Key.F9 => "F9",
Key.F10 => "F10",
Key.F11 => "F11",
Key.F12 => "F12",
>= Key.A and <= Key.Z => ((char)('a' + (key - Key.A))).ToString(),
>= Key.D0 and <= Key.D9 => ((char)('0' + (key - Key.D0))).ToString(),
_ => "Unidentified"
};
#region Keyboard_Events
/// <summary>
/// Convert WPF Key to W3C KeyboardEvent.key string.
/// </summary>
static string WpfKeyToW3C(Key key) => key switch
{
Key.Home => "Home",
Key.End => "End",
Key.PageUp => "PageUp",
Key.PageDown => "PageDown",
Key.Left => "ArrowLeft",
Key.Right => "ArrowRight",
Key.Up => "ArrowUp",
Key.Down => "ArrowDown",
Key.LeftShift or Key.RightShift => "Shift",
Key.LeftCtrl or Key.RightCtrl => "Control",
Key.LeftAlt or Key.RightAlt => "Alt",
Key.Return => "Enter",
Key.Escape => "Escape",
Key.Back => "Backspace",
Key.Tab => "Tab",
Key.Delete => "Delete",
Key.Insert => "Insert",
Key.Space => " ",
Key.F1 => "F1",
Key.F2 => "F2",
Key.F3 => "F3",
Key.F4 => "F4",
Key.F5 => "F5",
Key.F6 => "F6",
Key.F7 => "F7",
Key.F8 => "F8",
Key.F9 => "F9",
Key.F10 => "F10",
Key.F11 => "F11",
Key.F12 => "F12",
>= Key.A and <= Key.Z => ((char)('a' + (key - Key.A))).ToString(),
>= Key.D0 and <= Key.D9 => ((char)('0' + (key - Key.D0))).ToString(),
_ => "Unidentified"
};
/// <summary>
/// Handles the key up event
/// </summary>
private void RenderingCanvas_KeyUp(object sender, KeyEventArgs e)
{
DispEngine.KeyUp(WpfKeyToW3C(e.Key));
}
/// <summary>
/// Handles the key up event
/// </summary>
private void RenderingCanvas_KeyUp(object sender, KeyEventArgs e)
{
DispEngine.KeyUp(WpfKeyToW3C(e.Key));
}
/// <summary>
/// Handles the key down event
/// </summary>
private void RenderingCanvas_KeyDown(object sender, KeyEventArgs e)
{
string key = WpfKeyToW3C(e.Key);
DispEngine.KeyDown(key);
/// <summary>
/// Handles the key down event
/// </summary>
private void RenderingCanvas_KeyDown(object sender, KeyEventArgs e)
{
string key = WpfKeyToW3C(e.Key);
DispEngine.KeyDown(key);
DispEngine.KeyDownTransform(key, new key_table__transform_view_by_key_pressing_t()
{
HOME = "Home",
PAGE_UP = "PageUp",
PAGE_DOWN = "PageDown",
F1 = "F1",
F2 = "F2",
F3 = "F3",
F4 = "F4",
SHIFT = "Shift",
ARROW_LEFT = "ArrowLeft",
ARROW_RIGHT = "ArrowRight",
ARROW_DOWN = "ArrowDown",
ARROW_UP = "ArrowUp"
});
}
#endregion
DispEngine.KeyDownTransform(key, new key_table__transform_view_by_key_pressing_t()
{
HOME = "Home",
PAGE_UP = "PageUp",
PAGE_DOWN = "PageDown",
F1 = "F1",
F2 = "F2",
F3 = "F3",
F4 = "F4",
SHIFT = "Shift",
ARROW_LEFT = "ArrowLeft",
ARROW_RIGHT = "ArrowRight",
ARROW_DOWN = "ArrowDown",
ARROW_UP = "ArrowUp"
});
}
#endregion
#region Mouse_Events
/// <summary>
/// Helper method to get mouse button mask
/// </summary>
internal static HiMouseButtonMask GetMouseButtonMask(MouseDevice device)
{
HiMouseButtonMask mouseButtonMask = 0;
mouseButtonMask.SetLeftPressed(device.LeftButton == MouseButtonState.Pressed);
mouseButtonMask.SetMiddlePressed(device.MiddleButton == MouseButtonState.Pressed);
mouseButtonMask.SetRightPressed(device.RightButton == MouseButtonState.Pressed);
mouseButtonMask.SetXButton1Pressed(device.XButton1 == MouseButtonState.Pressed);
mouseButtonMask.SetXButton2Pressed(device.XButton2 == MouseButtonState.Pressed);
return mouseButtonMask;
}
#region Mouse_Events
/// <summary>
/// Helper method to get mouse button mask
/// </summary>
internal static HiMouseButtonMask GetMouseButtonMask(MouseDevice device)
{
HiMouseButtonMask mouseButtonMask = 0;
mouseButtonMask.SetLeftPressed(device.LeftButton == MouseButtonState.Pressed);
mouseButtonMask.SetMiddlePressed(device.MiddleButton == MouseButtonState.Pressed);
mouseButtonMask.SetRightPressed(device.RightButton == MouseButtonState.Pressed);
mouseButtonMask.SetXButton1Pressed(device.XButton1 == MouseButtonState.Pressed);
mouseButtonMask.SetXButton2Pressed(device.XButton2 == MouseButtonState.Pressed);
return mouseButtonMask;
}
/// <summary>
/// Handles the mouse wheel event
/// </summary>
private void RenderingCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
// Handle mouse wheel for zoom operations
DispEngine.MouseWheel(0, e.Delta / 120);
DispEngine.MouseWheelTransform(0, e.Delta / 120);
}
/// <summary>
/// Handles the mouse wheel event
/// </summary>
private void RenderingCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
// Handle mouse wheel for zoom operations
DispEngine.MouseWheel(0, e.Delta / 120);
DispEngine.MouseWheelTransform(0, e.Delta / 120);
}
/// <summary>
/// Handles the mouse up event
/// </summary>
private void RenderingCanvas_MouseUp(object sender, MouseButtonEventArgs e)
{
// Handle mouse button release
DispEngine.MouseButtonUp((long)e.ChangedButton);
(sender as UIElement)?.ReleaseMouseCapture();
}
/// <summary>
/// Handles the mouse up event
/// </summary>
private void RenderingCanvas_MouseUp(object sender, MouseButtonEventArgs e)
{
// Handle mouse button release
DispEngine.MouseButtonUp((long)e.ChangedButton);
(sender as UIElement)?.ReleaseMouseCapture();
}
/// <summary>
/// Handles the mouse down event
/// </summary>
private void RenderingCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
// Handle mouse button press
DispEngine.MouseButtonDown((long)e.ChangedButton);
DisplayerPane.Focus();
(sender as UIElement)?.CaptureMouse();
}
/// <summary>
/// Handles the mouse down event
/// </summary>
private void RenderingCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
// Handle mouse button press
DispEngine.MouseButtonDown((long)e.ChangedButton);
DisplayerPane.Focus();
(sender as UIElement)?.CaptureMouse();
}
/// <summary>
/// Handles the mouse move event
/// </summary>
private void RenderingCanvas_MouseMove(object sender, MouseEventArgs e)
{
// Update mouse position and handle drag transforms
Point p = e.GetPosition(DisplayerPane);
DispEngine.MouseMove((int)p.X, (int)p.Y);
DispEngine.MouseDragTransform((int)p.X, (int)p.Y,
new mouse_button_table__transform_view_by_mouse_drag_t()
{
LEFT_BUTTON = (long)MouseButton.Left,
RIGHT_BUTTON = (long)MouseButton.Right
});
}
#endregion
/// <summary>
/// Handles the mouse move event
/// </summary>
private void RenderingCanvas_MouseMove(object sender, MouseEventArgs e)
{
// Update mouse position and handle drag transforms
Point p = e.GetPosition(DisplayerPane);
DispEngine.MouseMove((int)p.X, (int)p.Y);
DispEngine.MouseDragTransform((int)p.X, (int)p.Y,
new mouse_button_table__transform_view_by_mouse_drag_t()
{
LEFT_BUTTON = (long)MouseButton.Left,
RIGHT_BUTTON = (long)MouseButton.Right
});
}
#endregion
#region Cleanup
/// <summary>
/// Flag to track disposed state
/// </summary>
private bool disposedValue;
#region Cleanup
/// <summary>
/// Flag to track disposed state
/// </summary>
private bool disposedValue;
/// <summary>
/// Disposes managed resources
/// </summary>
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// Unsubscribe from power events
SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
/// <summary>
/// Disposes managed resources
/// </summary>
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// Unsubscribe from power events
SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
// Dispose the DispEngine to free resources
DispEngine.Dispose();
}
disposedValue = true;
}
}
// Dispose the DispEngine to free resources
DispEngine.Dispose();
}
disposedValue = true;
}
}
/// <summary>
/// Public dispose method to free resources
/// </summary>
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
#endregion
}
#endregion
/// <summary>
/// Public dispose method to free resources
/// </summary>
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
#endregion
}
#endregion

View File

@ -3,53 +3,52 @@ using System;
using System.Windows;
using System.Windows.Media;
namespace Hi.WpfPlus.Disp
{
/// <summary>
/// Window for 3D rendering.
/// </summary>
public class RenderingWindow : Window, IGetDispEngine
{
/// <summary>
/// Gets the rendering canvas control used for displaying 3D content.
/// </summary>
public RenderingCanvas RenderingCanvas => Content as RenderingCanvas;
namespace Hi.WpfPlus.Disp;
/// <summary>
/// Ctor.
/// </summary>
public RenderingWindow()
{
Title = nameof(RenderingWindow);
Height = 450;
Width = 800;
StateChanged += RenderingWind_StateChanged;
Content = new RenderingCanvas()
{
BorderThickness = new Thickness(1),
BorderBrush = Brushes.Black
};
}
private void RenderingWind_StateChanged(object sender, EventArgs e)
{
RenderingCanvas.DispEngine.IsVisible = WindowState != WindowState.Minimized;
}
/// <inheritdoc/>
public DispEngine GetDispEngine() => RenderingCanvas.DispEngine;
/// <summary>
/// Gets or sets the current displayable 3D object.
/// When setting a new displayee, the view will be reset to home position if no previous displayee was set.
/// </summary>
public IDisplayee Displayee
{
get => GetDispEngine().Displayee;
set
{
var preDisplayee = GetDispEngine().Displayee;
GetDispEngine().Displayee = value;
if (preDisplayee == null)
RenderingCanvas.DispEngine.SetViewToHomeView();
}
}
}
/// <summary>
/// Window for 3D rendering.
/// </summary>
public class RenderingWindow : Window, IGetDispEngine
{
/// <summary>
/// Gets the rendering canvas control used for displaying 3D content.
/// </summary>
public RenderingCanvas RenderingCanvas => Content as RenderingCanvas;
/// <summary>
/// Ctor.
/// </summary>
public RenderingWindow()
{
Title = nameof(RenderingWindow);
Height = 450;
Width = 800;
StateChanged += RenderingWind_StateChanged;
Content = new RenderingCanvas()
{
BorderThickness = new Thickness(1),
BorderBrush = Brushes.Black
};
}
private void RenderingWind_StateChanged(object sender, EventArgs e)
{
RenderingCanvas.DispEngine.IsVisible = WindowState != WindowState.Minimized;
}
/// <inheritdoc/>
public DispEngine GetDispEngine() => RenderingCanvas.DispEngine;
/// <summary>
/// Gets or sets the current displayable 3D object.
/// When setting a new displayee, the view will be reset to home position if no previous displayee was set.
/// </summary>
public IDisplayee Displayee
{
get => GetDispEngine().Displayee;
set
{
var preDisplayee = GetDispEngine().Displayee;
GetDispEngine().Displayee = value;
if (preDisplayee == null)
RenderingCanvas.DispEngine.SetViewToHomeView();
}
}
}

60
Disp/WpfDisp.cs Normal file
View File

@ -0,0 +1,60 @@
using Google.Protobuf.WellKnownTypes;
using Hi.Disp;
using Hi.Geom;
using System.Collections.Concurrent;
using System.Windows;
namespace Hi.WpfPlus.Disp;
/// <summary>
/// Registers WPF as the display framework for <see cref="DispFrameUtil"/>,
/// supporting multiple windows identified by key.
/// </summary>
/// <remarks>
/// <para>
/// Usage pattern: call <see cref="DispFrameUtil.Call"/> to queue display content,
/// then call <see cref="Run"/> to start the WPF application and show windows.
/// </para>
/// <para>
/// Each unique key creates a separate <see cref="RenderingWindow"/>.
/// Calling <see cref="DispFrameUtil.Call"/> with the same key updates the existing window.
/// </para>
/// <example>
/// <code>
/// // Queue display content (before or after Run)
/// DispFrameUtil.CallDispFrame("Window1", displayee1);
/// DispFrameUtil.CallDispFrame("Window2", displayee2);
/// // Start the WPF application (blocks until all windows are closed)
/// DispFrameWpf.Run();
/// </code>
/// </example>
/// </remarks>
public static class WpfDisp
{
static readonly ConcurrentDictionary<string, RenderingWindow> KeyToWindowDictionary = new();
static WpfDisp()
{
DispFrameUtil.UpdateByDispEngineConfigFunc = ApplyConfig;
}
public static void Init() { }
static void ApplyConfig(string key, DispEngineConfig config)
{
if (!KeyToWindowDictionary.TryGetValue(key, out var window))
{
window = new RenderingWindow() { Title = key };
window.Closed += (s, e) => KeyToWindowDictionary.TryRemove(key, out _);
KeyToWindowDictionary[key] = window;
window.Show();
}
var dispEngine = window.GetDispEngine();
if (config.Displayee != null)
dispEngine.Displayee = config.Displayee;
if (config.SketchView == null)
config.SketchView = config.Displayee?.GetBox3d()?.FrontView;
if (config.SketchView != null)
dispEngine.SketchView = config.SketchView;
}
}