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 TitleButtons title_buttons;
42 protected Point clicked_point;
43 private FormPos sizing_edge;
44 internal Rectangle virtual_position;
46 private Rectangle normal_bounds;
47 private Rectangle iconic_bounds;
68 TopRight = Top | Right,
70 BottomLeft = Bottom | Left,
71 BottomRight = Bottom | Right,
73 AnyEdge = Top | Left | Right | Bottom,
76 public InternalWindowManager (Form form)
80 form.SizeChanged += new EventHandler (FormSizeChangedHandler);
82 title_buttons = new TitleButtons (form);
83 ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
90 public int IconWidth {
91 get { return TitleBarHeight - 5; }
94 public TitleButtons TitleButtons {
99 internal Rectangle NormalBounds {
101 return normal_bounds;
104 normal_bounds = value;
107 internal Size IconicSize {
109 return SystemInformation.MinimizedWindowSize;
113 internal Rectangle IconicBounds {
115 if (iconic_bounds == Rectangle.Empty)
116 return Rectangle.Empty;
117 Rectangle result = iconic_bounds;
118 result.Y = Form.Parent.ClientRectangle.Bottom - iconic_bounds.Y;
122 iconic_bounds = value;
123 iconic_bounds.Y = Form.Parent.ClientRectangle.Bottom - iconic_bounds.Y;
127 internal virtual Rectangle MaximizedBounds {
129 return Form.Parent.ClientRectangle;
133 public virtual void UpdateWindowState (FormWindowState old_window_state, FormWindowState new_window_state, bool force)
135 if (old_window_state == FormWindowState.Normal) {
136 NormalBounds = form.Bounds;
137 } else if (old_window_state == FormWindowState.Minimized) {
138 IconicBounds = form.Bounds;
141 switch (new_window_state) {
142 case FormWindowState.Minimized:
143 if (IconicBounds == Rectangle.Empty) {
144 Size size = IconicSize;
145 Point location = new Point (0, Form.Parent.ClientSize.Height - size.Height);
146 IconicBounds = new Rectangle (location, size);
148 form.Bounds = IconicBounds;
150 case FormWindowState.Maximized:
151 form.Bounds = MaximizedBounds;
153 case FormWindowState.Normal:
154 form.Bounds = NormalBounds;
158 UpdateWindowDecorations (new_window_state);
162 public virtual void UpdateWindowDecorations (FormWindowState window_state)
164 ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
165 if (form.IsHandleCreated)
166 XplatUI.RequestNCRecalc (form.Handle);
169 public virtual bool WndProc (ref Message m)
172 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 ());
175 switch ((Msg)m.Msg) {
178 // The mouse handling messages are actually
179 // not WM_NC* messages except for the first button and NCMOVEs
180 // down because we capture on the form
182 case Msg.WM_MOUSEMOVE:
183 return HandleMouseMove (form, ref m);
185 case Msg.WM_LBUTTONUP:
186 HandleLButtonUp (ref m);
189 case Msg.WM_RBUTTONDOWN:
190 return HandleRButtonDown (ref m);
192 case Msg.WM_LBUTTONDOWN:
193 return HandleLButtonDown (ref m);
195 case Msg.WM_LBUTTONDBLCLK:
196 return HandleLButtonDblClick (ref m);
198 case Msg.WM_PARENTNOTIFY:
199 if (Control.LowOrder(m.WParam.ToInt32()) == (int) Msg.WM_LBUTTONDOWN)
203 case Msg.WM_NCHITTEST:
204 return HandleNCHitTest (ref m);
206 // Return true from these guys, otherwise win32 will mess up z-order
207 case Msg.WM_NCLBUTTONUP:
208 HandleNCLButtonUp (ref m);
211 case Msg.WM_NCLBUTTONDOWN:
212 HandleNCLButtonDown (ref m);
215 case Msg.WM_NCMOUSEMOVE:
216 HandleNCMouseMove (ref m);
219 case Msg.WM_NCLBUTTONDBLCLK:
220 HandleNCLButtonDblClick (ref m);
223 case Msg.WM_NCMOUSELEAVE:
224 HandleNCMouseLeave (ref m);
227 case Msg.WM_MOUSELEAVE:
228 HandleMouseLeave (ref m);
231 case Msg.WM_NCCALCSIZE:
232 return HandleNCCalcSize (ref m);
235 return HandleNCPaint (ref m);
241 protected virtual bool HandleNCPaint (ref Message m)
243 PaintEventArgs pe = XplatUI.PaintEventStart (ref m, form.Handle, false);
247 if (form.ActiveMenu != null) {
250 pnt = GetMenuOrigin ();
252 // The entire menu has to be in the clip rectangle because the
253 // control buttons are right-aligned and otherwise they would
254 // stay painted when the window gets resized.
255 clip = new Rectangle (pnt.X, pnt.Y, form.ClientSize.Width, 0);
256 clip = Rectangle.Union (clip, pe.ClipRectangle);
258 pe.Graphics.SetClip (clip);
260 form.ActiveMenu.Draw (pe, new Rectangle (pnt.X, pnt.Y, form.ClientSize.Width, 0));
262 // clip region is not correct on win32.
263 // use the entire form's area.
264 clip = new Rectangle (0, 0, form.Width, form.Height);
265 ThemeEngine.Current.DrawManagedWindowDecorations (pe.Graphics, clip, this);
266 XplatUI.PaintEventEnd (ref m, form.Handle, false);
270 protected virtual bool HandleNCCalcSize (ref Message m)
272 XplatUIWin32.NCCALCSIZE_PARAMS ncp;
273 XplatUIWin32.RECT rect;
275 if (m.WParam == (IntPtr)1) {
276 ncp = (XplatUIWin32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure (m.LParam,
277 typeof (XplatUIWin32.NCCALCSIZE_PARAMS));
279 ncp.rgrc1 = NCCalcSize (ncp.rgrc1);
281 Marshal.StructureToPtr (ncp, m.LParam, true);
283 rect = (XplatUIWin32.RECT) Marshal.PtrToStructure (m.LParam, typeof (XplatUIWin32.RECT));
285 rect = NCCalcSize (rect);
287 Marshal.StructureToPtr (rect, m.LParam, true);
293 protected virtual XplatUIWin32.RECT NCCalcSize (XplatUIWin32.RECT proposed_window_rect)
295 int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
298 proposed_window_rect.top += TitleBarHeight + bw;
299 proposed_window_rect.bottom -= bw;
300 proposed_window_rect.left += bw;
301 proposed_window_rect.right -= bw;
304 // This is necessary for Linux, can't handle <= 0-sized
305 // client areas correctly.
306 if (proposed_window_rect.right <= proposed_window_rect.left) {
307 proposed_window_rect.right += proposed_window_rect.left - proposed_window_rect.right + 1;
309 if (proposed_window_rect.top >= proposed_window_rect.bottom) {
310 proposed_window_rect.bottom += proposed_window_rect.top - proposed_window_rect.bottom + 1;
313 return proposed_window_rect;
316 protected virtual bool HandleNCHitTest (ref Message m)
319 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
320 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
322 NCPointToClient (ref x, ref y);
324 FormPos pos = FormPosForCoords (x, y);
326 if (pos == FormPos.TitleBar) {
327 m.Result = new IntPtr ((int)HitTest.HTCAPTION);
336 m.Result = new IntPtr ((int)HitTest.HTTOP);
339 m.Result = new IntPtr ((int)HitTest.HTLEFT);
342 m.Result = new IntPtr ((int)HitTest.HTRIGHT);
345 m.Result = new IntPtr ((int)HitTest.HTBOTTOM);
347 case FormPos.TopLeft:
348 m.Result = new IntPtr ((int)HitTest.HTTOPLEFT);
350 case FormPos.TopRight:
351 m.Result = new IntPtr ((int)HitTest.HTTOPRIGHT);
353 case FormPos.BottomLeft:
354 m.Result = new IntPtr ((int)HitTest.HTBOTTOMLEFT);
356 case FormPos.BottomRight:
357 m.Result = new IntPtr ((int)HitTest.HTBOTTOMRIGHT);
360 // We return false so that DefWndProc handles things
366 public virtual void UpdateBorderStyle (FormBorderStyle border_style)
368 if (form.IsHandleCreated) {
369 XplatUI.SetBorderStyle (form.Handle, border_style);
372 if (ShouldRemoveWindowManager (border_style)) {
373 form.RemoveWindowManager ();
377 ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
382 public virtual void SetWindowState (FormWindowState old_state, FormWindowState window_state)
384 UpdateWindowState (old_state, window_state, false);
387 public virtual FormWindowState GetWindowState ()
389 return form.window_state;
392 public virtual void PointToClient (ref int x, ref int y)
394 // toolwindows stay in screencoords we just have to make sure
395 // they obey the working area
396 Rectangle working = SystemInformation.WorkingArea;
398 if (x > working.Right)
400 if (x < working.Left)
405 if (y > working.Bottom)
409 public virtual void PointToScreen (ref int x, ref int y)
411 XplatUI.ClientToScreen (form.Handle, ref x, ref y);
414 protected virtual bool ShouldRemoveWindowManager (FormBorderStyle style)
416 return style != FormBorderStyle.FixedToolWindow && style != FormBorderStyle.SizableToolWindow;
419 public bool IconRectangleContains (int x, int y)
421 if (form.Icon == null)
424 int bw = ThemeEngine.Current.ManagedWindowBorderWidth (this);
425 Rectangle icon = new Rectangle (bw + 3, bw + 2, IconWidth, IconWidth);
426 return icon.Contains (x, y);
429 protected virtual void Activate ()
434 public virtual bool IsActive {
441 private void FormSizeChangedHandler (object sender, EventArgs e)
443 if (form.IsHandleCreated) {
444 ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
445 XplatUI.InvalidateNC (form.Handle);
449 protected virtual bool HandleRButtonDown (ref Message m)
455 protected virtual bool HandleLButtonDown (ref Message m)
461 protected virtual bool HandleLButtonDblClick(ref Message m)
466 protected virtual bool HandleNCMouseLeave (ref Message m)
468 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
469 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
471 NCPointToClient (ref x, ref y);
472 FormPos pos = FormPosForCoords (x, y);
474 if (pos != FormPos.TitleBar) {
475 HandleTitleBarLeave (x, y);
482 protected virtual bool HandleNCMouseMove (ref Message m)
484 int x = Control.LowOrder((int)m.LParam.ToInt32( ));
485 int y = Control.HighOrder((int)m.LParam.ToInt32( ));
487 NCPointToClient (ref x, ref y);
488 FormPos pos = FormPosForCoords (x, y);
490 if (pos == FormPos.TitleBar) {
491 HandleTitleBarMouseMove (x, y);
495 if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) {
496 MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y, 0);
497 form.ActiveMenu.OnMouseMove (form, mea);
504 protected virtual bool HandleNCLButtonDown (ref Message m)
508 start = Cursor.Position;
509 virtual_position = form.Bounds;
511 int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
512 int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
514 // Need to adjust because we are in NC land
515 NCPointToClient (ref x, ref y);
516 FormPos pos = FormPosForCoords (x, y);
518 if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) {
519 MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y - TitleBarHeight, 0);
520 form.ActiveMenu.OnMouseDown (form, mea);
523 if (pos == FormPos.TitleBar) {
524 HandleTitleBarDown (x, y);
529 if ((pos & FormPos.AnyEdge) == 0)
532 virtual_position = form.Bounds;
533 state = State.Sizing;
542 protected virtual void HandleNCLButtonDblClick (ref Message m)
544 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
545 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
547 // Need to adjust because we are in NC land
548 NCPointToClient (ref x, ref y);
550 FormPos pos = FormPosForCoords (x, y);
551 if (pos == FormPos.TitleBar || pos == FormPos.Top)
552 HandleTitleBarDoubleClick (x, y);
556 protected virtual void HandleTitleBarDoubleClick (int x, int y)
561 protected virtual void HandleTitleBarLeave (int x, int y)
563 title_buttons.MouseLeave (x, y);
566 protected virtual void HandleTitleBarMouseMove (int x, int y)
568 bool any_change = false;
570 any_change = title_buttons.MouseMove (x, y);
573 if (IsMaximized && form.IsMdiChild)
574 XplatUI.InvalidateNC (form.MdiParent.Handle);
576 XplatUI.InvalidateNC (form.Handle);
580 protected virtual void HandleTitleBarUp (int x, int y)
582 title_buttons.MouseUp (x, y);
587 protected virtual void HandleTitleBarDown (int x, int y)
589 title_buttons.MouseDown (x, y);
591 if (!TitleButtons.AnyPushedTitleButtons && !IsMaximized) {
592 state = State.Moving;
593 clicked_point = new Point (x, y);
594 if (form.Parent != null) {
595 form.CaptureWithConfine (form.Parent);
601 XplatUI.InvalidateNC (form.Handle);
604 private bool HandleMouseMove (Form form, ref Message m)
608 HandleWindowMove (m);
618 private void HandleMouseLeave (ref Message m)
623 protected virtual void HandleWindowMove (Message m)
625 Point move = MouseMove (m);
627 UpdateVP (virtual_position.X + move.X, virtual_position.Y + move.Y,
628 virtual_position.Width, virtual_position.Height);
631 private void HandleSizing (Message m)
633 Rectangle pos = virtual_position;
634 Size minimum_size = SystemInformation.MinWindowTrackSize;
635 int mw = minimum_size.Width;
636 int mh = minimum_size.Height;
637 int x = Cursor.Position.X;
638 int y = Cursor.Position.Y;
640 PointToClient (ref x, ref y);
642 if ((sizing_edge & FormPos.Top) != 0) {
643 if (pos.Bottom - y < mh)
645 pos.Height = pos.Bottom - y;
647 } else if ((sizing_edge & FormPos.Bottom) != 0) {
648 int height = y - pos.Top;
654 if ((sizing_edge & FormPos.Left) != 0) {
655 if (pos.Right - x < mw)
657 pos.Width = pos.Right - x;
659 } else if ((sizing_edge & FormPos.Right) != 0) {
660 int width = x - form.Left;
669 public bool IsMaximized {
670 get { return GetWindowState () == FormWindowState.Maximized; }
673 public bool IsMinimized {
674 get { return GetWindowState () == FormWindowState.Minimized; }
677 public bool IsSizable {
679 switch (form.FormBorderStyle) {
680 case FormBorderStyle.Sizable:
681 case FormBorderStyle.SizableToolWindow:
682 return (form.window_state != FormWindowState.Minimized);
689 public bool HasBorders {
691 return form.FormBorderStyle != FormBorderStyle.None;
695 public bool IsToolWindow {
697 if (form.FormBorderStyle == FormBorderStyle.SizableToolWindow ||
698 form.FormBorderStyle == FormBorderStyle.FixedToolWindow)
704 public int TitleBarHeight {
706 return ThemeEngine.Current.ManagedWindowTitleBarHeight (this);
710 public int BorderWidth {
712 return ThemeEngine.Current.ManagedWindowBorderWidth (this);
716 public virtual int MenuHeight {
718 return (form.Menu != null ? ThemeEngine.Current.MenuHeight : 0);
722 protected void UpdateVP (Rectangle r)
724 UpdateVP (r.X, r.Y, r.Width, r.Height);
727 protected void UpdateVP (Point loc, int w, int h)
729 UpdateVP (loc.X, loc.Y, w, h);
732 protected void UpdateVP (int x, int y, int w, int h)
734 virtual_position.X = x;
735 virtual_position.Y = y;
736 virtual_position.Width = w;
737 virtual_position.Height = h;
739 DrawVirtualPosition (virtual_position);
742 protected virtual void HandleLButtonUp (ref Message m)
744 if (state == State.Idle)
747 ClearVirtualPosition ();
749 form.Capture = false;
750 if (state == State.Moving && form.Location != virtual_position.Location)
751 form.Location = virtual_position.Location;
752 else if (state == State.Sizing && form.Bounds != virtual_position)
753 form.Bounds = virtual_position;
756 OnWindowFinishedMoving ();
759 private bool HandleNCLButtonUp (ref Message m)
762 ClearVirtualPosition ();
764 form.Capture = false;
766 if (form.MdiContainer != null)
767 form.MdiContainer.SizeScrollBars();
770 int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
771 int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
773 NCPointToClient (ref x, ref y);
774 FormPos pos = FormPosForCoords (x, y);
776 if (pos == FormPos.TitleBar) {
777 HandleTitleBarUp (x, y);
784 protected void DrawTitleButton (Graphics dc, TitleButton button, Rectangle clip)
786 if (!button.Rectangle.IntersectsWith (clip))
789 dc.FillRectangle (SystemBrushes.Control, button.Rectangle);
790 ControlPaint.DrawCaptionButton (dc, button.Rectangle,
791 button.Caption, button.State);
794 public virtual void DrawMaximizedButtons (object sender, PaintEventArgs pe)
798 protected Point MouseMove (Message m)
800 Point cp = Cursor.Position;
801 return new Point (cp.X - start.X, cp.Y - start.Y);
804 protected virtual void DrawVirtualPosition (Rectangle virtual_position)
806 form.Bounds = virtual_position;
807 start = Cursor.Position;
810 protected virtual void ClearVirtualPosition ()
815 protected virtual void OnWindowFinishedMoving ()
819 protected virtual void NCPointToClient(ref int x, ref int y) {
820 form.PointToClient(ref x, ref y);
821 NCClientToNC (ref x, ref y);
824 protected virtual void NCClientToNC (ref int x, ref int y) {
830 internal Point GetMenuOrigin ()
832 return new Point (BorderWidth, BorderWidth + TitleBarHeight);
835 protected FormPos FormPosForCoords (int x, int y)
837 int bw = BorderWidth;
838 if (y < TitleBarHeight + bw) {
839 // Console.WriteLine ("A");
840 if (y > bw && x > bw &&
842 return FormPos.TitleBar;
844 if (x < bw || (x < 20 && y < bw))
845 return FormPos.TopLeft;
847 if (x > form.Width - bw ||
848 (x > form.Width - 20 && y < bw))
849 return FormPos.TopRight;
854 } else if (y > form.Height - 20) {
855 // Console.WriteLine ("B");
857 (x < 20 && y > form.Height - bw))
858 return FormPos.BottomLeft;
860 if (x > form.Width - (bw * 2) ||
861 (x > form.Width - 20 &&
862 y > form.Height - bw))
863 return FormPos.BottomRight;
865 if (y > form.Height - (bw * 2))
866 return FormPos.Bottom;
870 // Console.WriteLine ("C");
872 } else if (x > form.Width - (bw * 2)) {
873 // Console.WriteLine ("D");
874 return FormPos.Right;
876 // Console.WriteLine ("E {0}", form.Width - bw);
882 internal class TitleButton
884 public Rectangle Rectangle;
885 public ButtonState State;
886 public CaptionButton Caption;
887 private EventHandler Clicked;
890 public TitleButton (CaptionButton caption, EventHandler clicked)
896 public void OnClick ()
898 if (Clicked != null) {
899 Clicked (this, EventArgs.Empty);
904 internal class TitleButtons : System.Collections.IEnumerable
906 public TitleButton MinimizeButton;
907 public TitleButton MaximizeButton;
908 public TitleButton RestoreButton;
909 public TitleButton CloseButton;
910 public TitleButton HelpButton;
912 public TitleButton [] AllButtons;
915 private ToolTip.ToolTipWindow tooltip;
916 private Timer tooltip_timer;
917 private TitleButton tooltip_hovered_button;
918 private TitleButton tooltip_hidden_button;
919 private const int tooltip_hide_interval = 3000;
920 private const int tooltip_show_interval = 1000;
923 public TitleButtons (Form frm)
928 MinimizeButton = new TitleButton (CaptionButton.Minimize, new EventHandler (ClickHandler));
929 MaximizeButton = new TitleButton (CaptionButton.Maximize, new EventHandler (ClickHandler));
930 RestoreButton = new TitleButton (CaptionButton.Restore, new EventHandler (ClickHandler));
931 CloseButton = new TitleButton (CaptionButton.Close, new EventHandler (ClickHandler));
932 HelpButton = new TitleButton (CaptionButton.Help, new EventHandler (ClickHandler));
934 AllButtons = new TitleButton [] { MinimizeButton, MaximizeButton, RestoreButton, CloseButton, HelpButton };
937 private void ClickHandler (object sender, EventArgs e)
943 TitleButton button = (TitleButton) sender;
945 switch (button.Caption) {
946 case CaptionButton.Close:
949 case CaptionButton.Help:
950 Console.WriteLine ("Help not implemented.");
952 case CaptionButton.Maximize:
953 form.WindowState = FormWindowState.Maximized;
955 case CaptionButton.Minimize:
956 form.WindowState = FormWindowState.Minimized;
958 case CaptionButton.Restore:
959 form.WindowState = FormWindowState.Normal;
964 public TitleButton FindButton (int x, int y)
970 foreach (TitleButton button in AllButtons) {
971 if (button.Visible && button.Rectangle.Contains (x, y)) {
978 public bool AnyPushedTitleButtons {
984 foreach (TitleButton button in AllButtons) {
985 if (button.Visible && button.State == ButtonState.Pushed) {
993 #region IEnumerable Members
995 public System.Collections.IEnumerator GetEnumerator ()
997 return AllButtons.GetEnumerator ();
1001 #region ToolTip helpers
1002 // Called from MouseMove if mouse is over a button
1003 public void ToolTipStart (TitleButton button)
1005 tooltip_hovered_button = button;
1007 if (tooltip_hovered_button == tooltip_hidden_button)
1009 tooltip_hidden_button = null;
1011 if (tooltip != null && tooltip.Visible)
1014 if (tooltip_timer == null) {
1016 tooltip_timer = new Timer ();
1017 tooltip_timer.Tick += new EventHandler (ToolTipTimerTick);
1020 tooltip_timer.Interval = tooltip_show_interval;
1021 tooltip_timer.Start ();
1022 tooltip_hovered_button = button;
1025 public void ToolTipTimerTick (object sender, EventArgs e)
1027 if (tooltip_timer.Interval == tooltip_hide_interval) {
1028 tooltip_hidden_button = tooltip_hovered_button;
1029 ToolTipHide (false);
1031 ToolTipShow (false);
1034 // Called from timer (with only_refresh = false)
1035 // Called from ToolTipStart if tooltip is already shown (with only_refresh = true)
1036 public void ToolTipShow (bool only_refresh)
1041 string text = Locale.GetText (tooltip_hovered_button.Caption.ToString ());
1043 tooltip_timer.Interval = tooltip_hide_interval;
1044 tooltip_timer.Enabled = true;
1046 if (only_refresh && (tooltip == null || !tooltip.Visible)) {
1050 if (tooltip == null)
1051 tooltip = new ToolTip.ToolTipWindow ();
1052 else if (tooltip.Text == text && tooltip.Visible)
1054 else if (tooltip.Visible)
1055 tooltip.Visible = false;
1057 if (form.WindowState == FormWindowState.Maximized && form.MdiParent != null)
1058 tooltip.Present (form.MdiParent, text);
1060 tooltip.Present (form, text);
1064 // Called from MouseLeave (with reset_hidden_button = true)
1065 // Called from MouseDown (with reset_hidden_button = false)
1066 // Called from MouseMove if mouse isn't over any button (with reset_hidden_button = false)
1067 // Called from Timer if hiding (with reset_hidden_button = false)
1068 public void ToolTipHide (bool reset_hidden_button)
1070 if (tooltip_timer != null)
1071 tooltip_timer.Enabled = false;
1072 if (tooltip != null && tooltip.Visible)
1073 tooltip.Visible = false;
1074 if (reset_hidden_button)
1075 tooltip_hidden_button = null;
1079 public bool MouseMove (int x, int y)
1085 bool any_change = false;
1086 bool any_pushed_buttons = AnyPushedTitleButtons;
1087 bool any_tooltip = false;
1088 TitleButton over_button = FindButton (x, y);
1090 foreach (TitleButton button in this) {
1094 if (button == over_button) {
1095 if (any_pushed_buttons) {
1096 any_change |= button.State != ButtonState.Pushed;
1097 button.State = ButtonState.Pushed;
1099 ToolTipStart (button);
1102 if (any_pushed_buttons) {
1103 any_change |= button.State != ButtonState.Normal;
1104 button.State = ButtonState.Normal;
1110 ToolTipHide (false);
1115 public void MouseDown (int x, int y)
1121 ToolTipHide (false);
1123 foreach (TitleButton button in this) {
1124 if (button != null) {
1125 button.State = ButtonState.Normal;
1128 TitleButton clicked_button = FindButton (x, y);
1129 if (clicked_button != null) {
1130 clicked_button.State = ButtonState.Pushed;
1134 public void MouseUp (int x, int y)
1140 TitleButton clicked_button = FindButton (x, y);
1141 if (clicked_button != null) {
1142 clicked_button.OnClick ();
1145 foreach (TitleButton button in this) {
1149 button.State = ButtonState.Normal;
1152 if (clicked_button == CloseButton && !form.closing)
1153 XplatUI.InvalidateNC (form.Handle);
1156 internal void MouseLeave (int x, int y)
1162 foreach (TitleButton button in this) {
1166 button.State = ButtonState.Normal;