/// <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);
        }
Esempio n. 2
0
        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;
            }
        }