aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/Internal/InternalWindowManager.cs
diff options
context:
space:
mode:
authorMichael VanOverbeek <[email protected]>2016-07-25 12:57:52 -0400
committerGitHub <[email protected]>2016-07-25 12:57:52 -0400
commit46c1c31302f111a1f3ec23a70e6f3986a9aa2a27 (patch)
treef00af7ea3f6ad2641fb26fa1d310fd8b7179b39c /source/ShiftUI/Internal/InternalWindowManager.cs
parentaf48e774189596b8d7a058c564a7d6d75205ca03 (diff)
parent6fa16209519896de09949a27425dff00ebf2970a (diff)
downloadshiftos-c--46c1c31302f111a1f3ec23a70e6f3986a9aa2a27.tar.gz
shiftos-c--46c1c31302f111a1f3ec23a70e6f3986a9aa2a27.tar.bz2
shiftos-c--46c1c31302f111a1f3ec23a70e6f3986a9aa2a27.zip
Merge pull request #17 from MichaelTheShifter/shiftui_integration
Shiftui integration
Diffstat (limited to 'source/ShiftUI/Internal/InternalWindowManager.cs')
-rw-r--r--source/ShiftUI/Internal/InternalWindowManager.cs1211
1 files changed, 1211 insertions, 0 deletions
diff --git a/source/ShiftUI/Internal/InternalWindowManager.cs b/source/ShiftUI/Internal/InternalWindowManager.cs
new file mode 100644
index 0000000..95fae49
--- /dev/null
+++ b/source/ShiftUI/Internal/InternalWindowManager.cs
@@ -0,0 +1,1211 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Jackson Harper ([email protected])
+//
+//
+
+
+using System;
+using System.Drawing;
+using System.Runtime.InteropServices;
+
+
+namespace ShiftUI {
+
+ internal abstract class InternalWindowManager {
+ private TitleButtons title_buttons;
+ internal Form form;
+
+ // moving windows
+ internal Point start;
+ internal State state;
+ protected Point clicked_point;
+ private FormPos sizing_edge;
+ internal Rectangle virtual_position;
+
+ private Rectangle normal_bounds;
+ private Rectangle iconic_bounds;
+
+
+ public enum State {
+ Idle,
+ Moving,
+ Sizing,
+ }
+
+ [Flags]
+ public enum FormPos {
+ None,
+
+ TitleBar = 1,
+
+ Top = 2,
+ Left = 4,
+ Right = 8,
+ Bottom = 16,
+
+ TopLeft = Top | Left,
+ TopRight = Top | Right,
+
+ BottomLeft = Bottom | Left,
+ BottomRight = Bottom | Right,
+
+ AnyEdge = Top | Left | Right | Bottom,
+ }
+
+ public InternalWindowManager (Form form)
+ {
+ this.form = form;
+
+ form.SizeChanged += new EventHandler (FormSizeChangedHandler);
+
+ title_buttons = new TitleButtons (form);
+ ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
+ }
+
+ public Form Form {
+ get { return form; }
+ }
+
+ public int IconWidth {
+ get { return TitleBarHeight - 5; }
+ }
+
+ public TitleButtons TitleButtons {
+ get {
+ return title_buttons;
+ }
+ }
+ internal Rectangle NormalBounds {
+ get {
+ return normal_bounds;
+ }
+ set {
+ normal_bounds = value;
+ }
+ }
+ internal Size IconicSize {
+ get {
+ return SystemInformation.MinimizedWindowSize;
+ }
+ }
+
+ internal Rectangle IconicBounds {
+ get {
+ if (iconic_bounds == Rectangle.Empty)
+ return Rectangle.Empty;
+ Rectangle result = iconic_bounds;
+ result.Y = Form.Parent.ClientRectangle.Bottom - iconic_bounds.Y;
+ return result;
+ }
+ set {
+ iconic_bounds = value;
+ iconic_bounds.Y = Form.Parent.ClientRectangle.Bottom - iconic_bounds.Y;
+ }
+ }
+
+ internal virtual Rectangle MaximizedBounds {
+ get {
+ return Form.Parent.ClientRectangle;
+ }
+ }
+
+ public virtual void UpdateWindowState (FormWindowState old_window_state, FormWindowState new_window_state, bool force)
+ {
+ if (old_window_state == FormWindowState.Normal) {
+ NormalBounds = form.Bounds;
+ } else if (old_window_state == FormWindowState.Minimized) {
+ IconicBounds = form.Bounds;
+ }
+
+ switch (new_window_state) {
+ case FormWindowState.Minimized:
+ if (IconicBounds == Rectangle.Empty) {
+ Size size = IconicSize;
+ Point location = new Point (0, Form.Parent.ClientSize.Height - size.Height);
+ IconicBounds = new Rectangle (location, size);
+ }
+ form.Bounds = IconicBounds;
+ break;
+ case FormWindowState.Maximized:
+ form.Bounds = MaximizedBounds;
+ break;
+ case FormWindowState.Normal:
+ form.Bounds = NormalBounds;
+ break;
+ }
+
+ UpdateWindowDecorations (new_window_state);
+ form.ResetCursor ();
+ }
+
+ public virtual void UpdateWindowDecorations (FormWindowState window_state)
+ {
+ ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
+ if (form.IsHandleCreated)
+ XplatUI.RequestNCRecalc (form.Handle);
+ }
+
+ public virtual bool WndProc (ref Message m)
+ {
+#if debug
+ Console.WriteLine(DateTime.Now.ToLongTimeString () + " " + this.GetType () .Name + " (Handle={0},Text={1}) received message {2}", form.IsHandleCreated ? form.Handle : IntPtr.Zero, form.Text, m.ToString ());
+#endif
+
+ switch ((Msg)m.Msg) {
+
+
+ // The mouse handling messages are actually
+ // not WM_NC* messages except for the first button and NCMOVEs
+ // down because we capture on the form
+
+ case Msg.WM_MOUSEMOVE:
+ return HandleMouseMove (form, ref m);
+
+ case Msg.WM_LBUTTONUP:
+ HandleLButtonUp (ref m);
+ break;
+
+ case Msg.WM_RBUTTONDOWN:
+ return HandleRButtonDown (ref m);
+
+ case Msg.WM_LBUTTONDOWN:
+ return HandleLButtonDown (ref m);
+
+ case Msg.WM_LBUTTONDBLCLK:
+ return HandleLButtonDblClick (ref m);
+
+ case Msg.WM_PARENTNOTIFY:
+ if (Widget.LowOrder(m.WParam.ToInt32()) == (int) Msg.WM_LBUTTONDOWN)
+ Activate ();
+ break;
+
+ case Msg.WM_NCHITTEST:
+ return HandleNCHitTest (ref m);
+
+ // Return true from these guys, otherwise win32 will mess up z-order
+ case Msg.WM_NCLBUTTONUP:
+ HandleNCLButtonUp (ref m);
+ return true;
+
+ case Msg.WM_NCLBUTTONDOWN:
+ HandleNCLButtonDown (ref m);
+ return true;
+
+ case Msg.WM_NCMOUSEMOVE:
+ HandleNCMouseMove (ref m);
+ return true;
+
+ case Msg.WM_NCLBUTTONDBLCLK:
+ HandleNCLButtonDblClick (ref m);
+ break;
+
+ case Msg.WM_NCMOUSELEAVE:
+ HandleNCMouseLeave (ref m);
+ break;
+
+ case Msg.WM_MOUSELEAVE:
+ HandleMouseLeave (ref m);
+ break;
+
+ case Msg.WM_NCCALCSIZE:
+ return HandleNCCalcSize (ref m);
+
+ case Msg.WM_NCPAINT:
+ return HandleNCPaint (ref m);
+ }
+
+ return false;
+ }
+
+ protected virtual bool HandleNCPaint (ref Message m)
+ {
+ PaintEventArgs pe = XplatUI.PaintEventStart (ref m, form.Handle, false);
+
+ Rectangle clip;
+
+ if (form.ActiveMenu != null) {
+ Point pnt;
+
+ pnt = GetMenuOrigin ();
+
+ // The entire menu has to be in the clip rectangle because the
+ // control buttons are right-aligned and otherwise they would
+ // stay painted when the window gets resized.
+ clip = new Rectangle (pnt.X, pnt.Y, form.ClientSize.Width, 0);
+ clip = Rectangle.Union (clip, pe.ClipRectangle);
+ pe.SetClip (clip);
+ pe.Graphics.SetClip (clip);
+
+ form.ActiveMenu.Draw (pe, new Rectangle (pnt.X, pnt.Y, form.ClientSize.Width, 0));
+ }
+ if (HasBorders || IsMinimized && !(Form.IsMdiChild && IsMaximized)) {
+ // clip region is not correct on win32.
+ // use the entire form's area.
+ clip = new Rectangle (0, 0, form.Width, form.Height);
+ ThemeEngine.Current.DrawManagedWindowDecorations (pe.Graphics, clip, this);
+ }
+ XplatUI.PaintEventEnd (ref m, form.Handle, false);
+ return true;
+ }
+
+ protected virtual bool HandleNCCalcSize (ref Message m)
+ {
+ XplatUIWin32.NCCALCSIZE_PARAMS ncp;
+ XplatUIWin32.RECT rect;
+
+ if (m.WParam == (IntPtr)1) {
+ ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (m.LParam,
+ typeof (XplatUIWin32.NCCALCSIZE_PARAMS));
+
+ ncp.rgrc1 = NCCalcSize (ncp.rgrc1);
+
+ Marshal.StructureToPtr (ncp, m.LParam, true);
+ } else {
+ rect = (XplatUIWin32.RECT) Marshal.PtrToStructure (m.LParam, typeof (XplatUIWin32.RECT));
+
+ rect = NCCalcSize (rect);
+
+ Marshal.StructureToPtr (rect, m.LParam, true);
+ }
+
+ return true;
+ }
+
+ protected virtual XplatUIWin32.RECT NCCalcSize (XplatUIWin32.RECT proposed_window_rect)
+ {
+ int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
+
+ if (HasBorders) {
+ proposed_window_rect.top += TitleBarHeight + bw;
+ proposed_window_rect.bottom -= bw;
+ proposed_window_rect.left += bw;
+ proposed_window_rect.right -= bw;
+ }
+
+ if (XplatUI.RequiresPositiveClientAreaSize) {
+ // This is necessary for Linux, can't handle <= 0-sized
+ // client areas correctly.
+ if (proposed_window_rect.right <= proposed_window_rect.left) {
+ proposed_window_rect.right += proposed_window_rect.left - proposed_window_rect.right + 1;
+ }
+ if (proposed_window_rect.top >= proposed_window_rect.bottom) {
+ proposed_window_rect.bottom += proposed_window_rect.top - proposed_window_rect.bottom + 1;
+ }
+ }
+
+ return proposed_window_rect;
+ }
+
+ protected virtual bool HandleNCHitTest (ref Message m)
+ {
+
+ int x = Widget.LowOrder ((int)m.LParam.ToInt32 ());
+ int y = Widget.HighOrder ((int)m.LParam.ToInt32 ());
+
+ NCPointToClient (ref x, ref y);
+
+ FormPos pos = FormPosForCoords (x, y);
+
+ if (pos == FormPos.TitleBar) {
+ m.Result = new IntPtr ((int)HitTest.HTCAPTION);
+ return true;
+ }
+
+ if (!IsSizable)
+ return false;
+
+ switch (pos) {
+ case FormPos.Top:
+ m.Result = new IntPtr ((int)HitTest.HTTOP);
+ break;
+ case FormPos.Left:
+ m.Result = new IntPtr ((int)HitTest.HTLEFT);
+ break;
+ case FormPos.Right:
+ m.Result = new IntPtr ((int)HitTest.HTRIGHT);
+ break;
+ case FormPos.Bottom:
+ m.Result = new IntPtr ((int)HitTest.HTBOTTOM);
+ break;
+ case FormPos.TopLeft:
+ m.Result = new IntPtr ((int)HitTest.HTTOPLEFT);
+ break;
+ case FormPos.TopRight:
+ m.Result = new IntPtr ((int)HitTest.HTTOPRIGHT);
+ break;
+ case FormPos.BottomLeft:
+ m.Result = new IntPtr ((int)HitTest.HTBOTTOMLEFT);
+ break;
+ case FormPos.BottomRight:
+ m.Result = new IntPtr ((int)HitTest.HTBOTTOMRIGHT);
+ break;
+ default:
+ // We return false so that DefWndProc handles things
+ return false;
+ }
+ return true;
+ }
+
+ public virtual void UpdateBorderStyle (FormBorderStyle border_style)
+ {
+ if (form.IsHandleCreated) {
+ XplatUI.SetBorderStyle (form.Handle, border_style);
+ }
+
+ if (ShouldRemoveWindowManager (border_style)) {
+ form.RemoveWindowManager ();
+ return;
+ }
+
+ ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
+ }
+
+
+
+ public virtual void SetWindowState (FormWindowState old_state, FormWindowState window_state)
+ {
+ UpdateWindowState (old_state, window_state, false);
+ }
+
+ public virtual FormWindowState GetWindowState ()
+ {
+ return form.window_state;
+ }
+
+ public virtual void PointToClient (ref int x, ref int y)
+ {
+ // toolwindows stay in screencoords we just have to make sure
+ // they obey the working area
+ Rectangle working = SystemInformation.WorkingArea;
+
+ if (x > working.Right)
+ x = working.Right;
+ if (x < working.Left)
+ x = working.Left;
+
+ if (y < working.Top)
+ y = working.Top;
+ if (y > working.Bottom)
+ y = working.Bottom;
+ }
+
+ public virtual void PointToScreen (ref int x, ref int y)
+ {
+ XplatUI.ClientToScreen (form.Handle, ref x, ref y);
+ }
+
+ protected virtual bool ShouldRemoveWindowManager (FormBorderStyle style)
+ {
+ return style != FormBorderStyle.FixedToolWindow && style != FormBorderStyle.SizableToolWindow;
+ }
+
+ public bool IconRectangleContains (int x, int y)
+ {
+ if (!ShowIcon)
+ return false;
+
+ Rectangle icon = ThemeEngine.Current.ManagedWindowGetTitleBarIconArea (this);
+ return icon.Contains (x, y);
+ }
+
+ public bool ShowIcon {
+ get {
+ if (!Form.ShowIcon)
+ return false;
+ if (!HasBorders)
+ return false;
+ if (IsMinimized)
+ return true;
+ if (IsToolWindow || Form.FormBorderStyle == FormBorderStyle.FixedDialog)
+ return false;
+ return true;
+ }
+ }
+
+ protected virtual void Activate ()
+ {
+ form.Invalidate (true);
+ form.Update ();
+ }
+
+ public virtual bool IsActive {
+ get {
+ return true;
+ }
+ }
+
+
+ private void FormSizeChangedHandler (object sender, EventArgs e)
+ {
+ if (form.IsHandleCreated) {
+ ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
+ XplatUI.InvalidateNC (form.Handle);
+ }
+ }
+
+ protected virtual bool HandleRButtonDown (ref Message m)
+ {
+ Activate ();
+ return false;
+ }
+
+ protected virtual bool HandleLButtonDown (ref Message m)
+ {
+ Activate ();
+ return false;
+ }
+
+ protected virtual bool HandleLButtonDblClick(ref Message m)
+ {
+ return false;
+ }
+
+ protected virtual bool HandleNCMouseLeave (ref Message m)
+ {
+ int x = Widget.LowOrder ((int)m.LParam.ToInt32 ());
+ int y = Widget.HighOrder ((int)m.LParam.ToInt32 ());
+
+ NCPointToClient (ref x, ref y);
+ FormPos pos = FormPosForCoords (x, y);
+
+ if (pos != FormPos.TitleBar) {
+ HandleTitleBarLeave (x, y);
+ return true;
+ }
+
+ return true;
+ }
+
+ protected virtual bool HandleNCMouseMove (ref Message m)
+ {
+ int x = Widget.LowOrder((int)m.LParam.ToInt32( ));
+ int y = Widget.HighOrder((int)m.LParam.ToInt32( ));
+
+ NCPointToClient (ref x, ref y);
+ FormPos pos = FormPosForCoords (x, y);
+
+ if (pos == FormPos.TitleBar) {
+ HandleTitleBarMouseMove (x, y);
+ return true;
+ }
+
+ if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) {
+ MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y, 0);
+ form.ActiveMenu.OnMouseMove (form, mea);
+ }
+
+ return true;
+
+ }
+
+ protected virtual bool HandleNCLButtonDown (ref Message m)
+ {
+ Activate ();
+
+ start = Cursor.Position;
+ virtual_position = form.Bounds;
+
+ int x = Widget.LowOrder ((int) m.LParam.ToInt32 ());
+ int y = Widget.HighOrder ((int) m.LParam.ToInt32 ());
+
+ // Need to adjust because we are in NC land
+ NCPointToClient (ref x, ref y);
+ FormPos pos = FormPosForCoords (x, y);
+
+ if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) {
+ MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y - TitleBarHeight, 0);
+ form.ActiveMenu.OnMouseDown (form, mea);
+ }
+
+ if (pos == FormPos.TitleBar) {
+ HandleTitleBarDown (x, y);
+ return true;
+ }
+
+ if (IsSizable) {
+ if ((pos & FormPos.AnyEdge) == 0)
+ return false;
+
+ virtual_position = form.Bounds;
+ state = State.Sizing;
+ sizing_edge = pos;
+ form.Capture = true;
+ return true;
+ }
+
+ return false;
+ }
+
+ protected virtual void HandleNCLButtonDblClick (ref Message m)
+ {
+ int x = Widget.LowOrder ((int)m.LParam.ToInt32 ());
+ int y = Widget.HighOrder ((int)m.LParam.ToInt32 ());
+
+ // Need to adjust because we are in NC land
+ NCPointToClient (ref x, ref y);
+
+ FormPos pos = FormPosForCoords (x, y);
+ if (pos == FormPos.TitleBar || pos == FormPos.Top)
+ HandleTitleBarDoubleClick (x, y);
+
+ }
+
+ protected virtual void HandleTitleBarDoubleClick (int x, int y)
+ {
+
+ }
+
+ protected virtual void HandleTitleBarLeave (int x, int y)
+ {
+ title_buttons.MouseLeave (x, y);
+ }
+
+ protected virtual void HandleTitleBarMouseMove (int x, int y)
+ {
+ if (title_buttons.MouseMove (x, y))
+ XplatUI.InvalidateNC (form.Handle);
+ }
+
+ protected virtual void HandleTitleBarUp (int x, int y)
+ {
+ title_buttons.MouseUp (x, y);
+
+ return;
+ }
+
+ protected virtual void HandleTitleBarDown (int x, int y)
+ {
+ title_buttons.MouseDown (x, y);
+
+ if (!TitleButtons.AnyPushedTitleButtons && !IsMaximized) {
+ state = State.Moving;
+ clicked_point = new Point (x, y);
+ if (form.Parent != null) {
+ form.CaptureWithConfine (form.Parent);
+ } else {
+ form.Capture = true;
+ }
+ }
+
+ XplatUI.InvalidateNC (form.Handle);
+ }
+
+ private bool HandleMouseMove (Form form, ref Message m)
+ {
+ switch (state) {
+ case State.Moving:
+ HandleWindowMove (m);
+ return true;
+ case State.Sizing:
+ HandleSizing (m);
+ return true;
+ }
+
+ return false;
+ }
+
+ private void HandleMouseLeave (ref Message m)
+ {
+ form.ResetCursor ();
+ }
+
+ protected virtual void HandleWindowMove (Message m)
+ {
+ Point move = MouseMove (Cursor.Position);
+
+ UpdateVP (virtual_position.X + move.X, virtual_position.Y + move.Y,
+ virtual_position.Width, virtual_position.Height);
+ }
+
+ private void HandleSizing (Message m)
+ {
+ Rectangle pos = virtual_position;
+ int mw;
+ int mh;
+ if (IsToolWindow) {
+ int border_width = BorderWidth;
+ mw = 2 * (border_width + Theme.ManagedWindowSpacingAfterLastTitleButton) + ThemeEngine.Current.ManagedWindowButtonSize (this).Width;
+ mh = 2 * border_width + TitleBarHeight;
+ } else {
+ Size minimum_size = SystemInformation.MinWindowTrackSize;
+ mw = minimum_size.Width;
+ mh = minimum_size.Height;
+ }
+ int x = Cursor.Position.X;
+ int y = Cursor.Position.Y;
+
+ PointToClient (ref x, ref y);
+
+ if ((sizing_edge & FormPos.Top) != 0) {
+ if (pos.Bottom - y < mh)
+ y = pos.Bottom - mh;
+ pos.Height = pos.Bottom - y;
+ pos.Y = y;
+ } else if ((sizing_edge & FormPos.Bottom) != 0) {
+ int height = y - pos.Top;
+ if (height <= mh)
+ height = mh;
+ pos.Height = height;
+ }
+
+ if ((sizing_edge & FormPos.Left) != 0) {
+ if (pos.Right - x < mw)
+ x = pos.Right - mw;
+ pos.Width = pos.Right - x;
+ pos.X = x;
+ } else if ((sizing_edge & FormPos.Right) != 0) {
+ int width = x - form.Left;
+ if (width <= mw)
+ width = mw;
+ pos.Width = width;
+ }
+
+ UpdateVP (pos);
+ }
+
+ public bool IsMaximized {
+ get { return GetWindowState () == FormWindowState.Maximized; }
+ }
+
+ public bool IsMinimized {
+ get { return GetWindowState () == FormWindowState.Minimized; }
+ }
+
+ public bool IsSizable {
+ get {
+ switch (form.FormBorderStyle) {
+ case FormBorderStyle.Sizable:
+ case FormBorderStyle.SizableToolWindow:
+ return (form.window_state != FormWindowState.Minimized);
+ default:
+ return false;
+ }
+ }
+ }
+
+ public bool HasBorders {
+ get {
+ return form.FormBorderStyle != FormBorderStyle.None;
+ }
+ }
+
+ public bool IsToolWindow {
+ get {
+ if (form.FormBorderStyle == FormBorderStyle.SizableToolWindow ||
+ form.FormBorderStyle == FormBorderStyle.FixedToolWindow ||
+ form.GetCreateParams().IsSet (WindowExStyles.WS_EX_TOOLWINDOW))
+ return true;
+ return false;
+ }
+ }
+
+ public int TitleBarHeight {
+ get {
+ return ThemeEngine.Current.ManagedWindowTitleBarHeight (this);
+ }
+ }
+
+ public int BorderWidth {
+ get {
+ return ThemeEngine.Current.ManagedWindowBorderWidth (this);
+ }
+ }
+
+ public virtual int MenuHeight {
+ get {
+ return (form.Menu != null ? ThemeEngine.Current.MenuHeight : 0);
+ }
+ }
+
+ protected void UpdateVP (Rectangle r)
+ {
+ UpdateVP (r.X, r.Y, r.Width, r.Height);
+ }
+
+ protected void UpdateVP (Point loc, int w, int h)
+ {
+ UpdateVP (loc.X, loc.Y, w, h);
+ }
+
+ protected void UpdateVP (int x, int y, int w, int h)
+ {
+ virtual_position.X = x;
+ virtual_position.Y = y;
+ virtual_position.Width = w;
+ virtual_position.Height = h;
+
+ DrawVirtualPosition (virtual_position);
+ }
+
+ protected virtual void HandleLButtonUp (ref Message m)
+ {
+ if (state == State.Idle)
+ return;
+
+ ClearVirtualPosition ();
+
+ form.Capture = false;
+ if (state == State.Moving && form.Location != virtual_position.Location)
+ form.Location = virtual_position.Location;
+ else if (state == State.Sizing && form.Bounds != virtual_position)
+ form.Bounds = virtual_position;
+ state = State.Idle;
+
+ OnWindowFinishedMoving ();
+ }
+
+ private bool HandleNCLButtonUp (ref Message m)
+ {
+ if (form.Capture) {
+ ClearVirtualPosition ();
+
+ form.Capture = false;
+ state = State.Idle;
+ if (form.MdiContainer != null)
+ form.MdiContainer.SizeScrollBars();
+ }
+
+ int x = Widget.LowOrder ((int) m.LParam.ToInt32 ());
+ int y = Widget.HighOrder ((int) m.LParam.ToInt32 ());
+
+ NCPointToClient (ref x, ref y);
+ FormPos pos = FormPosForCoords (x, y);
+
+ if (pos == FormPos.TitleBar) {
+ HandleTitleBarUp (x, y);
+ return true;
+ }
+
+ return true;
+ }
+
+ protected void DrawTitleButton (Graphics dc, TitleButton button, Rectangle clip)
+ {
+ if (!button.Rectangle.IntersectsWith (clip))
+ return;
+
+ ThemeEngine.Current.ManagedWindowDrawMenuButton (dc, button, clip, this);
+ }
+
+ public virtual void DrawMaximizedButtons (object sender, PaintEventArgs pe)
+ {
+ }
+
+ protected Point MouseMove (Point pos)
+ {
+ return new Point (pos.X - start.X, pos.Y - start.Y);
+ }
+
+ protected virtual void DrawVirtualPosition (Rectangle virtual_position)
+ {
+ form.Bounds = virtual_position;
+ start = Cursor.Position;
+ }
+
+ protected virtual void ClearVirtualPosition ()
+ {
+
+ }
+
+ protected virtual void OnWindowFinishedMoving ()
+ {
+ }
+
+ protected virtual void NCPointToClient(ref int x, ref int y) {
+ form.PointToClient(ref x, ref y);
+ NCClientToNC (ref x, ref y);
+ }
+
+ protected virtual void NCClientToNC (ref int x, ref int y) {
+ y += TitleBarHeight;
+ y += BorderWidth;
+ y += MenuHeight;
+ }
+
+ internal Point GetMenuOrigin ()
+ {
+ return new Point (BorderWidth, BorderWidth + TitleBarHeight);
+ }
+
+ protected FormPos FormPosForCoords (int x, int y)
+ {
+ int bw = BorderWidth;
+ if (y < TitleBarHeight + bw) {
+ // Console.WriteLine ("A");
+ if (y > bw && x > bw &&
+ x < form.Width - bw)
+ return FormPos.TitleBar;
+
+ if (x < bw || (x < 20 && y < bw))
+ return FormPos.TopLeft;
+
+ if (x > form.Width - bw ||
+ (x > form.Width - 20 && y < bw))
+ return FormPos.TopRight;
+
+ if (y < bw)
+ return FormPos.Top;
+
+ } else if (y > form.Height - 20) {
+ // Console.WriteLine ("B");
+ if (x < bw ||
+ (x < 20 && y > form.Height - bw))
+ return FormPos.BottomLeft;
+
+ if (x > form.Width - (bw * 2) ||
+ (x > form.Width - 20 &&
+ y > form.Height - bw))
+ return FormPos.BottomRight;
+
+ if (y > form.Height - (bw * 2))
+ return FormPos.Bottom;
+
+
+ } else if (x < bw) {
+ // Console.WriteLine ("C");
+ return FormPos.Left;
+ } else if (x > form.Width - (bw * 2)) {
+// Console.WriteLine ("D");
+ return FormPos.Right;
+ } else {
+ // Console.WriteLine ("E {0}", form.Width - bw);
+ }
+
+ return FormPos.None;
+ }
+ }
+ internal class TitleButton
+ {
+ public Rectangle Rectangle;
+ public ButtonState State;
+ public CaptionButton Caption;
+ private EventHandler Clicked;
+ public bool Visible;
+ bool entered;
+
+ public TitleButton (CaptionButton caption, EventHandler clicked)
+ {
+ Caption = caption;
+ Clicked = clicked;
+ }
+
+ public void OnClick ()
+ {
+ if (Clicked != null) {
+ Clicked (this, EventArgs.Empty);
+ }
+ }
+
+ public bool Entered {
+ get { return entered; }
+ set { entered = value; }
+ }
+ }
+
+ internal class TitleButtons : System.Collections.IEnumerable
+ {
+ public TitleButton MinimizeButton;
+ public TitleButton MaximizeButton;
+ public TitleButton RestoreButton;
+ public TitleButton CloseButton;
+ public TitleButton HelpButton;
+
+ public TitleButton [] AllButtons;
+ public bool Visible;
+
+ private ToolTip.ToolTipWindow tooltip;
+ private Timer tooltip_timer;
+ private TitleButton tooltip_hovered_button;
+ private TitleButton tooltip_hidden_button;
+ private const int tooltip_hide_interval = 3000;
+ private const int tooltip_show_interval = 1000;
+ private Form form;
+
+ public TitleButtons (Form frm)
+ {
+ this.form = frm;
+ this.Visible = true;
+
+ MinimizeButton = new TitleButton (CaptionButton.Minimize, new EventHandler (ClickHandler));
+ MaximizeButton = new TitleButton (CaptionButton.Maximize, new EventHandler (ClickHandler));
+ RestoreButton = new TitleButton (CaptionButton.Restore, new EventHandler (ClickHandler));
+ CloseButton = new TitleButton (CaptionButton.Close, new EventHandler (ClickHandler));
+ HelpButton = new TitleButton (CaptionButton.Help, new EventHandler (ClickHandler));
+
+ AllButtons = new TitleButton [] { MinimizeButton, MaximizeButton, RestoreButton, CloseButton, HelpButton };
+ }
+
+ private void ClickHandler (object sender, EventArgs e)
+ {
+ if (!Visible) {
+ return;
+ }
+
+ TitleButton button = (TitleButton) sender;
+
+ switch (button.Caption) {
+ case CaptionButton.Close:
+ form.Close ();
+ break;
+ case CaptionButton.Help:
+ Console.WriteLine ("Help not implemented.");
+ break;
+ case CaptionButton.Maximize:
+ form.WindowState = FormWindowState.Maximized;
+ break;
+ case CaptionButton.Minimize:
+ form.WindowState = FormWindowState.Minimized;
+ break;
+ case CaptionButton.Restore:
+ form.WindowState = FormWindowState.Normal;
+ break;
+ }
+ }
+
+ public TitleButton FindButton (int x, int y)
+ {
+ if (!Visible) {
+ return null;
+ }
+
+ foreach (TitleButton button in AllButtons) {
+ if (button.Visible && button.Rectangle.Contains (x, y)) {
+ return button;
+ }
+ }
+ return null;
+ }
+
+ public bool AnyPushedTitleButtons {
+ get {
+ if (!Visible) {
+ return false;
+ }
+
+ foreach (TitleButton button in AllButtons) {
+ if (button.Visible && button.State == ButtonState.Pushed) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ #region IEnumerable Members
+
+ public System.Collections.IEnumerator GetEnumerator ()
+ {
+ return AllButtons.GetEnumerator ();
+ }
+ #endregion
+
+ #region ToolTip helpers
+ // Called from MouseMove if mouse is over a button
+ public void ToolTipStart (TitleButton button)
+ {
+ tooltip_hovered_button = button;
+
+ if (tooltip_hovered_button == tooltip_hidden_button)
+ return;
+ tooltip_hidden_button = null;
+
+ if (tooltip != null && tooltip.Visible)
+ ToolTipShow (true);
+
+ if (tooltip_timer == null) {
+
+ tooltip_timer = new Timer ();
+ tooltip_timer.Tick += new EventHandler (ToolTipTimerTick);
+ }
+
+ tooltip_timer.Interval = tooltip_show_interval;
+ tooltip_timer.Start ();
+ tooltip_hovered_button = button;
+ }
+
+ public void ToolTipTimerTick (object sender, EventArgs e)
+ {
+ if (tooltip_timer.Interval == tooltip_hide_interval) {
+ tooltip_hidden_button = tooltip_hovered_button;
+ ToolTipHide (false);
+ } else {
+ ToolTipShow (false);
+ }
+ }
+ // Called from timer (with only_refresh = false)
+ // Called from ToolTipStart if tooltip is already shown (with only_refresh = true)
+ public void ToolTipShow (bool only_refresh)
+ {
+ if (!form.Visible)
+ return;
+
+ string text = String.Format (tooltip_hovered_button.Caption.ToString ());
+
+ tooltip_timer.Interval = tooltip_hide_interval;
+ tooltip_timer.Enabled = true;
+
+ if (only_refresh && (tooltip == null || !tooltip.Visible)) {
+ return;
+ }
+
+ if (tooltip == null)
+ tooltip = new ToolTip.ToolTipWindow ();
+ else if (tooltip.Text == text && tooltip.Visible)
+ return;
+ else if (tooltip.Visible)
+ tooltip.Visible = false;
+
+ if (form.WindowState == FormWindowState.Maximized && form.MdiParent != null)
+ tooltip.Present (form.MdiParent, text);
+ else
+ tooltip.Present (form, text);
+
+ }
+
+ // Called from MouseLeave (with reset_hidden_button = true)
+ // Called from MouseDown (with reset_hidden_button = false)
+ // Called from MouseMove if mouse isn't over any button (with reset_hidden_button = false)
+ // Called from Timer if hiding (with reset_hidden_button = false)
+ public void ToolTipHide (bool reset_hidden_button)
+ {
+ if (tooltip_timer != null)
+ tooltip_timer.Enabled = false;
+ if (tooltip != null && tooltip.Visible)
+ tooltip.Visible = false;
+ if (reset_hidden_button)
+ tooltip_hidden_button = null;
+ }
+ #endregion
+
+ public bool MouseMove (int x, int y)
+ {
+ if (!Visible) {
+ return false;
+ }
+
+ bool any_change = false;
+ bool any_pushed_buttons = AnyPushedTitleButtons;
+ bool any_tooltip = false;
+ TitleButton over_button = FindButton (x, y);
+
+ foreach (TitleButton button in this) {
+ if (button == null)
+ continue;
+
+ if (button.State == ButtonState.Inactive)
+ continue;
+
+ if (button == over_button) {
+ if (any_pushed_buttons) {
+ any_change |= button.State != ButtonState.Pushed;
+ button.State = ButtonState.Pushed;
+ }
+ ToolTipStart (button);
+ any_tooltip = true;
+ if (!button.Entered) {
+ button.Entered = true;
+ if (ThemeEngine.Current.ManagedWindowTitleButtonHasHotElementStyle (button, form))
+ any_change = true;
+ }
+ } else {
+ if (any_pushed_buttons) {
+ any_change |= button.State != ButtonState.Normal;
+ button.State = ButtonState.Normal;
+ }
+ if (button.Entered) {
+ button.Entered = false;
+ if (ThemeEngine.Current.ManagedWindowTitleButtonHasHotElementStyle (button, form))
+ any_change = true;
+ }
+ }
+ }
+
+ if (!any_tooltip)
+ ToolTipHide (false);
+
+ return any_change;
+ }
+
+ public void MouseDown (int x, int y)
+ {
+ if (!Visible) {
+ return;
+ }
+
+ ToolTipHide (false);
+
+ foreach (TitleButton button in this) {
+ if (button != null && button.State != ButtonState.Inactive) {
+ button.State = ButtonState.Normal;
+ }
+ }
+ TitleButton clicked_button = FindButton (x, y);
+ if (clicked_button != null && clicked_button.State != ButtonState.Inactive) {
+ clicked_button.State = ButtonState.Pushed;
+ }
+ }
+
+ public void MouseUp (int x, int y)
+ {
+ if (!Visible) {
+ return;
+ }
+
+ TitleButton clicked_button = FindButton (x, y);
+ if (clicked_button != null && clicked_button.State != ButtonState.Inactive) {
+ clicked_button.OnClick ();
+ }
+
+ foreach (TitleButton button in this) {
+ if (button == null || button.State == ButtonState.Inactive)
+ continue;
+
+ button.State = ButtonState.Normal;
+ }
+
+ if (clicked_button == CloseButton && !form.closing)
+ XplatUI.InvalidateNC (form.Handle);
+
+ ToolTipHide (true);
+ }
+
+ internal void MouseLeave (int x, int y)
+ {
+ if (!Visible) {
+ return;
+ }
+
+ foreach (TitleButton button in this) {
+ if (button == null || button.State == ButtonState.Inactive)
+ continue;
+
+ button.State = ButtonState.Normal;
+ }
+
+ ToolTipHide (true);
+ }
+ }
+}
+
+