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 if (HasBorders || IsMinimized) {
263 // clip region is not correct on win32.
264 // use the entire form's area.
265 clip = new Rectangle (0, 0, form.Width, form.Height);
266 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 if (XplatUI.RequiresPositiveClientAreaSize) {
307 // This is necessary for Linux, can't handle <= 0-sized
308 // client areas correctly.
309 if (proposed_window_rect.right <= proposed_window_rect.left) {
310 proposed_window_rect.right += proposed_window_rect.left - proposed_window_rect.right + 1;
312 if (proposed_window_rect.top >= proposed_window_rect.bottom) {
313 proposed_window_rect.bottom += proposed_window_rect.top - proposed_window_rect.bottom + 1;
317 return proposed_window_rect;
320 protected virtual bool HandleNCHitTest (ref Message m)
323 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
324 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
326 NCPointToClient (ref x, ref y);
328 FormPos pos = FormPosForCoords (x, y);
330 if (pos == FormPos.TitleBar) {
331 m.Result = new IntPtr ((int)HitTest.HTCAPTION);
340 m.Result = new IntPtr ((int)HitTest.HTTOP);
343 m.Result = new IntPtr ((int)HitTest.HTLEFT);
346 m.Result = new IntPtr ((int)HitTest.HTRIGHT);
349 m.Result = new IntPtr ((int)HitTest.HTBOTTOM);
351 case FormPos.TopLeft:
352 m.Result = new IntPtr ((int)HitTest.HTTOPLEFT);
354 case FormPos.TopRight:
355 m.Result = new IntPtr ((int)HitTest.HTTOPRIGHT);
357 case FormPos.BottomLeft:
358 m.Result = new IntPtr ((int)HitTest.HTBOTTOMLEFT);
360 case FormPos.BottomRight:
361 m.Result = new IntPtr ((int)HitTest.HTBOTTOMRIGHT);
364 // We return false so that DefWndProc handles things
370 public virtual void UpdateBorderStyle (FormBorderStyle border_style)
372 if (form.IsHandleCreated) {
373 XplatUI.SetBorderStyle (form.Handle, border_style);
376 if (ShouldRemoveWindowManager (border_style)) {
377 form.RemoveWindowManager ();
381 ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
386 public virtual void SetWindowState (FormWindowState old_state, FormWindowState window_state)
388 UpdateWindowState (old_state, window_state, false);
391 public virtual FormWindowState GetWindowState ()
393 return form.window_state;
396 public virtual void PointToClient (ref int x, ref int y)
398 // toolwindows stay in screencoords we just have to make sure
399 // they obey the working area
400 Rectangle working = SystemInformation.WorkingArea;
402 if (x > working.Right)
404 if (x < working.Left)
409 if (y > working.Bottom)
413 public virtual void PointToScreen (ref int x, ref int y)
415 XplatUI.ClientToScreen (form.Handle, ref x, ref y);
418 protected virtual bool ShouldRemoveWindowManager (FormBorderStyle style)
420 return style != FormBorderStyle.FixedToolWindow && style != FormBorderStyle.SizableToolWindow;
423 public bool IconRectangleContains (int x, int y)
428 Rectangle icon = ThemeEngine.Current.ManagedWindowGetTitleBarIconArea (this);
429 return icon.Contains (x, y);
432 public bool ShowIcon {
442 if (IsToolWindow || Form.FormBorderStyle == FormBorderStyle.FixedDialog)
448 protected virtual void Activate ()
453 public virtual bool IsActive {
460 private void FormSizeChangedHandler (object sender, EventArgs e)
462 if (form.IsHandleCreated) {
463 ThemeEngine.Current.ManagedWindowSetButtonLocations (this);
464 XplatUI.InvalidateNC (form.Handle);
468 protected virtual bool HandleRButtonDown (ref Message m)
474 protected virtual bool HandleLButtonDown (ref Message m)
480 protected virtual bool HandleLButtonDblClick(ref Message m)
485 protected virtual bool HandleNCMouseLeave (ref Message m)
487 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
488 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
490 NCPointToClient (ref x, ref y);
491 FormPos pos = FormPosForCoords (x, y);
493 if (pos != FormPos.TitleBar) {
494 HandleTitleBarLeave (x, y);
501 protected virtual bool HandleNCMouseMove (ref Message m)
503 int x = Control.LowOrder((int)m.LParam.ToInt32( ));
504 int y = Control.HighOrder((int)m.LParam.ToInt32( ));
506 NCPointToClient (ref x, ref y);
507 FormPos pos = FormPosForCoords (x, y);
509 if (pos == FormPos.TitleBar) {
510 HandleTitleBarMouseMove (x, y);
514 if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) {
515 MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y, 0);
516 form.ActiveMenu.OnMouseMove (form, mea);
523 protected virtual bool HandleNCLButtonDown (ref Message m)
527 start = Cursor.Position;
528 virtual_position = form.Bounds;
530 int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
531 int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
533 // Need to adjust because we are in NC land
534 NCPointToClient (ref x, ref y);
535 FormPos pos = FormPosForCoords (x, y);
537 if (form.ActiveMenu != null && XplatUI.IsEnabled (form.Handle)) {
538 MouseEventArgs mea = new MouseEventArgs (Form.FromParamToMouseButtons (m.WParam.ToInt32 ()), form.mouse_clicks, x, y - TitleBarHeight, 0);
539 form.ActiveMenu.OnMouseDown (form, mea);
542 if (pos == FormPos.TitleBar) {
543 HandleTitleBarDown (x, y);
548 if ((pos & FormPos.AnyEdge) == 0)
551 virtual_position = form.Bounds;
552 state = State.Sizing;
561 protected virtual void HandleNCLButtonDblClick (ref Message m)
563 int x = Control.LowOrder ((int)m.LParam.ToInt32 ());
564 int y = Control.HighOrder ((int)m.LParam.ToInt32 ());
566 // Need to adjust because we are in NC land
567 NCPointToClient (ref x, ref y);
569 FormPos pos = FormPosForCoords (x, y);
570 if (pos == FormPos.TitleBar || pos == FormPos.Top)
571 HandleTitleBarDoubleClick (x, y);
575 protected virtual void HandleTitleBarDoubleClick (int x, int y)
580 protected virtual void HandleTitleBarLeave (int x, int y)
582 title_buttons.MouseLeave (x, y);
585 protected virtual void HandleTitleBarMouseMove (int x, int y)
587 bool any_change = false;
589 any_change = title_buttons.MouseMove (x, y);
592 if (IsMaximized && form.IsMdiChild)
593 XplatUI.InvalidateNC (form.MdiParent.Handle);
595 XplatUI.InvalidateNC (form.Handle);
599 protected virtual void HandleTitleBarUp (int x, int y)
601 title_buttons.MouseUp (x, y);
606 protected virtual void HandleTitleBarDown (int x, int y)
608 title_buttons.MouseDown (x, y);
610 if (!TitleButtons.AnyPushedTitleButtons && !IsMaximized) {
611 state = State.Moving;
612 clicked_point = new Point (x, y);
613 if (form.Parent != null) {
614 form.CaptureWithConfine (form.Parent);
620 XplatUI.InvalidateNC (form.Handle);
623 private bool HandleMouseMove (Form form, ref Message m)
627 HandleWindowMove (m);
637 private void HandleMouseLeave (ref Message m)
642 protected virtual void HandleWindowMove (Message m)
644 Point move = MouseMove (m);
646 UpdateVP (virtual_position.X + move.X, virtual_position.Y + move.Y,
647 virtual_position.Width, virtual_position.Height);
650 private void HandleSizing (Message m)
652 Rectangle pos = virtual_position;
653 Size minimum_size = SystemInformation.MinWindowTrackSize;
654 int mw = minimum_size.Width;
655 int mh = minimum_size.Height;
656 int x = Cursor.Position.X;
657 int y = Cursor.Position.Y;
659 PointToClient (ref x, ref y);
661 if ((sizing_edge & FormPos.Top) != 0) {
662 if (pos.Bottom - y < mh)
664 pos.Height = pos.Bottom - y;
666 } else if ((sizing_edge & FormPos.Bottom) != 0) {
667 int height = y - pos.Top;
673 if ((sizing_edge & FormPos.Left) != 0) {
674 if (pos.Right - x < mw)
676 pos.Width = pos.Right - x;
678 } else if ((sizing_edge & FormPos.Right) != 0) {
679 int width = x - form.Left;
688 public bool IsMaximized {
689 get { return GetWindowState () == FormWindowState.Maximized; }
692 public bool IsMinimized {
693 get { return GetWindowState () == FormWindowState.Minimized; }
696 public bool IsSizable {
698 switch (form.FormBorderStyle) {
699 case FormBorderStyle.Sizable:
700 case FormBorderStyle.SizableToolWindow:
701 return (form.window_state != FormWindowState.Minimized);
708 public bool HasBorders {
710 return form.FormBorderStyle != FormBorderStyle.None;
714 public bool IsToolWindow {
716 if (form.FormBorderStyle == FormBorderStyle.SizableToolWindow ||
717 form.FormBorderStyle == FormBorderStyle.FixedToolWindow ||
718 form.GetCreateParams().IsSet (WindowExStyles.WS_EX_TOOLWINDOW))
724 public int TitleBarHeight {
726 return ThemeEngine.Current.ManagedWindowTitleBarHeight (this);
730 public int BorderWidth {
732 return ThemeEngine.Current.ManagedWindowBorderWidth (this);
736 public virtual int MenuHeight {
738 return (form.Menu != null ? ThemeEngine.Current.MenuHeight : 0);
742 protected void UpdateVP (Rectangle r)
744 UpdateVP (r.X, r.Y, r.Width, r.Height);
747 protected void UpdateVP (Point loc, int w, int h)
749 UpdateVP (loc.X, loc.Y, w, h);
752 protected void UpdateVP (int x, int y, int w, int h)
754 virtual_position.X = x;
755 virtual_position.Y = y;
756 virtual_position.Width = w;
757 virtual_position.Height = h;
759 DrawVirtualPosition (virtual_position);
762 protected virtual void HandleLButtonUp (ref Message m)
764 if (state == State.Idle)
767 ClearVirtualPosition ();
769 form.Capture = false;
770 if (state == State.Moving && form.Location != virtual_position.Location)
771 form.Location = virtual_position.Location;
772 else if (state == State.Sizing && form.Bounds != virtual_position)
773 form.Bounds = virtual_position;
776 OnWindowFinishedMoving ();
779 private bool HandleNCLButtonUp (ref Message m)
782 ClearVirtualPosition ();
784 form.Capture = false;
786 if (form.MdiContainer != null)
787 form.MdiContainer.SizeScrollBars();
790 int x = Control.LowOrder ((int) m.LParam.ToInt32 ());
791 int y = Control.HighOrder ((int) m.LParam.ToInt32 ());
793 NCPointToClient (ref x, ref y);
794 FormPos pos = FormPosForCoords (x, y);
796 if (pos == FormPos.TitleBar) {
797 HandleTitleBarUp (x, y);
804 protected void DrawTitleButton (Graphics dc, TitleButton button, Rectangle clip)
806 if (!button.Rectangle.IntersectsWith (clip))
809 dc.FillRectangle (SystemBrushes.Control, button.Rectangle);
810 ControlPaint.DrawCaptionButton (dc, button.Rectangle,
811 button.Caption, button.State);
814 public virtual void DrawMaximizedButtons (object sender, PaintEventArgs pe)
818 protected Point MouseMove (Message m)
820 Point cp = Cursor.Position;
821 return new Point (cp.X - start.X, cp.Y - start.Y);
824 protected virtual void DrawVirtualPosition (Rectangle virtual_position)
826 form.Bounds = virtual_position;
827 start = Cursor.Position;
830 protected virtual void ClearVirtualPosition ()
835 protected virtual void OnWindowFinishedMoving ()
839 protected virtual void NCPointToClient(ref int x, ref int y) {
840 form.PointToClient(ref x, ref y);
841 NCClientToNC (ref x, ref y);
844 protected virtual void NCClientToNC (ref int x, ref int y) {
850 internal Point GetMenuOrigin ()
852 return new Point (BorderWidth, BorderWidth + TitleBarHeight);
855 protected FormPos FormPosForCoords (int x, int y)
857 int bw = BorderWidth;
858 if (y < TitleBarHeight + bw) {
859 // Console.WriteLine ("A");
860 if (y > bw && x > bw &&
862 return FormPos.TitleBar;
864 if (x < bw || (x < 20 && y < bw))
865 return FormPos.TopLeft;
867 if (x > form.Width - bw ||
868 (x > form.Width - 20 && y < bw))
869 return FormPos.TopRight;
874 } else if (y > form.Height - 20) {
875 // Console.WriteLine ("B");
877 (x < 20 && y > form.Height - bw))
878 return FormPos.BottomLeft;
880 if (x > form.Width - (bw * 2) ||
881 (x > form.Width - 20 &&
882 y > form.Height - bw))
883 return FormPos.BottomRight;
885 if (y > form.Height - (bw * 2))
886 return FormPos.Bottom;
890 // Console.WriteLine ("C");
892 } else if (x > form.Width - (bw * 2)) {
893 // Console.WriteLine ("D");
894 return FormPos.Right;
896 // Console.WriteLine ("E {0}", form.Width - bw);
902 internal class TitleButton
904 public Rectangle Rectangle;
905 public ButtonState State;
906 public CaptionButton Caption;
907 private EventHandler Clicked;
910 public TitleButton (CaptionButton caption, EventHandler clicked)
916 public void OnClick ()
918 if (Clicked != null) {
919 Clicked (this, EventArgs.Empty);
924 internal class TitleButtons : System.Collections.IEnumerable
926 public TitleButton MinimizeButton;
927 public TitleButton MaximizeButton;
928 public TitleButton RestoreButton;
929 public TitleButton CloseButton;
930 public TitleButton HelpButton;
932 public TitleButton [] AllButtons;
935 private ToolTip.ToolTipWindow tooltip;
936 private Timer tooltip_timer;
937 private TitleButton tooltip_hovered_button;
938 private TitleButton tooltip_hidden_button;
939 private const int tooltip_hide_interval = 3000;
940 private const int tooltip_show_interval = 1000;
943 public TitleButtons (Form frm)
948 MinimizeButton = new TitleButton (CaptionButton.Minimize, new EventHandler (ClickHandler));
949 MaximizeButton = new TitleButton (CaptionButton.Maximize, new EventHandler (ClickHandler));
950 RestoreButton = new TitleButton (CaptionButton.Restore, new EventHandler (ClickHandler));
951 CloseButton = new TitleButton (CaptionButton.Close, new EventHandler (ClickHandler));
952 HelpButton = new TitleButton (CaptionButton.Help, new EventHandler (ClickHandler));
954 AllButtons = new TitleButton [] { MinimizeButton, MaximizeButton, RestoreButton, CloseButton, HelpButton };
957 private void ClickHandler (object sender, EventArgs e)
963 TitleButton button = (TitleButton) sender;
965 switch (button.Caption) {
966 case CaptionButton.Close:
969 case CaptionButton.Help:
970 Console.WriteLine ("Help not implemented.");
972 case CaptionButton.Maximize:
973 form.WindowState = FormWindowState.Maximized;
975 case CaptionButton.Minimize:
976 form.WindowState = FormWindowState.Minimized;
978 case CaptionButton.Restore:
979 form.WindowState = FormWindowState.Normal;
984 public TitleButton FindButton (int x, int y)
990 foreach (TitleButton button in AllButtons) {
991 if (button.Visible && button.Rectangle.Contains (x, y)) {
998 public bool AnyPushedTitleButtons {
1004 foreach (TitleButton button in AllButtons) {
1005 if (button.Visible && button.State == ButtonState.Pushed) {
1013 #region IEnumerable Members
1015 public System.Collections.IEnumerator GetEnumerator ()
1017 return AllButtons.GetEnumerator ();
1021 #region ToolTip helpers
1022 // Called from MouseMove if mouse is over a button
1023 public void ToolTipStart (TitleButton button)
1025 tooltip_hovered_button = button;
1027 if (tooltip_hovered_button == tooltip_hidden_button)
1029 tooltip_hidden_button = null;
1031 if (tooltip != null && tooltip.Visible)
1034 if (tooltip_timer == null) {
1036 tooltip_timer = new Timer ();
1037 tooltip_timer.Tick += new EventHandler (ToolTipTimerTick);
1040 tooltip_timer.Interval = tooltip_show_interval;
1041 tooltip_timer.Start ();
1042 tooltip_hovered_button = button;
1045 public void ToolTipTimerTick (object sender, EventArgs e)
1047 if (tooltip_timer.Interval == tooltip_hide_interval) {
1048 tooltip_hidden_button = tooltip_hovered_button;
1049 ToolTipHide (false);
1051 ToolTipShow (false);
1054 // Called from timer (with only_refresh = false)
1055 // Called from ToolTipStart if tooltip is already shown (with only_refresh = true)
1056 public void ToolTipShow (bool only_refresh)
1061 string text = Locale.GetText (tooltip_hovered_button.Caption.ToString ());
1063 tooltip_timer.Interval = tooltip_hide_interval;
1064 tooltip_timer.Enabled = true;
1066 if (only_refresh && (tooltip == null || !tooltip.Visible)) {
1070 if (tooltip == null)
1071 tooltip = new ToolTip.ToolTipWindow ();
1072 else if (tooltip.Text == text && tooltip.Visible)
1074 else if (tooltip.Visible)
1075 tooltip.Visible = false;
1077 if (form.WindowState == FormWindowState.Maximized && form.MdiParent != null)
1078 tooltip.Present (form.MdiParent, text);
1080 tooltip.Present (form, text);
1084 // Called from MouseLeave (with reset_hidden_button = true)
1085 // Called from MouseDown (with reset_hidden_button = false)
1086 // Called from MouseMove if mouse isn't over any button (with reset_hidden_button = false)
1087 // Called from Timer if hiding (with reset_hidden_button = false)
1088 public void ToolTipHide (bool reset_hidden_button)
1090 if (tooltip_timer != null)
1091 tooltip_timer.Enabled = false;
1092 if (tooltip != null && tooltip.Visible)
1093 tooltip.Visible = false;
1094 if (reset_hidden_button)
1095 tooltip_hidden_button = null;
1099 public bool MouseMove (int x, int y)
1105 bool any_change = false;
1106 bool any_pushed_buttons = AnyPushedTitleButtons;
1107 bool any_tooltip = false;
1108 TitleButton over_button = FindButton (x, y);
1110 foreach (TitleButton button in this) {
1114 if (button == over_button) {
1115 if (any_pushed_buttons) {
1116 any_change |= button.State != ButtonState.Pushed;
1117 button.State = ButtonState.Pushed;
1119 ToolTipStart (button);
1122 if (any_pushed_buttons) {
1123 any_change |= button.State != ButtonState.Normal;
1124 button.State = ButtonState.Normal;
1130 ToolTipHide (false);
1135 public void MouseDown (int x, int y)
1141 ToolTipHide (false);
1143 foreach (TitleButton button in this) {
1144 if (button != null) {
1145 button.State = ButtonState.Normal;
1148 TitleButton clicked_button = FindButton (x, y);
1149 if (clicked_button != null) {
1150 clicked_button.State = ButtonState.Pushed;
1154 public void MouseUp (int x, int y)
1160 TitleButton clicked_button = FindButton (x, y);
1161 if (clicked_button != null) {
1162 clicked_button.OnClick ();
1165 foreach (TitleButton button in this) {
1169 button.State = ButtonState.Normal;
1172 if (clicked_button == CloseButton && !form.closing)
1173 XplatUI.InvalidateNC (form.Handle);
1176 internal void MouseLeave (int x, int y)
1182 foreach (TitleButton button in this) {
1186 button.State = ButtonState.Normal;