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

View File

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