using System; using System.Windows.Forms; using System.Drawing; using System.Drawing.Imaging; using Hi.Native; using Hi.Disp; using System.Collections.Generic; using Hi.Geom; using System.Linq; using System.Runtime.InteropServices; namespace Hi.WinForm.Disp { /// /// Window Form Displayer. /// public partial class RenderingCanvas : UserControl { #region Core_Properties /// /// . /// public DispEngine DispEngine { get; } // Constants and structures for WM_TOUCH private const int WM_TOUCH = 0x0240; private const int TOUCHEVENTF_MOVE = 0x0001; private const int TOUCHEVENTF_DOWN = 0x0002; private const int TOUCHEVENTF_UP = 0x0004; [StructLayout(LayoutKind.Sequential)] private struct TOUCHINPUT { public int x; public int y; public IntPtr hSource; public int dwID; public int dwFlags; public int dwMask; public int dwTime; public IntPtr dwExtraInfo; public int cxContact; public int cyContact; } [DllImport("user32.dll")] private static extern bool RegisterTouchWindow(IntPtr hWnd, uint ulFlags); [DllImport("user32.dll")] private static extern bool GetTouchInputInfo(IntPtr hTouchInput, int cInputs, [In, Out] TOUCHINPUT[] pInputs, int cbSize); [DllImport("user32.dll")] private static extern void CloseTouchInputHandle(IntPtr lParam); #endregion #region Initialization /// /// Ctor. /// /// displayees public unsafe RenderingCanvas(params IDisplayee[] displayees) { // Configure the control's visual styles SetStyle(ControlStyles.Selectable, true); SetStyle(ControlStyles.OptimizedDoubleBuffer, false); SetStyle(ControlStyles.ContainerControl, false); SetStyle(ControlStyles.ResizeRedraw, false); DoubleBuffered = true; InitializeComponent(); Dock = DockStyle.Fill; // Connect event handlers for user input and window events this.Resize += RenderingCanvas_Resize; this.VisibleChanged += RenderingCanvas_VisibleChanged; this.MouseMove += RenderingCanvas_MouseMove; this.MouseDown += RenderingCanvas_MouseDown; this.MouseUp += RenderingCanvas_MouseUp; this.MouseWheel += RenderingCanvas_MouseWheel; this.KeyDown += RenderingCanvas_KeyDown; this.KeyUp += RenderingCanvas_KeyUp; // Add focus event handler this.GotFocus += RenderingCanvas_GotFocus; this.HandleCreated += OnHandleCreated; // Enable touch input and click events for the control this.SetStyle(ControlStyles.StandardClick, true); this.SetStyle(ControlStyles.StandardDoubleClick, true); this.TabStop = true; // Initialize the DispEngine with provided displayees DispEngine = new DispEngine(displayees); DispEngine.BackgroundColor = new Vec3d(0.1, 0.1, 0.5); DispEngine.BackgroundOpacity = 0.1; DispEngine.SetViewToHomeView(); DispEngine.ImageRequestAfterBufferSwapped += DispEngine_ImageRequestAfterBufferSwapped; // Set initial size and start the rendering engine this.Size = new System.Drawing.Size(500, 300); DispEngine.Start(this.ClientSize.Width, this.ClientSize.Height); } #endregion #region Win32_Message_Handling protected override void WndProc(ref Message m) { if (m.Msg == WM_TOUCH) { HandleTouchInput(m.WParam, m.LParam); return; } base.WndProc(ref m); } private void OnHandleCreated(object sender, EventArgs e) { // Register window to receive touch messages RegisterTouchWindow(this.Handle, 0); } private void HandleTouchInput(IntPtr wParam, IntPtr lParam) { int inputCount = wParam.ToInt32(); TOUCHINPUT[] inputs = new TOUCHINPUT[inputCount]; if (!GetTouchInputInfo(lParam, inputCount, inputs, Marshal.SizeOf(typeof(TOUCHINPUT)))) return; try { for (int i = 0; i < inputCount; i++) { TOUCHINPUT ti = inputs[i]; int touchId = ti.dwID; // Convert touch coordinates to client coordinates Point touchPoint = PointToClient(new Point(ti.x / 100, ti.y / 100)); if ((ti.dwFlags & TOUCHEVENTF_DOWN) != 0) { // Touch down event DispEngine.TouchDown(touchId, touchPoint.X, touchPoint.Y); this.Focus(); } else if ((ti.dwFlags & TOUCHEVENTF_MOVE) != 0) { // Touch move event DispEngine.TouchMove(touchId, touchPoint.X, touchPoint.Y); } else if ((ti.dwFlags & TOUCHEVENTF_UP) != 0) { // Touch up event DispEngine.TouchUp(touchId); } } } finally { CloseTouchInputHandle(lParam); } } #endregion #region Cleanup /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { // Dispose the DispEngine to free resources DispEngine.Dispose(); components.Dispose(); } base.Dispose(disposing); } #endregion #region DispEngine_Rendering private unsafe void DispEngine_ImageRequestAfterBufferSwapped(byte* bgra_unsignedbyte_pixels, int w, int h) { // Create a bitmap from the raw pixel data provided by DispEngine Bitmap bitmap; bitmap = new Bitmap(new Bitmap(w, h, w * 4, PixelFormat.Format32bppArgb, new IntPtr(bgra_unsignedbyte_pixels))); // Update the background image and dispose the previous one Image pre = this.BackgroundImage; this.BackgroundImage = bitmap; pre?.Dispose(); } #endregion #region Window_Events private void RenderingCanvas_Resize(object sender, EventArgs e) { // Notify DispEngine of size changes DispEngine.Resize(this.ClientSize.Width, this.ClientSize.Height); } private void RenderingCanvas_VisibleChanged(object sender, EventArgs e) { // Update visibility state in DispEngine DispEngine.IsVisible = this.Visible; } #endregion #region Mouse_Events private void RenderingCanvas_MouseMove(object sender, MouseEventArgs e) { // Update mouse position and handle drag transforms DispEngine.MouseMove(e.Location.X, e.Location.Y); DispEngine.MouseDragTransform(e.Location.X, e.Location.Y, new mouse_button_table__transform_view_by_mouse_drag_t() { LEFT_BUTTON = (long)MouseButtons.Left, RIGHT_BUTTON = (long)MouseButtons.Right }); } private void RenderingCanvas_MouseDown(object sender, MouseEventArgs e) { // Handle mouse button press DispEngine.MouseButtonDown((long)e.Button); this.Focus(); } private void RenderingCanvas_MouseUp(object sender, MouseEventArgs e) { // Handle mouse button release DispEngine.MouseButtonUp((long)e.Button); } private void RenderingCanvas_MouseWheel(object sender, MouseEventArgs e) { // Handle mouse wheel for zoom operations DispEngine.MouseWheel(0, e.Delta / 120); DispEngine.MouseWheelTransform(0, e.Delta / 120); } #endregion #region Keyboard_Events /// protected override bool IsInputKey(Keys keyData) { //since in default, arrow does not trigger key event(keyDown and keyUp). return true; } private void RenderingCanvas_KeyDown(object sender, KeyEventArgs e) { Focus(); DispEngine.KeyDown((long)e.KeyData); // Map specific keys for view transformation long key = (long)e.KeyData; if (key == (long)Keys.LShiftKey || key == (long)Keys.RShiftKey || key == (long)Keys.ShiftKey) key = (long)Keys.Shift; DispEngine.KeyDownTransform(key, new key_table__transform_view_by_key_pressing_t() { HOME = (long)Keys.Home, PAGE_UP = (long)Keys.PageUp, PAGE_DOWN = (long)Keys.PageDown, F1 = (long)Keys.F1, F2 = (long)Keys.F2, F3 = (long)Keys.F3, F4 = (long)Keys.F4, SHIFT = (long)Keys.Shift, ARROW_LEFT = (long)Keys.Left, ARROW_RIGHT = (long)Keys.Right, ARROW_DOWN = (long)Keys.Down, ARROW_UP = (long)Keys.Up }); } private void RenderingCanvas_KeyUp(object sender, KeyEventArgs e) { DispEngine.KeyUp((long)e.KeyData); } #endregion #region Touch_Events private void RenderingCanvas_GotFocus(object sender, EventArgs e) { // Ensure touch input is enabled when control gets focus this.Capture = true; } #endregion } }