/// <remarks>my first idea was to return the correct hittest to let windows handle the click, but it shows the ugly default buttons</remarks> protected override WinApi.HitTest HitTestNca(IntPtr lparam) { var result = base.HitTestNca(lparam); if (result == WinApi.HitTest.HTCAPTION || result == WinApi.HitTest.HTTOP || result == WinApi.HitTest.HTTOPRIGHT) { var cursorLocation = PointToClient(new Point(lparam.ToInt32())); foreach (var yamuiFormButton in _windowButtonList.Values) { if (cursorLocation.X >= yamuiFormButton.ClientRectangle.Left && cursorLocation.X <= yamuiFormButton.ClientRectangle.Right) { yamuiFormButton.IsHovered = true; result = WinApi.HitTest.HTBORDER; // track mouse leaving (otherwise the WM_NCMOUSELEAVE message would not fire) if (!_trackLeave) { WinApi.TRACKMOUSEEVENT tme = new WinApi.TRACKMOUSEEVENT(); tme.cbSize = (uint)Marshal.SizeOf(tme); tme.dwFlags = (uint)(WinApi.TMEFlags.TME_LEAVE | WinApi.TMEFlags.TME_NONCLIENT); tme.hwndTrack = Handle; WinApi.TrackMouseEvent(tme); _trackLeave = true; } } else { yamuiFormButton.IsHovered = false; yamuiFormButton.IsPressed = false; } } } else if (result == WinApi.HitTest.HTCLIENT && Resizable) { var cursorLocation2 = PointToClient(new Point(lparam.ToInt32())); if (cursorLocation2.X >= _resizeRectangle.Left && cursorLocation2.Y >= _resizeRectangle.Top) { result = WinApi.HitTest.HTBOTTOMRIGHT; } } return(result); }
protected override void WndProc(ref Message m) { if (DesignMode) { base.WndProc(ref m); return; } switch ((Window.Msg)m.Msg) { case Window.Msg.WM_NCCALCSIZE: // Check WPARAM if (m.WParam != IntPtr.Zero) { // When TRUE, LPARAM Points to a NCCALCSIZE_PARAMS structure var nccsp = (WinApi.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(WinApi.NCCALCSIZE_PARAMS)); ApplyPreferedSize(_preferedSize, nccsp.rectProposed.Size); AdjustClientArea(ref nccsp.rectProposed); Marshal.StructureToPtr(nccsp, m.LParam, true); } else { // When FALSE, LPARAM Points to a RECT structure var clnRect = (WinApi.RECT)Marshal.PtrToStructure(m.LParam, typeof(WinApi.RECT)); ApplyPreferedSize(_preferedSize, clnRect.Size); AdjustClientArea(ref clnRect); Marshal.StructureToPtr(clnRect, m.LParam, true); } //Return Zero m.Result = IntPtr.Zero; break; case Window.Msg.WM_NCPAINT: PaintScrollBars(null); // we handled everything m.Result = IntPtr.Zero; break; case Window.Msg.WM_NCHITTEST: // we need to correctly handle this if we want the non client area events (WM_NC*) to fire properly! var point = PointToClient(new Point(m.LParam.ToInt32())); if (!ClientRectangle.Contains(point)) { m.Result = (IntPtr)WinApi.HitTest.HTBORDER; } else { base.WndProc(ref m); } break; case Window.Msg.WM_MOUSEWHEEL: if (HasScroll) { // delta negative when scrolling up var delta = (short)(m.WParam.ToInt64() >> 16); var mouseEvent1 = new MouseEventArgs(MouseButtons.None, 0, 0, 0, delta); if (HorizontalScroll.IsHovered) { HorizontalScroll.HandleScroll(null, mouseEvent1); } else { VerticalScroll.HandleScroll(null, mouseEvent1); } } else { // propagate the event base.WndProc(ref m); } break; case Window.Msg.WM_MOUSEMOVE: if (VerticalScroll.IsThumbPressed) { VerticalScroll.HandleMouseMove(null, null); } if (HorizontalScroll.IsThumbPressed) { HorizontalScroll.HandleMouseMove(null, null); } base.WndProc(ref m); break; case Window.Msg.WM_NCMOUSEMOVE: // track mouse leaving (otherwise the WM_NCMOUSELEAVE message would not fire) WinApi.TRACKMOUSEEVENT tme = new WinApi.TRACKMOUSEEVENT(); tme.cbSize = (uint)Marshal.SizeOf(tme); tme.dwFlags = (uint)(WinApi.TMEFlags.TME_LEAVE | WinApi.TMEFlags.TME_NONCLIENT); tme.hwndTrack = Handle; WinApi.TrackMouseEvent(tme); // PointToClient(new Point(m.LParam.ToInt32())); VerticalScroll.HandleMouseMove(null, null); HorizontalScroll.HandleMouseMove(null, null); base.WndProc(ref m); break; case Window.Msg.WM_NCLBUTTONDOWN: VerticalScroll.HandleMouseDown(null, null); HorizontalScroll.HandleMouseDown(null, null); Focus(); // here we forward to base button down because it has a internal focus mecanism that we want to exploit // if we don't do that, the mouse MOVE events are not fired outside the bounds of this control! m.Msg = (int)Window.Msg.WM_LBUTTONDOWN; base.WndProc(ref m); break; case Window.Msg.WM_NCLBUTTONUP: case Window.Msg.WM_LBUTTONUP: VerticalScroll.HandleMouseUp(null, null); HorizontalScroll.HandleMouseUp(null, null); // here we forward this message to base WM_LBUTTONUP to release the internal focus on this control m.Msg = (int)Window.Msg.WM_LBUTTONUP; base.WndProc(ref m); break; case Window.Msg.WM_NCMOUSELEAVE: VerticalScroll.HandleMouseLeave(null, null); HorizontalScroll.HandleMouseLeave(null, null); base.WndProc(ref m); break; default: base.WndProc(ref m); break; } }