diff --git a/Disp/RenderingCanvas.cs b/Disp/RenderingCanvas.cs
index dfa27ec..48248d3 100644
--- a/Disp/RenderingCanvas.cs
+++ b/Disp/RenderingCanvas.cs
@@ -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
+///
+/// Provides a WPF rendering canvas for 3D visualization of HiAPI components.
+/// Handles user interactions, rendering, and integration with the DispEngine system.
+///
+///
+/// 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.
+///
+public class RenderingCanvas : UserControl, IDisposable
{
- #region WPF Rendering Canvas
- ///
- /// Provides a WPF rendering canvas for 3D visualization of HiAPI components.
- /// Handles user interactions, rendering, and integration with the DispEngine system.
- ///
- ///
- /// 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.
- ///
- public class RenderingCanvas : UserControl, IDisposable
- {
- #region Core_Properties
- ///
- /// The DispEngine instance that handles rendering and user interactions
- ///
- public DispEngine DispEngine { get; } = new DispEngine();
-
- ///
- /// Internal container for rendering content
- ///
- private UserControl DisplayerPane { get; }
-
- ///
- /// Dictionary to store touch point information
- ///
- private Dictionary TouchingPointsMap { get; } = new Dictionary();
-
- ///
- /// Dictionary to store previous positions of touch points
- ///
- private Dictionary PreviousTouchingPointsMap { get; } = new Dictionary();
- #endregion
-
- #region Power_Management
- ///
- /// Handles system power mode changes
- ///
- private void InitializePowerManagement()
- {
- SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
- }
+ #region Core_Properties
+ ///
+ /// The DispEngine instance that handles rendering and user interactions
+ ///
+ public DispEngine DispEngine { get; } = new DispEngine();
- ///
- /// Handles power mode change events
- ///
- 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
- ///
- /// Initializes a new instance of the RenderingCanvas
- ///
- public RenderingCanvas()
- {
- DispEngine.BackgroundColor = new Vec3d(0.1, 0.1, 0.5);
- DispEngine.BackgroundOpacity = 0.1;
+ ///
+ /// Internal container for rendering content
+ ///
+ private UserControl DisplayerPane { get; }
- // Configure the main control properties
- HorizontalAlignment = HorizontalAlignment.Stretch;
- VerticalAlignment = VerticalAlignment.Stretch;
- Focusable = true;
- KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Cycle);
- DataContextChanged += CanvasDataContextChanged;
+ ///
+ /// Dictionary to store touch point information
+ ///
+ private Dictionary TouchingPointsMap { get; } = new Dictionary();
- // Create and configure the display pane
- DisplayerPane = new UserControl();
- DisplayerPane.HorizontalAlignment = HorizontalAlignment.Stretch;
- DisplayerPane.VerticalAlignment = VerticalAlignment.Stretch;
- DisplayerPane.Focusable = true;
- DisplayerPane.IsTabStop = true;
+ ///
+ /// Dictionary to store previous positions of touch points
+ ///
+ private Dictionary PreviousTouchingPointsMap { get; } = new Dictionary();
+ #endregion
- // 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;
+ #region Power_Management
+ ///
+ /// Handles system power mode changes
+ ///
+ private void InitializePowerManagement()
+ {
+ SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
+ }
- // Add touch event handlers
- DisplayerPane.TouchDown += RenderingCanvas_TouchDown;
- DisplayerPane.TouchMove += RenderingCanvas_TouchMove;
- DisplayerPane.TouchUp += RenderingCanvas_TouchUp;
-
- // Enable touch support
- this.IsManipulationEnabled = true;
+ ///
+ /// Handles power mode change events
+ ///
+ 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
- // Initialize power management
- InitializePowerManagement();
+ #region Initialization
+ ///
+ /// Initializes a new instance of the RenderingCanvas
+ ///
+ public RenderingCanvas()
+ {
+ DispEngine.BackgroundColor = new Vec3d(0.1, 0.1, 0.5);
+ DispEngine.BackgroundOpacity = 0.1;
- // Add the display pane to this control's content
- Content = DisplayerPane;
- }
- #endregion
-
- #region Touch_Events
- ///
- /// Handles the touch down event
- ///
- 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);
+ // Configure the main control properties
+ HorizontalAlignment = HorizontalAlignment.Stretch;
+ VerticalAlignment = VerticalAlignment.Stretch;
+ Focusable = true;
+ KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Cycle);
+ DataContextChanged += CanvasDataContextChanged;
- // Ensure control gets focus
- DisplayerPane.Focus();
- e.TouchDevice.Capture(DisplayerPane);
-
- e.Handled = true;
- }
-
- ///
- /// Handles the touch move event
- ///
- 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;
- }
-
- ///
- /// Handles the touch up event
- ///
- private void RenderingCanvas_TouchUp(object sender, TouchEventArgs e)
- {
- DispEngine.TouchUp(e.TouchDevice.Id);
- e.Handled = true;
- }
- #endregion
-
- #region Window_Events
- ///
- /// Handles window state changes (maximize, minimize, etc.)
- ///
- 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;
- }
- }
+ // Create and configure the display pane
+ DisplayerPane = new UserControl();
+ DisplayerPane.HorizontalAlignment = HorizontalAlignment.Stretch;
+ DisplayerPane.VerticalAlignment = VerticalAlignment.Stretch;
+ DisplayerPane.Focusable = true;
+ DisplayerPane.IsTabStop = true;
- ///
- /// Handles data context changes
- ///
- private unsafe void CanvasDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
- {
- DispEngine pre = e.OldValue as DispEngine;
- DispEngine cur = e.NewValue as DispEngine;
+ // 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;
- //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);
+ // Add touch event handlers
+ DisplayerPane.TouchDown += RenderingCanvas_TouchDown;
+ DisplayerPane.TouchMove += RenderingCanvas_TouchMove;
+ DisplayerPane.TouchUp += RenderingCanvas_TouchUp;
- cur.IsVisible = IsVisible;
- }
- }
-
- ///
- /// Reference to the current window containing this control
- ///
- private Window currentWindow;
-
- ///
- /// Gets or sets the current window, connecting or disconnecting state change events
- ///
- Window CurrentWindow
- {
- get => currentWindow; set
- {
- if (currentWindow != null)
- currentWindow.StateChanged -= RenderingCanvas_StateChanged;
- currentWindow = value;
- if (currentWindow != null)
- currentWindow.StateChanged += RenderingCanvas_StateChanged;
- }
- }
-
- ///
- /// Handles the loaded event
- ///
- 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;
- }
-
- ///
- /// Handles the unloaded event
- ///
- private unsafe void RenderingCanvas_Unloaded(object sender, RoutedEventArgs e)
- {
- DispEngine.IsVisible = IsVisible;
- DispEngine.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
- CurrentWindow = null;
- }
- #endregion
+ // Enable touch support
+ this.IsManipulationEnabled = true;
- #region DispEngine_Rendering
- ///
- /// Handles the buffer swapped event from DispEngine
- ///
- private unsafe void RenderingCanvas_BufferSwapped(byte* data, int w, int h)
- {
- if (data == null)
- return;
+ // Initialize power management
+ InitializePowerManagement();
- Span bgra = new Span(data, w * h * 4);
+ // Add the display pane to this control's content
+ Content = DisplayerPane;
+ }
+ #endregion
- // 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);
- });
- }
-
- ///
- /// Handles the size changed event
- ///
- private void RenderingCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
- {
- // Notify DispEngine of size changes
- DispEngine.Resize((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
- }
-
- ///
- /// Handles visibility changes
- ///
- private unsafe void DisplayerPane_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
- {
- // Update visibility state in DispEngine
- DispEngine.IsVisible = IsVisible;
- }
- #endregion
-
- #region Keyboard_Events
- ///
- /// Convert WPF Key to W3C KeyboardEvent.key string.
- ///
- 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 Touch_Events
+ ///
+ /// Handles the touch down event
+ ///
+ 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);
- ///
- /// Handles the key up event
- ///
- private void RenderingCanvas_KeyUp(object sender, KeyEventArgs e)
- {
- DispEngine.KeyUp(WpfKeyToW3C(e.Key));
- }
-
- ///
- /// Handles the key down event
- ///
- private void RenderingCanvas_KeyDown(object sender, KeyEventArgs e)
- {
- string key = WpfKeyToW3C(e.Key);
- DispEngine.KeyDown(key);
+ // Ensure control gets focus
+ DisplayerPane.Focus();
+ e.TouchDevice.Capture(DisplayerPane);
- 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
- ///
- /// Helper method to get mouse button mask
- ///
- 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;
- }
+ e.Handled = true;
+ }
- ///
- /// Handles the mouse wheel event
- ///
- 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);
- }
-
- ///
- /// Handles the mouse up event
- ///
- private void RenderingCanvas_MouseUp(object sender, MouseButtonEventArgs e)
- {
- // Handle mouse button release
- DispEngine.MouseButtonUp((long)e.ChangedButton);
- (sender as UIElement)?.ReleaseMouseCapture();
- }
-
- ///
- /// Handles the mouse down event
- ///
- private void RenderingCanvas_MouseDown(object sender, MouseButtonEventArgs e)
- {
- // Handle mouse button press
- DispEngine.MouseButtonDown((long)e.ChangedButton);
- DisplayerPane.Focus();
- (sender as UIElement)?.CaptureMouse();
- }
-
- ///
- /// Handles the mouse move event
- ///
- 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
- ///
- /// Flag to track disposed state
- ///
- private bool disposedValue;
-
- ///
- /// Disposes managed resources
- ///
- 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;
- }
- }
-
- ///
- /// Public dispose method to free resources
- ///
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
- Dispose(disposing: true);
- GC.SuppressFinalize(this);
- }
- #endregion
- }
- #endregion
+ ///
+ /// Handles the touch move event
+ ///
+ 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;
+ }
+
+ ///
+ /// Handles the touch up event
+ ///
+ private void RenderingCanvas_TouchUp(object sender, TouchEventArgs e)
+ {
+ DispEngine.TouchUp(e.TouchDevice.Id);
+ e.Handled = true;
+ }
+ #endregion
+
+ #region Window_Events
+ ///
+ /// Handles window state changes (maximize, minimize, etc.)
+ ///
+ 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;
+ }
+ }
+
+ ///
+ /// Handles data context changes
+ ///
+ 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);
+
+ cur.IsVisible = IsVisible;
+ }
+ }
+
+ ///
+ /// Reference to the current window containing this control
+ ///
+ private Window currentWindow;
+
+ ///
+ /// Gets or sets the current window, connecting or disconnecting state change events
+ ///
+ Window CurrentWindow
+ {
+ get => currentWindow; set
+ {
+ if (currentWindow != null)
+ currentWindow.StateChanged -= RenderingCanvas_StateChanged;
+ currentWindow = value;
+ if (currentWindow != null)
+ currentWindow.StateChanged += RenderingCanvas_StateChanged;
+ }
+ }
+
+ ///
+ /// Handles the loaded event
+ ///
+ 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;
+ }
+
+ ///
+ /// Handles the unloaded event
+ ///
+ private unsafe void RenderingCanvas_Unloaded(object sender, RoutedEventArgs e)
+ {
+ DispEngine.IsVisible = IsVisible;
+ DispEngine.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
+ CurrentWindow = null;
+ }
+ #endregion
+
+ #region DispEngine_Rendering
+ ///
+ /// Handles the buffer swapped event from DispEngine
+ ///
+ private unsafe void RenderingCanvas_BufferSwapped(byte* data, int w, int h)
+ {
+ if (data == null)
+ return;
+
+ Span bgra = new Span(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];
+
+ // 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);
+ });
+ }
+
+ ///
+ /// Handles the size changed event
+ ///
+ private void RenderingCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ // Notify DispEngine of size changes
+ DispEngine.Resize((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
+ }
+
+ ///
+ /// Handles visibility changes
+ ///
+ private unsafe void DisplayerPane_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
+ {
+ // Update visibility state in DispEngine
+ DispEngine.IsVisible = IsVisible;
+ }
+ #endregion
+
+ #region Keyboard_Events
+ ///
+ /// Convert WPF Key to W3C KeyboardEvent.key string.
+ ///
+ 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"
+ };
+
+ ///
+ /// Handles the key up event
+ ///
+ private void RenderingCanvas_KeyUp(object sender, KeyEventArgs e)
+ {
+ DispEngine.KeyUp(WpfKeyToW3C(e.Key));
+ }
+
+ ///
+ /// Handles the key down event
+ ///
+ 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
+
+ #region Mouse_Events
+ ///
+ /// Helper method to get mouse button mask
+ ///
+ 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;
+ }
+
+ ///
+ /// Handles the mouse wheel event
+ ///
+ 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);
+ }
+
+ ///
+ /// Handles the mouse up event
+ ///
+ private void RenderingCanvas_MouseUp(object sender, MouseButtonEventArgs e)
+ {
+ // Handle mouse button release
+ DispEngine.MouseButtonUp((long)e.ChangedButton);
+ (sender as UIElement)?.ReleaseMouseCapture();
+ }
+
+ ///
+ /// Handles the mouse down event
+ ///
+ private void RenderingCanvas_MouseDown(object sender, MouseButtonEventArgs e)
+ {
+ // Handle mouse button press
+ DispEngine.MouseButtonDown((long)e.ChangedButton);
+ DisplayerPane.Focus();
+ (sender as UIElement)?.CaptureMouse();
+ }
+
+ ///
+ /// Handles the mouse move event
+ ///
+ 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
+ ///
+ /// Flag to track disposed state
+ ///
+ private bool disposedValue;
+
+ ///
+ /// Disposes managed resources
+ ///
+ 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;
+ }
+ }
+
+ ///
+ /// Public dispose method to free resources
+ ///
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+ #endregion
}
+#endregion
diff --git a/Disp/RenderingWindow.cs b/Disp/RenderingWindow.cs
index b13fc6b..0e3d7c9 100644
--- a/Disp/RenderingWindow.cs
+++ b/Disp/RenderingWindow.cs
@@ -3,53 +3,52 @@ using System;
using System.Windows;
using System.Windows.Media;
-namespace Hi.WpfPlus.Disp
-{
- ///
- /// Window for 3D rendering.
- ///
- public class RenderingWindow : Window, IGetDispEngine
- {
- ///
- /// Gets the rendering canvas control used for displaying 3D content.
- ///
- public RenderingCanvas RenderingCanvas => Content as RenderingCanvas;
+namespace Hi.WpfPlus.Disp;
- ///
- /// Ctor.
- ///
- 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;
- }
- ///
- public DispEngine GetDispEngine() => RenderingCanvas.DispEngine;
- ///
- /// 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.
- ///
- public IDisplayee Displayee
- {
- get => GetDispEngine().Displayee;
- set
- {
- var preDisplayee = GetDispEngine().Displayee;
- GetDispEngine().Displayee = value;
- if (preDisplayee == null)
- RenderingCanvas.DispEngine.SetViewToHomeView();
- }
- }
- }
+///
+/// Window for 3D rendering.
+///
+public class RenderingWindow : Window, IGetDispEngine
+{
+ ///
+ /// Gets the rendering canvas control used for displaying 3D content.
+ ///
+ public RenderingCanvas RenderingCanvas => Content as RenderingCanvas;
+
+ ///
+ /// Ctor.
+ ///
+ 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;
+ }
+ ///
+ public DispEngine GetDispEngine() => RenderingCanvas.DispEngine;
+ ///
+ /// 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.
+ ///
+ public IDisplayee Displayee
+ {
+ get => GetDispEngine().Displayee;
+ set
+ {
+ var preDisplayee = GetDispEngine().Displayee;
+ GetDispEngine().Displayee = value;
+ if (preDisplayee == null)
+ RenderingCanvas.DispEngine.SetViewToHomeView();
+ }
+ }
}
diff --git a/Disp/WpfDisp.cs b/Disp/WpfDisp.cs
new file mode 100644
index 0000000..6a82085
--- /dev/null
+++ b/Disp/WpfDisp.cs
@@ -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;
+
+///
+/// Registers WPF as the display framework for ,
+/// supporting multiple windows identified by key.
+///
+///
+///
+/// Usage pattern: call to queue display content,
+/// then call to start the WPF application and show windows.
+///
+///
+/// Each unique key creates a separate .
+/// Calling with the same key updates the existing window.
+///
+///
+///
+/// // 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();
+///
+///
+///
+public static class WpfDisp
+{
+ static readonly ConcurrentDictionary 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;
+ }
+}