1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
23 // Jackson Harper (jackson@ximian.com)
30 using System.Runtime.InteropServices;
33 namespace System.Windows.Forms {
35 internal abstract class InternalWindowManager {
36 private Size MinTitleBarSize = new Size (115, 25);
37 private TitleButtons title_buttons;
43 protected Point clicked_point;
44 private FormPos sizing_edge;
45 internal Rectangle virtual_position;
47 private Rectangle normal_bounds;
48 private Rectangle iconic_bounds;
69 TopRight = Top | Right,
71 BottomLeft = Bottom | Left,
72 BottomRight = Bottom | Right,
74 AnyEdge = Top | Left | Right | Bottom,
77 public InternalWindowManager (Form form)
81 form.SizeChanged += new EventHandler (FormSizeChangedHandler);
83 title_buttons = new TitleButtons (form);
84 ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
91 public int IconWidth {
92 get { return TitleBarHeight - 5; }
95 public TitleButtons TitleButtons {
100 internal Rectangle NormalBounds {
102 return normal_bounds;
105 normal_bounds = value;
108 internal Size IconicSize {
110 int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
111 return new Size (152 + bw * 2, TitleBarHeight + bw * 2);
115 internal Rectangle IconicBounds {
117 if (iconic_bounds == Rectangle.Empty)
118 return Rectangle.Empty;
119 Rectangle result = iconic_bounds;
120 result.Y = Form.Parent.ClientRectangle.Bottom - iconic_bounds.Y;
124 iconic_bounds = value;
125 iconic_bounds.Y = Form.Parent.ClientRectangle.Bottom - iconic_bounds.Y;
129 internal virtual Rectangle MaximizedBounds {
131 return Form.Parent.ClientRectangle;
135 public virtual void UpdateWindowState (FormWindowState old_window_state, FormWindowState new_window_state, bool force)
137 if (old_window_state == FormWindowState.Normal) {
138 NormalBounds = form.Bounds;
139 } else if (old_window_state == FormWindowState.Minimized) {
140 IconicBounds = form.Bounds;
143 switch (new_window_state) {
144 case FormWindowState.Minimized:
145 if (IconicBounds == Rectangle.Empty) {
146 Size size = IconicSize;
147 Point location = new Point (0, Form.Parent.ClientSize.Height - size.Height);
148 IconicBounds = new Rectangle (location, size);
150 form.Bounds = IconicBounds;
152 case FormWindowState.Maximized:
153 form.Bounds = MaximizedBounds;
155 case FormWindowState.Normal:
156 form.Bounds = NormalBounds;
160 UpdateWindowDecorations (new_window_state);
164 public virtual void UpdateWindowDecorations (FormWindowState window_state)
166 ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
167 if (form.IsHandleCreated)
168 XplatUI.RequestNCRecalc (form.Handle);
171 public virtual bool WndProc (ref Message m)
174 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 ());
177 switch ((Msg)m.Msg) {
180 // The mouse handling messages are actually
181 // not WM_NC* messages except for the first button and NCMOVEs
182 // down because we capture on the form
184 case Msg.WM_MOUSEMOVE:
185 return HandleMouseMove (form, ref m);
187 case Msg.WM_LBUTTONUP:
188 HandleLButtonUp (ref m);
191 case Msg.WM_RBUTTONDOWN:
192 return HandleRButtonDown (ref m);
194 case Msg.WM_LBUTTONDOWN:
195 return HandleLButtonDown (ref m);
197 case Msg.WM_LBUTTONDBLCLK:
198 return HandleLButtonDblClick (ref m);
200 case Msg.WM_PARENTNOTIFY:
201 if (Control.LowOrder(m.WParam.ToInt32()) == (int) Msg.WM_LBUTTONDOWN)
205 case Msg.WM_NCHITTEST:
206 return HandleNCHitTest (ref m);
208 // Return true from these guys, otherwise win32 will mess up z-order
209 case Msg.WM_NCLBUTTONUP:
210 HandleNCLButtonUp (ref m);
213 case Msg.WM_NCLBUTTONDOWN:
214 HandleNCLButtonDown (ref m);
217 case Msg.WM_NCMOUSEMOVE:
218 HandleNCMouseMove (ref m);
221 case Msg.WM_NCLBUTTONDBLCLK:
222 HandleNCLButtonDblClick (ref m);
225 case Msg.WM_NCMOUSELEAVE:
226 HandleNCMouseLeave (ref m);
229 case Msg.WM_MOUSELEAVE:
230 HandleMouseLeave (ref m);
233 case Msg.WM_NCCALCSIZE:
234 return HandleNCCalcSize (ref m);
237 return HandleNCPaint (ref m);
243 protected virtual bool HandleNCPaint (ref Message m)
245 PaintEventArgs pe = XplatUI.PaintEventStart (ref m, form.Handle, false);
249 if (form.ActiveMenu != null) {
252 pnt = GetMenuOrigin ();
254 // The entire menu has to be in the clip rectangle because the
255 // control buttons are right-aligned and otherwise they would
256 // stay painted when the window gets resized.
257 clip = new Rectangle (pnt.X, pnt.Y, form.ClientSize.Width, 0);
258 clip = Rectangle.Union (clip, pe.ClipRectangle);
260 pe.Graphics.SetClip (clip);
262 form.ActiveMenu.Draw (pe, new Rectangle (pnt.X, pnt.Y, form.ClientSize.Width, 0));
264 // clip region is not correct on win32.
265 // use the entire form's area.
266 clip = new Rectangle (0, 0, form.Width, form.Height);
267 ThemeEngine.Current.DrawManagedWindowDecorations (pe.Graphics, clip, this);
268 XplatUI.PaintEventEnd (ref m, form.Handle, false);
272 protected virtual bool HandleNCCalcSize (ref Message m)
274 XplatUIWin32.NCCALCSIZE_PARAMS ncp;
275 XplatUIWin32.RECT rect;
277 if (m.WParam == (IntPtr)1) {
278 ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (m.LParam,
279 typeof (XplatUIWin32.NCCALCSIZE_PARAMS));
281 ncp.rgrc1 = NCCalcSize (ncp.rgrc1);
283 Marshal.StructureToPtr (ncp, m.LParam, true);
285 rect = (XplatUIWin32.RECT) Marshal.PtrToStructure (m.LParam, typeof (XplatUIWin32.RECT));
287 rect = NCCalcSize (rect);
289 Marshal.StructureToPtr (rect, m.LParam, true);
295 protected virtual XplatUIWin32.RECT NCCalcSize (XplatUIWin32.RECT proposed_window_rect)
297 int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
300 proposed_window_rect.top += TitleBarHeight + bw;
301 proposed_window_rect.bottom -= bw;
302 proposed_window_rect.left += bw;
303 proposed_window_rect.right -= bw;
306 // This is necessary for Linux, can't handle <= 0-sized
307 // client areas correctly.
308 if (proposed_window_rect.right <= proposed_window_rect.left) {
309 proposed_window_rect.right += proposed_window_rect.left - proposed_window_rect.right + 1;
311 if (proposed_window_rect.top >= proposed_window_rect.bottom) {
312 proposed_window_rect.bottom += proposed_window_rect.top - proposed_window_rect.bottom + 1;
315 return proposed_window_rect;
318 protected virtual bool HandleNCHitTest (ref Message m)
321 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
322 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
324 NCPointToClient (ref x, ref y);
326 FormPos pos = FormPosForCoords (x, y);
328 if (pos == FormPos.TitleBar) {
329 m.Result = new IntPtr ((int)HitTest.HTCAPTION);
338 m.Result = new IntPtr ((int)HitTest.HTTOP);
341 m.Result = new IntPtr ((int)HitTest.HTLEFT);
344 m.Result = new IntPtr ((int)HitTest.HTRIGHT);
347 m.Result = new IntPtr ((int)HitTest.HTBOTTOM);
349 case FormPos.TopLeft:
350 m.Result = new IntPtr ((int)HitTest.HTTOPLEFT);
352 case FormPos.TopRight:
353 m.Result = new IntPtr ((int)HitTest.HTTOPRIGHT);
355 case FormPos.BottomLeft:
356 m.Result = new IntPtr ((int)HitTest.HTBOTTOMLEFT);
358 case FormPos.BottomRight:
359 m.Result = new IntPtr ((int)HitTest.HTBOTTOMRIGHT);
362 // We return false so that DefWndProc handles things
368 public virtual void UpdateBorderStyle (FormBorderStyle border_style)
370 if (form.IsHandleCreated) {
371 XplatUI.SetBorderStyle (form.Handle, border_style);
374 if (ShouldRemoveWindowManager (border_style)) {
375 form.RemoveWindowManager ();
379 ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
384 public virtual void SetWindowState (FormWindowState old_state, FormWindowState window_state)
386 UpdateWindowState (old_state, window_state, false);
389 public virtual FormWindowState GetWindowState ()
391 return form.window_state;
394 public virtual void PointToClient (ref int x, ref int y)
396 // toolwindows stay in screencoords we just have to make sure
397 // they obey the working area
398 Rectangle working = SystemInformation.WorkingArea;
400 if (x > working.Right)
402 if (x < working.Left)
407 if (y > working.Bottom)
411 public virtual void PointToScreen (ref int x, ref int y)
413 XplatUI.ClientToScreen (form.Handle, ref x, ref y);
416 protected virtual bool ShouldRemoveWindowManager (FormBorderStyle style)
418 return style != FormBorderStyle.FixedToolWindow && style != FormBorderStyle.SizableToolWindow;
421 public bool IconRectangleContains (int x, int y)
423 if (form.Icon == null)
426 int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
427 Rectangle icon = new Rectangle (bw + 3, bw + 2, IconWidth, IconWidth);
428 return icon.Contains (x, y);
431 protected virtual void Activate ()
436 public virtual bool IsActive {
443 private void FormSizeChangedHandler (object sender, EventArgs e)
445 if (form.IsHandleCreated) {
446 ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
447 XplatUI.InvalidateNC (form.Handle);
451 protected virtual bool HandleRButtonDown (ref Message m)
457 protected virtual bool HandleLButtonDown (ref Message m)
463 protected virtual bool HandleLButtonDblClick(ref Message m)
468 protected virtual bool HandleNCMouseLeave (ref Message m)
470 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
471 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
473 NCPointToClient (ref x, ref y);
474 FormPos pos = FormPosForCoords (x, y);
476 if (pos != FormPos.TitleBar) {
477 HandleTitleBarLeave (x, y);
484 protected virtual bool HandleNCMouseMove (ref Message m)
486 int x = Control.LowOrder((int)m.LParam.ToInt32( ));
487 int y = Control.HighOrder((int)m.LParam.ToInt32( ));
489 NCPointToClient (ref x, ref y);
490 FormPos pos = FormPosForCoords (x, y);
492 if (pos == FormPos.TitleBar) {
493 HandleTitleBarMouseMove (x, y);
497 if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) {
498 MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y, 0);
499 form.ActiveMenu.OnMouseMove (form, mea);
506 protected virtual bool HandleNCLButtonDown (ref Message m)
510 start = Cursor.Position;
511 virtual_position = form.Bounds;
513 int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
514 int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
516 // Need to adjust because we are in NC land
517 NCPointToClient (ref x, ref y);
518 FormPos pos = FormPosForCoords (x, y);
520 if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) {
521 MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y - TitleBarHeight, 0);
522 form.ActiveMenu.OnMouseDown (form, mea);
525 if (pos == FormPos.TitleBar) {
526 HandleTitleBarDown (x, y);
531 if ((pos & FormPos.AnyEdge) == 0)
534 virtual_position = form.Bounds;
535 state = State.Sizing;
544 protected virtual void HandleNCLButtonDblClick (ref Message m)
546 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
547 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
549 // Need to adjust because we are in NC land
550 NCPointToClient (ref x, ref y);
552 FormPos pos = FormPosForCoords (x, y);
553 if (pos == FormPos.TitleBar || pos == FormPos.Top)
554 HandleTitleBarDoubleClick (x, y);
558 protected virtual void HandleTitleBarDoubleClick (int x, int y)
563 protected virtual void HandleTitleBarLeave (int x, int y)
565 title_buttons.MouseLeave (x, y);
568 protected virtual void HandleTitleBarMouseMove (int x, int y)
570 bool any_change = false;
572 any_change = title_buttons.MouseMove (x, y);
575 if (IsMaximized && form.IsMdiChild)
576 XplatUI.InvalidateNC (form.MdiParent.Handle);
578 XplatUI.InvalidateNC (form.Handle);
582 protected virtual void HandleTitleBarUp (int x, int y)
584 title_buttons.MouseUp (x, y);
589 protected virtual void HandleTitleBarDown (int x, int y)
591 title_buttons.MouseDown (x, y);
593 if (!TitleButtons.AnyPushedTitleButtons && !IsMaximized) {
594 state = State.Moving;
595 clicked_point = new Point (x, y);
596 if (form.Parent != null) {
597 form.CaptureWithConfine (form.Parent);
603 XplatUI.InvalidateNC (form.Handle);
606 private bool HandleMouseMove (Form form, ref Message m)
610 HandleWindowMove (m);
620 private void HandleMouseLeave (ref Message m)
625 protected virtual void HandleWindowMove (Message m)
627 Point move = MouseMove (m);
629 UpdateVP (virtual_position.X + move.X, virtual_position.Y + move.Y,
630 virtual_position.Width, virtual_position.Height);
633 private void HandleSizing (Message m)
635 Rectangle pos = virtual_position;
636 int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
637 int mw = MinTitleBarSize.Width + (bw * 2);
638 int mh = MinTitleBarSize.Height + (bw * 2);
639 int x = Cursor.Position.X;
640 int y = Cursor.Position.Y;
642 PointToClient (ref x, ref y);
644 if ((sizing_edge & FormPos.Top) != 0) {
645 if (pos.Bottom - y < mh)
647 pos.Height = pos.Bottom - y;
649 } else if ((sizing_edge & FormPos.Bottom) != 0) {
650 int height = y - pos.Top;
656 if ((sizing_edge & FormPos.Left) != 0) {
657 if (pos.Right - x < mw)
659 pos.Width = pos.Right - x;
661 } else if ((sizing_edge & FormPos.Right) != 0) {
662 int width = x - form.Left;
671 public bool IsMaximized {
672 get { return GetWindowState () == FormWindowState.Maximized; }
675 public bool IsMinimized {
676 get { return GetWindowState () == FormWindowState.Minimized; }
679 public bool IsSizable {
681 switch (form.FormBorderStyle) {
682 case FormBorderStyle.Sizable:
683 case FormBorderStyle.SizableToolWindow:
684 return (form.window_state != FormWindowState.Minimized);
691 public bool HasBorders {
693 return form.FormBorderStyle != FormBorderStyle.None;
697 public bool IsToolWindow {
699 if (form.FormBorderStyle == FormBorderStyle.SizableToolWindow ||
700 form.FormBorderStyle == FormBorderStyle.FixedToolWindow)
706 public int TitleBarHeight {
708 return ThemeEngine.Current.ManagedWindowTitleBarHeight (this);
712 public int BorderWidth {
714 return ThemeEngine.Current.ManagedWindowBorderWidth (this);
718 public virtual int MenuHeight {
720 return (form.Menu != null ? ThemeEngine.Current.MenuHeight : 0);
724 protected void UpdateVP (Rectangle r)
726 UpdateVP (r.X, r.Y, r.Width, r.Height);
729 protected void UpdateVP (Point loc, int w, int h)
731 UpdateVP (loc.X, loc.Y, w, h);
734 protected void UpdateVP (int x, int y, int w, int h)
736 virtual_position.X = x;
737 virtual_position.Y = y;
738 virtual_position.Width = w;
739 virtual_position.Height = h;
741 DrawVirtualPosition (virtual_position);
744 protected virtual void HandleLButtonUp (ref Message m)
746 if (state == State.Idle)
749 ClearVirtualPosition ();
751 form.Capture = false;
752 if (state == State.Moving && form.Location != virtual_position.Location)
753 form.Location = virtual_position.Location;
754 else if (state == State.Sizing && form.Bounds != virtual_position)
755 form.Bounds = virtual_position;
758 OnWindowFinishedMoving ();
761 private bool HandleNCLButtonUp (ref Message m)
764 ClearVirtualPosition ();
766 form.Capture = false;
768 if (form.MdiContainer != null)
769 form.MdiContainer.SizeScrollBars();
772 int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
773 int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
775 NCPointToClient (ref x, ref y);
776 FormPos pos = FormPosForCoords (x, y);
778 if (pos == FormPos.TitleBar) {
779 HandleTitleBarUp (x, y);
786 protected void DrawTitleButton (Graphics dc, TitleButton button, Rectangle clip)
788 if (!button.Rectangle.IntersectsWith (clip))
791 dc.FillRectangle (SystemBrushes.Control, button.Rectangle);
792 ControlPaint.DrawCaptionButton (dc, button.Rectangle,
793 button.Caption, button.State);
796 public virtual void DrawMaximizedButtons (object sender, PaintEventArgs pe)
800 protected Point MouseMove (Message m)
802 Point cp = Cursor.Position;
803 return new Point (cp.X - start.X, cp.Y - start.Y);
806 protected virtual void DrawVirtualPosition (Rectangle virtual_position)
808 form.Bounds = virtual_position;
809 start = Cursor.Position;
812 protected virtual void ClearVirtualPosition ()
817 protected virtual void OnWindowFinishedMoving ()
821 protected virtual void NCPointToClient(ref int x, ref int y) {
822 form.PointToClient(ref x, ref y);
823 NCClientToNC (ref x, ref y);
826 protected virtual void NCClientToNC (ref int x, ref int y) {
832 internal Point GetMenuOrigin ()
834 return new Point (BorderWidth, BorderWidth + TitleBarHeight);
837 protected FormPos FormPosForCoords (int x, int y)
839 int bw = BorderWidth;
840 if (y < TitleBarHeight + bw) {
841 // Console.WriteLine ("A");
842 if (y > bw && x > bw &&
844 return FormPos.TitleBar;
846 if (x < bw || (x < 20 && y < bw))
847 return FormPos.TopLeft;
849 if (x > form.Width - bw ||
850 (x > form.Width - 20 && y < bw))
851 return FormPos.TopRight;
856 } else if (y > form.Height - 20) {
857 // Console.WriteLine ("B");
859 (x < 20 && y > form.Height - bw))
860 return FormPos.BottomLeft;
862 if (x > form.Width - (bw * 2) ||
863 (x > form.Width - 20 &&
864 y > form.Height - bw))
865 return FormPos.BottomRight;
867 if (y > form.Height - (bw * 2))
868 return FormPos.Bottom;
872 // Console.WriteLine ("C");
874 } else if (x > form.Width - (bw * 2)) {
875 // Console.WriteLine ("D");
876 return FormPos.Right;
878 // Console.WriteLine ("E {0}", form.Width - bw);
884 internal class TitleButton
886 public Rectangle Rectangle;
887 public ButtonState State;
888 public CaptionButton Caption;
889 private EventHandler Clicked;
892 public TitleButton (CaptionButton caption, EventHandler clicked)
898 public void OnClick ()
900 if (Clicked != null) {
901 Clicked (this, EventArgs.Empty);
906 internal class TitleButtons : System.Collections.IEnumerable
908 public TitleButton MinimizeButton;
909 public TitleButton MaximizeButton;
910 public TitleButton RestoreButton;
911 public TitleButton CloseButton;
912 public TitleButton HelpButton;
914 public TitleButton [] AllButtons;
917 private ToolTip.ToolTipWindow tooltip;
918 private Timer tooltip_timer;
919 private TitleButton tooltip_hovered_button;
920 private TitleButton tooltip_hidden_button;
921 private const int tooltip_hide_interval = 3000;
922 private const int tooltip_show_interval = 1000;
925 public TitleButtons (Form frm)
930 MinimizeButton = new TitleButton (CaptionButton.Minimize, new EventHandler (ClickHandler));
931 MaximizeButton = new TitleButton (CaptionButton.Maximize, new EventHandler (ClickHandler));
932 RestoreButton = new TitleButton (CaptionButton.Restore, new EventHandler (ClickHandler));
933 CloseButton = new TitleButton (CaptionButton.Close, new EventHandler (ClickHandler));
934 HelpButton = new TitleButton (CaptionButton.Help, new EventHandler (ClickHandler));
936 AllButtons = new TitleButton [] { MinimizeButton, MaximizeButton, RestoreButton, CloseButton, HelpButton };
939 private void ClickHandler (object sender, EventArgs e)
945 TitleButton button = (TitleButton) sender;
947 switch (button.Caption) {
948 case CaptionButton.Close:
951 case CaptionButton.Help:
952 Console.WriteLine ("Help not implemented.");
954 case CaptionButton.Maximize:
955 form.WindowState = FormWindowState.Maximized;
957 case CaptionButton.Minimize:
958 form.WindowState = FormWindowState.Minimized;
960 case CaptionButton.Restore:
961 form.WindowState = FormWindowState.Normal;
966 public TitleButton FindButton (int x, int y)
972 foreach (TitleButton button in AllButtons) {
973 if (button.Visible && button.Rectangle.Contains (x, y)) {
980 public bool AnyPushedTitleButtons {
986 foreach (TitleButton button in AllButtons) {
987 if (button.Visible && button.State == ButtonState.Pushed) {
995 #region IEnumerable Members
997 public System.Collections.IEnumerator GetEnumerator ()
999 return AllButtons.GetEnumerator ();
1003 #region ToolTip helpers
1004 // Called from MouseMove if mouse is over a button
1005 public void ToolTipStart (TitleButton button)
1007 tooltip_hovered_button = button;
1009 if (tooltip_hovered_button == tooltip_hidden_button)
1011 tooltip_hidden_button = null;
1013 if (tooltip != null && tooltip.Visible)
1016 if (tooltip_timer == null) {
1018 tooltip_timer = new Timer ();
1019 tooltip_timer.Tick += new EventHandler (ToolTipTimerTick);
1022 tooltip_timer.Interval = tooltip_show_interval;
1023 tooltip_timer.Start ();
1024 tooltip_hovered_button = button;
1027 public void ToolTipTimerTick (object sender, EventArgs e)
1029 if (tooltip_timer.Interval == tooltip_hide_interval) {
1030 tooltip_hidden_button = tooltip_hovered_button;
1031 ToolTipHide (false);
1033 ToolTipShow (false);
1036 // Called from timer (with only_refresh = false)
1037 // Called from ToolTipStart if tooltip is already shown (with only_refresh = true)
1038 public void ToolTipShow (bool only_refresh)
1043 string text = Locale.GetText (tooltip_hovered_button.Caption.ToString ());
1045 tooltip_timer.Interval = tooltip_hide_interval;
1046 tooltip_timer.Enabled = true;
1048 if (only_refresh && (tooltip == null || !tooltip.Visible)) {
1052 if (tooltip == null)
1053 tooltip = new ToolTip.ToolTipWindow ();
1054 else if (tooltip.Text == text && tooltip.Visible)
1056 else if (tooltip.Visible)
1057 tooltip.Visible = false;
1059 if (form.WindowState == FormWindowState.Maximized && form.MdiParent != null)
1060 tooltip.Present (form.MdiParent, text);
1062 tooltip.Present (form, text);
1066 // Called from MouseLeave (with reset_hidden_button = true)
1067 // Called from MouseDown (with reset_hidden_button = false)
1068 // Called from MouseMove if mouse isn't over any button (with reset_hidden_button = false)
1069 // Called from Timer if hiding (with reset_hidden_button = false)
1070 public void ToolTipHide (bool reset_hidden_button)
1072 if (tooltip_timer != null)
1073 tooltip_timer.Enabled = false;
1074 if (tooltip != null && tooltip.Visible)
1075 tooltip.Visible = false;
1076 if (reset_hidden_button)
1077 tooltip_hidden_button = null;
1081 public bool MouseMove (int x, int y)
1087 bool any_change = false;
1088 bool any_pushed_buttons = AnyPushedTitleButtons;
1089 bool any_tooltip = false;
1090 TitleButton over_button = FindButton (x, y);
1092 foreach (TitleButton button in this) {
1096 if (button == over_button) {
1097 if (any_pushed_buttons) {
1098 any_change |= button.State != ButtonState.Pushed;
1099 button.State = ButtonState.Pushed;
1101 ToolTipStart (button);
1104 if (any_pushed_buttons) {
1105 any_change |= button.State != ButtonState.Normal;
1106 button.State = ButtonState.Normal;
1112 ToolTipHide (false);
1117 public void MouseDown (int x, int y)
1123 ToolTipHide (false);
1125 foreach (TitleButton button in this) {
1126 if (button != null) {
1127 button.State = ButtonState.Normal;
1130 TitleButton clicked_button = FindButton (x, y);
1131 if (clicked_button != null) {
1132 clicked_button.State = ButtonState.Pushed;
1136 public void MouseUp (int x, int y)
1142 TitleButton clicked_button = FindButton (x, y);
1143 if (clicked_button != null) {
1144 clicked_button.OnClick ();
1147 foreach (TitleButton button in this) {
1151 button.State = ButtonState.Normal;
1154 if (clicked_button == CloseButton && !form.closing)
1155 XplatUI.InvalidateNC (form.Handle);
1158 internal void MouseLeave (int x, int y)
1164 foreach (TitleButton button in this) {
1168 button.State = ButtonState.Normal;