/// <summary> /// Sets the cursor depending on whether the mouse cursor is on border. /// </summary> /// <param name="val">The hit test result.</param> private void SetCursorOnBorder(PInvoke.HitTestValues val) { switch (val) { case PInvoke.HitTestValues.HTTOP: case PInvoke.HitTestValues.HTBOTTOM: Cursor.Current = Cursors.SizeNS; break; case PInvoke.HitTestValues.HTTOPRIGHT: case PInvoke.HitTestValues.HTBOTTOMLEFT: Cursor.Current = Cursors.SizeNESW; break; case PInvoke.HitTestValues.HTLEFT: case PInvoke.HitTestValues.HTRIGHT: Cursor.Current = Cursors.SizeWE; break; case PInvoke.HitTestValues.HTBOTTOMRIGHT: case PInvoke.HitTestValues.HTTOPLEFT: Cursor.Current = Cursors.SizeNWSE; break; default: Cursor.Current = this.Cursor; break; } }
/// <summary> /// Handles the MouseDown event of the PanelContent control. /// Specifically, this handles the resizing of the form. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param> private void PanelContent_MouseDown(object sender, MouseEventArgs e) { // If the resizing is disabled, don't bother to check. if (!this.Resizable) { return; } // Only handle left button click. if (e.Button != System.Windows.Forms.MouseButtons.Left) { return; } // Disable when maximized if (this.WindowState == FormWindowState.Maximized) { return; } // Determine if the border is clicked. Point p = this.PointToClient(this.panelContent.PointToScreen(e.Location)); PInvoke.HitTestValues val = this.BorderHitTest(p); if (val != PInvoke.HitTestValues.HTNOWHERE) { PInvoke.ReleaseCapture(); PInvoke.SendMessage(this.Handle, (int)PInvoke.WindowsMessages.WM_NCLBUTTONDOWN, (IntPtr)val, IntPtr.Zero); } }
/// <summary> /// Handles the MouseMove event of the PanelContent control. /// Used for changing the cursor dynamically. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param> private void PanelContent_MouseMove(object sender, MouseEventArgs e) { // If the resizing is disabled, don't bother to check. if (this.Resizable && this.WindowState != FormWindowState.Maximized && !this.DraggingTitleBar) { Point p = this.PointToClient(this.panelContent.PointToScreen(e.Location)); PInvoke.HitTestValues val = this.BorderHitTest(p); this.SetCursorOnBorder(val); } }
/// <summary> /// Handles the MouseDown event of the control buttons on the right hand side of the title bar. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param> private void ControlButton_MouseDown(object sender, MouseEventArgs e) { if (e.Button == System.Windows.Forms.MouseButtons.Left && this.Resizable && this.WindowState != FormWindowState.Maximized) { // Determine if the border is clicked. Point p = this.PointToClient(((Control)sender).PointToScreen(e.Location)); PInvoke.HitTestValues val = this.BorderHitTest(p); if (val != PInvoke.HitTestValues.HTNOWHERE) { PInvoke.ReleaseCapture(); PInvoke.SendMessage(this.Handle, (int)PInvoke.WindowsMessages.WM_NCLBUTTONDOWN, (IntPtr)val, IntPtr.Zero); } } }
/// <summary> /// Overrides the message loop. /// </summary> /// <param name="m">The Windows <see cref="T:System.Windows.Forms.Message" /> to process.</param> protected override void WndProc(ref Message m) { switch ((PInvoke.WindowsMessages)m.Msg) { case PInvoke.WindowsMessages.WM_SETCURSOR: PInvoke.HitTestValues val = this.BorderHitTest(this.PointToClient(Cursor.Position)); this.SetCursorOnBorder(val); m.Result = (IntPtr)1; break; default: base.WndProc(ref m); break; } }
/// <summary> /// Handles the MouseDown event of the panel title bar control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param> private void PanelTitlebar_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { // Determine if the resizing border is clicked. if (this.Resizable && this.WindowState != FormWindowState.Maximized) { Point p = this.PointToClient(this.panelTitlebar.PointToScreen(e.Location)); PInvoke.HitTestValues val = this.BorderHitTest(p); if (val != PInvoke.HitTestValues.HTNOWHERE) { PInvoke.ReleaseCapture(); PInvoke.SendMessage(this.Handle, (int)PInvoke.WindowsMessages.WM_NCLBUTTONDOWN, (IntPtr)val, IntPtr.Zero); return; } } this.DraggingTitleBar = true; if (this.WindowState == FormWindowState.Maximized) { Point offset = new Point(); if (this.RestoreBounds.Width >= this.Width || e.X < this.RestoreBounds.Width / 2) { offset = e.Location; } else if (e.X >= this.Width - (this.RestoreBounds.Width / 2)) { offset = new Point(e.Location.X - (this.Width - this.RestoreBounds.Width), e.Location.Y); } else { offset = new Point(this.RestoreBounds.Width / 2, e.Location.Y); } this.draggingOffset = offset; } else { this.draggingOffset = e.Location; } } else if (e.Button == MouseButtons.Right) { this.PopupSystemMenu(this.panelTitlebar.PointToScreen(e.Location)); } }
/// <summary> /// Handles the MouseMove event of the panel title bar control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="MouseEventArgs"/> instance containing the event data.</param> private void PanelTitlebar_MouseMove(object sender, MouseEventArgs e) { // If the resizing is disabled, don't bother to check. if (this.Resizable && this.WindowState != FormWindowState.Maximized && !this.DraggingTitleBar) { Point p = this.PointToClient(this.panelTitlebar.PointToScreen(e.Location)); PInvoke.HitTestValues val = this.BorderHitTest(p); this.SetCursorOnBorder(val); } // Title Bar Dragging. if (this.DraggingTitleBar) { // Make it normal state before moving. if (this.WindowState == FormWindowState.Maximized) { this.ToggleMaximize(); } Point curScreenPos = this.PointToScreen(e.Location); this.Location = new Point(curScreenPos.X - this.draggingOffset.X, curScreenPos.Y - this.draggingOffset.Y); } }
/// <summary> /// Hit test against the border (padding) area. /// </summary> /// <param name="p">The position of the mouse cursor relative to the form.</param> /// <returns> /// The border position value in the HitTestValues enumeration. HTNOWHERE if not in any of the border area. /// </returns> private PInvoke.HitTestValues BorderHitTest(Point p) { PInvoke.HitTestValues val = PInvoke.HitTestValues.HTNOWHERE; Padding pad = this.panelContent.Padding; Size size = this.ClientSize; // Outside the form. if (p.X < 0 || p.X >= size.Width || p.Y < 0 || p.Y >= size.Height) { return(val); } // Within the titlebar area if (0 <= p.Y && p.Y < this.panelTitlebar.Height) { if (pad.Left <= p.X && p.X < (size.Width - this.ResizingBorderWidth) && this.ResizingBorderWidth <= p.Y) { return(val); } pad.Top = Math.Max(this.ResizingBorderWidth, this.CornerSize); pad.Right = Math.Max(this.ResizingBorderWidth, this.CornerSize); pad.Bottom = Math.Max(pad.Bottom, this.CornerSize); pad.Left = Math.Max(pad.Left, this.CornerSize); } else { if (pad.Left <= p.X && p.X < (size.Width - pad.Right) && p.Y < (size.Height - pad.Bottom)) { return(val); } pad.Top = Math.Max(this.ResizingBorderWidth, this.CornerSize); pad.Right = Math.Max(pad.Right, this.CornerSize); pad.Bottom = Math.Max(pad.Bottom, this.CornerSize); pad.Left = Math.Max(pad.Left, this.CornerSize); } bool top = 0 <= p.Y && p.Y < pad.Top; bool right = (size.Width - pad.Right) <= p.X && p.X < size.Width; bool bottom = (size.Height - pad.Bottom) <= p.Y && p.Y < size.Height; bool left = 0 <= p.X && p.X < pad.Left; if (top) { if (left) { val = PInvoke.HitTestValues.HTTOPLEFT; } else if (right) { val = PInvoke.HitTestValues.HTTOPRIGHT; } else { val = PInvoke.HitTestValues.HTTOP; } } else if (bottom) { if (left) { val = PInvoke.HitTestValues.HTBOTTOMLEFT; } else if (right) { val = PInvoke.HitTestValues.HTBOTTOMRIGHT; } else { val = PInvoke.HitTestValues.HTBOTTOM; } } else { if (left) { val = PInvoke.HitTestValues.HTLEFT; } else if (right) { val = PInvoke.HitTestValues.HTRIGHT; } } return(val); }