diff options
| author | Michael VanOverbeek <[email protected]> | 2016-07-25 12:57:52 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2016-07-25 12:57:52 -0400 |
| commit | 46c1c31302f111a1f3ec23a70e6f3986a9aa2a27 (patch) | |
| tree | f00af7ea3f6ad2641fb26fa1d310fd8b7179b39c /source/ShiftUI/Internal/InternalWindowManager.cs | |
| parent | af48e774189596b8d7a058c564a7d6d75205ca03 (diff) | |
| parent | 6fa16209519896de09949a27425dff00ebf2970a (diff) | |
| download | shiftos-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.cs | 1211 |
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); + } + } +} + + |
