* TabControl.cs: Show the tooltip depending on the value
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ScrollableControl.cs
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:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
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.
19 //
20 // Copyright (c) 2004 Novell, Inc.
21 //
22 // Authors:
23 //      Peter Bartok    pbartok@novell.com
24 //
25
26 using System;
27 using System.ComponentModel;
28 using System.ComponentModel.Design;
29 using System.Drawing;
30 using System.Runtime.InteropServices;
31
32 namespace System.Windows.Forms {
33         [Designer ("System.Windows.Forms.Design.ScrollableControlDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
34 #if NET_2_0
35         [ClassInterface (ClassInterfaceType.AutoDispatch)]
36         [ComVisible (true)]
37 #endif
38         public class ScrollableControl : Control {
39                 #region Local Variables
40                 private bool                    force_hscroll_visible;
41                 private bool                    force_vscroll_visible;
42                 private bool                    auto_scroll;
43                 private Size                    auto_scroll_margin;
44                 private Size                    auto_scroll_min_size;
45                 private Point                   scroll_position;
46                 private DockPaddingEdges        dock_padding;
47                 private SizeGrip                sizegrip;
48                 internal ImplicitHScrollBar     hscrollbar;
49                 internal ImplicitVScrollBar     vscrollbar;
50                 internal Size                   canvas_size;
51                 private Rectangle               display_rectangle;
52                 private Control                 old_parent;
53
54 #if NET_2_0
55                 private HScrollProperties       horizontalScroll;
56                 private VScrollProperties       verticalScroll;
57 #endif
58                 #endregion      // Local Variables
59
60                 [TypeConverter(typeof(ScrollableControl.DockPaddingEdgesConverter))]
61                 #region Subclass DockPaddingEdges
62                 public class DockPaddingEdges : ICloneable
63                 {
64                         private Control owner;
65                         
66 #if NET_2_0
67                         internal DockPaddingEdges (Control owner)
68                         {
69                                 this.owner = owner;
70                         }
71
72                         #region DockPaddingEdges Public Instance Properties
73                         [RefreshProperties (RefreshProperties.All)]
74                         public int All {
75                                 get { return owner.Padding.All; }
76                                 set { owner.Padding = new Padding (value); }
77                         }
78
79                         [RefreshProperties (RefreshProperties.All)]
80                         public int Bottom {
81                                 get { return owner.Padding.Bottom; }
82                                 set { owner.Padding = new Padding (Left, Top, Right, value); }
83                         }
84
85                         [RefreshProperties (RefreshProperties.All)]
86                         public int Left {
87                                 get { return owner.Padding.Left; }
88                                 set { owner.Padding = new Padding (value, Top, Right, Bottom); }
89                         }
90
91                         [RefreshProperties (RefreshProperties.All)]
92                         public int Right {
93                                 get { return owner.Padding.Right; }
94                                 set { owner.Padding = new Padding (Left, Top, value, Bottom); }
95                         }
96
97                         [RefreshProperties (RefreshProperties.All)]
98                         public int Top {
99                                 get { return owner.Padding.Top; }
100                                 set { owner.Padding = new Padding (Left, value, Right, Bottom); }
101                         }
102                         #endregion      // DockPaddingEdges Public Instance Properties
103
104                         // Public Instance Methods
105                         public override bool Equals (object other)
106                         {
107                                 if (!(other is DockPaddingEdges)) {
108                                         return false;
109                                 }
110
111                                 if ((this.All == ((DockPaddingEdges)other).All) && (this.Left == ((DockPaddingEdges)other).Left) &&
112                                         (this.Right == ((DockPaddingEdges)other).Right) && (this.Top == ((DockPaddingEdges)other).Top) &&
113                                         (this.Bottom == ((DockPaddingEdges)other).Bottom)) {
114                                         return true;
115                                 }
116
117                                 return false;
118                         }
119
120                         public override int GetHashCode ()
121                         {
122                                 return All * Top * Bottom * Right * Left;
123                         }
124
125                         public override string ToString ()
126                         {
127                                 return "All = " + All.ToString () + " Top = " + Top.ToString () + " Left = " + Left.ToString () + " Bottom = " + Bottom.ToString () + " Right = " + Right.ToString ();
128                         }
129
130                         internal void Scale (float dx, float dy)
131                         {
132                                 Left = (int)(Left * dx);
133                                 Right = (int)(Right * dx);
134                                 Top = (int)(Top * dy);
135                                 Bottom = (int)(Bottom * dy);
136                         }
137
138                         object ICloneable.Clone ()
139                         {
140                                 return new DockPaddingEdges (owner);
141                         }
142 #else
143                         #region DockPaddingEdges Local Variables
144                         private int     all;
145                         private int     left;
146                         private int     right;
147                         private int     top;
148                         private int     bottom;
149                         #endregion      // DockPaddingEdges Local Variables
150
151                         #region DockPaddingEdges Constructor
152                         internal DockPaddingEdges(Control owner) {
153                                 all = 0;
154                                 left = 0;
155                                 right = 0;
156                                 top = 0;
157                                 bottom = 0;
158                                 this.owner = owner;
159                         }
160                         #endregion      // DockPaddingEdges Constructor
161
162                         #region DockPaddingEdges Public Instance Properties
163                         [RefreshProperties(RefreshProperties.All)]
164                         public int All {
165                                 get {
166                                         return all;
167                                 }
168
169                                 set {
170                                         all = value;
171                                         left = value;
172                                         right = value;
173                                         top = value;
174                                         bottom = value;
175
176                                         owner.PerformLayout();
177                                 }
178                         }
179
180                         [RefreshProperties(RefreshProperties.All)]
181                         public int Bottom {
182                                 get {
183                                         return bottom;
184                                 }
185
186                                 set {
187                                         bottom = value;
188                                         all = 0;
189
190                                         owner.PerformLayout();
191                                 }
192                         }
193
194                         [RefreshProperties(RefreshProperties.All)]
195                         public int Left {
196                                 get {
197                                         return left;
198                                 }
199
200                                 set {
201                                         left=value;
202                                         all = 0;
203
204                                         owner.PerformLayout();
205                                 }
206                         }
207
208                         [RefreshProperties(RefreshProperties.All)]
209                         public int Right {
210                                 get {
211                                         return right;
212                                 }
213
214                                 set {
215                                         right=value;
216                                         all = 0;
217
218                                         owner.PerformLayout();
219                                 }
220                         }
221
222                         [RefreshProperties(RefreshProperties.All)]
223                         public int Top {
224                                 get {
225                                         return top;
226                                 }
227
228                                 set {
229                                         top=value;
230                                         all = 0;
231
232                                         owner.PerformLayout();
233                                 }
234                         }
235                         #endregion      // DockPaddingEdges Public Instance Properties
236
237                         // Public Instance Methods
238                         public override bool Equals(object other) {
239                                 if (! (other is DockPaddingEdges)) {
240                                         return false;
241                                 }
242
243                                 if (    (this.all == ((DockPaddingEdges)other).all) && (this.left == ((DockPaddingEdges)other).left) &&
244                                         (this.right == ((DockPaddingEdges)other).right) && (this.top == ((DockPaddingEdges)other).top) && 
245                                         (this.bottom == ((DockPaddingEdges)other).bottom)) {
246                                         return true;
247                                 }
248
249                                 return false;
250                         }
251
252                         public override int GetHashCode() {
253                                 return all*top*bottom*right*left;
254                         }
255
256                         public override string ToString() {
257                                 return "All = "+all.ToString()+" Top = "+top.ToString()+" Left = "+left.ToString()+" Bottom = "+bottom.ToString()+" Right = "+right.ToString();
258                         }
259
260                         internal void Scale(float dx, float dy) {
261                                 left = (int) (left * dx);
262                                 right = (int) (right * dx);
263                                 top = (int) (top * dy);
264                                 bottom = (int) (bottom * dy);
265                         }
266
267                         object ICloneable.Clone() {
268                                 DockPaddingEdges padding_edge;
269
270                                 padding_edge=new DockPaddingEdges(owner);
271
272                                 padding_edge.all=all;
273                                 padding_edge.left=left;
274                                 padding_edge.right=right;
275                                 padding_edge.top=top;
276                                 padding_edge.bottom=bottom;
277
278                                 return padding_edge;
279                         }
280 #endif
281                 }
282                 #endregion      // Subclass DockPaddingEdges
283
284                 #region Subclass DockPaddingEdgesConverter
285                 public class DockPaddingEdgesConverter : System.ComponentModel.TypeConverter {
286                         // Public Constructors
287                         public DockPaddingEdgesConverter() {
288                         }
289
290                         // Public Instance Methods
291                         public override PropertyDescriptorCollection GetProperties(System.ComponentModel.ITypeDescriptorContext context, object value, Attribute[] attributes) {
292                                 return TypeDescriptor.GetProperties(typeof(DockPaddingEdges), attributes);
293                         }
294
295                         public override bool GetPropertiesSupported(System.ComponentModel.ITypeDescriptorContext context) {
296                                 return true;
297                         }
298                 }
299                 #endregion      // Subclass DockPaddingEdgesConverter
300
301                 #region Public Constructors
302                 public ScrollableControl() {
303                         SetStyle(ControlStyles.ContainerControl, true);
304                         SetStyle(ControlStyles.AllPaintingInWmPaint, false);
305
306                         auto_scroll = false;
307                         force_hscroll_visible = false;
308                         force_vscroll_visible = false;
309                         auto_scroll_margin = new Size(0, 0);
310                         auto_scroll_min_size = new Size(0, 0);
311                         scroll_position = new Point(0, 0);
312                         SizeChanged +=new EventHandler(Recalculate);
313                         VisibleChanged += new EventHandler (VisibleChangedHandler);
314                         LocationChanged += new EventHandler (LocationChangedHandler);
315                         ParentChanged += new EventHandler (ParentChangedHandler);
316                         HandleCreated += new EventHandler (AddScrollbars);
317
318                         CreateScrollbars ();
319                         
320 #if NET_2_0
321                         horizontalScroll = new HScrollProperties (this);
322                         verticalScroll = new VScrollProperties (this);
323 #endif
324                 }
325
326                 void VisibleChangedHandler (object sender, EventArgs e)
327                 {
328                         Recalculate (false);
329                 }
330
331                 void LocationChangedHandler (object sender, EventArgs e)
332                 {
333                         UpdateSizeGripVisible ();
334                 }
335
336                 void ParentChangedHandler (object sender, EventArgs e)
337                 {
338                         
339                         if (old_parent == Parent)
340                                 return;
341                                 
342                         if (old_parent != null) {
343                                 old_parent.SizeChanged -= new EventHandler (Parent_SizeChanged);
344 #if NET_2_0                             
345                                 old_parent.PaddingChanged -= new EventHandler (Parent_PaddingChanged);
346 #endif
347                         }
348                         
349                         if (Parent != null) {
350                                 Parent.SizeChanged += new EventHandler (Parent_SizeChanged);
351 #if NET_2_0
352                                 Parent.PaddingChanged += new EventHandler (Parent_PaddingChanged);
353 #endif
354                         }
355                         
356                         old_parent = Parent;
357                 }
358 #if NET_2_0
359                 void Parent_PaddingChanged (object sender, EventArgs e)
360                 {
361                         UpdateSizeGripVisible ();
362                 }
363 #endif
364                 void Parent_SizeChanged (object sender, EventArgs e)
365                 {
366                         UpdateSizeGripVisible ();
367                 }
368                 #endregion      // Public Constructors
369
370                 #region Protected Static Fields
371                 protected const int ScrollStateAutoScrolling    = 1;
372                 protected const int ScrollStateFullDrag         = 16;
373                 protected const int ScrollStateHScrollVisible   = 2;
374                 protected const int ScrollStateUserHasScrolled  = 8;
375                 protected const int ScrollStateVScrollVisible   = 4;
376                 #endregion      // Protected Static Fields
377
378                 #region Public Instance Properties
379                 [DefaultValue(false)]
380                 [Localizable(true)]
381                 [MWFCategory("Layout")]
382                 public virtual bool AutoScroll {
383                         get {
384                                 return  auto_scroll;
385                         }
386
387                         set {
388                                 if (auto_scroll != value) {
389                                         auto_scroll = value;
390                                         PerformLayout (this, "AutoScroll");
391                                 }
392                         }
393                 }
394
395                 [Localizable(true)]
396                 [MWFCategory("Layout")]
397                 public Size AutoScrollMargin {
398                         get {
399                                 return auto_scroll_margin;
400                         }
401
402                         set {
403                                 if (value.Width < 0) {
404                                         throw new ArgumentException("Width is assigned less than 0", "value.Width");
405                                 }
406
407                                 if (value.Height < 0) {
408                                         throw new ArgumentException("Height is assigned less than 0", "value.Height");
409                                 }
410
411                                 auto_scroll_margin = value;
412                         }
413                 }
414
415                 internal bool ShouldSerializeAutoScrollMargin ()
416                 {
417                         return this.AutoScrollMargin != new Size (0, 0);
418                 }
419
420                 [Localizable(true)]
421                 [MWFCategory("Layout")]
422                 public Size AutoScrollMinSize {
423                         get {
424                                 return auto_scroll_min_size;
425                         }
426
427                         set {
428                                 if (value != auto_scroll_min_size) {
429                                         auto_scroll_min_size = value;
430                                         AutoScroll = true;
431                                         PerformLayout (this, "AutoScrollMinSize");
432                                 }
433                         }
434                 }
435
436                 internal bool ShouldSerializeAutoScrollMinSize ()
437                 {
438                         return this.AutoScrollMinSize != new Size (0, 0);
439                 }
440
441                 [Browsable(false)]
442                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
443                 public Point AutoScrollPosition {
444                         get {
445                                 return DisplayRectangle.Location;
446                         }
447
448                         set {
449                                 if (value != AutoScrollPosition) {
450                                         int     shift_x;
451                                         int     shift_y;
452
453                                         shift_x = 0;
454                                         shift_y = 0;
455                                         if (hscrollbar.VisibleInternal) {
456                                                 int max = hscrollbar.Maximum - hscrollbar.LargeChange + 1;
457                                                 value.X = value.X < hscrollbar.Minimum ? hscrollbar.Minimum : value.X;
458                                                 value.X = value.X > max ? max : value.X;
459                                                 shift_x = value.X - scroll_position.X;
460                                         }
461
462                                         if (vscrollbar.VisibleInternal) {
463                                                 int max = vscrollbar.Maximum - vscrollbar.LargeChange + 1;
464                                                 value.Y = value.Y < vscrollbar.Minimum ? vscrollbar.Minimum : value.Y;
465                                                 value.Y = value.Y > max ? max : value.Y;
466                                                 shift_y = value.Y - scroll_position.Y;
467                                         }
468
469                                         ScrollWindow(shift_x, shift_y);
470
471                                         if (hscrollbar.VisibleInternal) {
472                                                 if (scroll_position.X >= hscrollbar.Minimum && scroll_position.X <= hscrollbar.Maximum)
473                                                         hscrollbar.Value = scroll_position.X;
474                                         }
475
476                                         if (vscrollbar.VisibleInternal) {
477                                                 if (scroll_position.Y >= vscrollbar.Minimum && scroll_position.Y <= vscrollbar.Maximum)
478                                                         vscrollbar.Value = scroll_position.Y;
479                                         }
480
481                                 }
482                         }
483                 }
484
485                 public override Rectangle DisplayRectangle {
486                         get {
487                                 if (auto_scroll) {
488                                         int             width;
489                                         int             height;
490
491                                         if (canvas_size.Width <= base.DisplayRectangle.Width) {
492                                                 width = base.DisplayRectangle.Width;
493                                                 if (vscrollbar.VisibleInternal) {
494                                                         width -= vscrollbar.Width;
495                                                 }
496                                         } else {
497                                                 width = canvas_size.Width;
498                                         }
499
500                                         if (canvas_size.Height <= base.DisplayRectangle.Height) {
501                                                 height = base.DisplayRectangle.Height;
502                                                 if (hscrollbar.VisibleInternal) {
503                                                         height -= hscrollbar.Height;
504                                                 }
505                                         } else {
506                                                 height = canvas_size.Height;
507                                         }
508
509                                         display_rectangle.X = -scroll_position.X;
510                                         display_rectangle.Y = -scroll_position.Y;
511                                         display_rectangle.Width = Math.Max(auto_scroll_min_size.Width, width);
512                                         display_rectangle.Height = Math.Max(auto_scroll_min_size.Height, height);
513                                 }
514                                 else {
515                                         display_rectangle = base.DisplayRectangle;
516                                 }
517
518                                 if (dock_padding != null) {
519                                         display_rectangle.X += dock_padding.Left;
520                                         display_rectangle.Y += dock_padding.Top;
521                                         display_rectangle.Width -= dock_padding.Left + dock_padding.Right;
522                                         display_rectangle.Height -= dock_padding.Top + dock_padding.Bottom;
523                                 }
524
525                                 return display_rectangle;
526                         }
527                 }
528
529                 [MWFCategory("Layout")]
530 #if NET_2_0
531                 [Browsable (false)]
532                 [EditorBrowsable (EditorBrowsableState.Never)]
533                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
534 #else
535                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
536                 [Localizable(true)]
537 #endif
538                 public DockPaddingEdges DockPadding {
539                         get {
540                                 if (dock_padding == null)
541                                         CreateDockPadding ();
542
543                                 return dock_padding;
544                         }
545                 }
546
547 #if NET_2_0
548                 [Browsable (false)]
549                 [EditorBrowsable (EditorBrowsableState.Always)]
550                 public HScrollProperties HorizontalScroll {
551                         get { return horizontalScroll; }
552                 }
553
554                 [Browsable (false)]
555                 [EditorBrowsable (EditorBrowsableState.Always)]
556                 public VScrollProperties VerticalScroll {
557                         get { return verticalScroll; }
558                 }
559 #endif
560                 #endregion      // Public Instance Properties
561
562                 #region Protected Instance Methods
563                 protected override CreateParams CreateParams {
564                         get {
565                                 return base.CreateParams;
566                         }
567                 }
568
569                 protected bool HScroll {
570                         get {
571                                 return hscrollbar.VisibleInternal;
572                         }
573
574                         set {
575                                 if (!AutoScroll && hscrollbar.VisibleInternal != value) {
576                                         force_hscroll_visible = value;
577                                         Recalculate (false);
578                                 }
579                         }
580                 }
581
582                 protected bool VScroll {
583                         get {
584                                 return vscrollbar.VisibleInternal;
585                         }
586
587                         set {
588                                 if (!AutoScroll && vscrollbar.VisibleInternal != value) {
589                                         force_vscroll_visible = value;
590                                         Recalculate (false);
591                                 }
592                         }
593                 }
594                 #endregion      // Protected Instance Methods
595
596                 #region Public Instance Methods
597                 public void ScrollControlIntoView(Control activeControl) {
598                         int     corner_x;
599                         int     corner_y;
600
601                         Rectangle within = new Rectangle ();
602                         within.Size = ClientSize;
603                         
604                         if (!AutoScroll || (!hscrollbar.VisibleInternal && !vscrollbar.VisibleInternal)) {
605                                 return;
606                         }
607
608                         if (!Contains(activeControl)) {
609                                 return;
610                         }
611
612                         if (vscrollbar.Visible) {
613                                 within.Width -= vscrollbar.Width;
614                         }
615                         if (hscrollbar.Visible) {
616                                 within.Height -= hscrollbar.Height;
617                         }
618
619                         // Don't scroll if already visible
620                         if (within.Contains (activeControl.Location) && within.Contains (activeControl.Right, activeControl.Bottom)) {
621                                 return;
622                         }
623
624                         // If the control is above the top or the left, move it down and right until it aligns 
625                         // with the top/left.
626                         // If the control is below the bottom or to the right, move it up/left until it aligns
627                         // with the bottom/right, but do never move it further than the top/left side.
628                         int x_diff = 0, y_diff = 0;
629                         if (activeControl.Top <= 0 || activeControl.Height >= within.Height) {
630                                 y_diff = -activeControl.Top;
631                         } else if (activeControl.Bottom > within.Height) {
632                                 y_diff = within.Height - activeControl.Bottom;
633                         }
634                         if (activeControl.Left <= 0 || activeControl.Width >= within.Width) {
635                                 x_diff = -activeControl.Left;
636                         } else if (activeControl.Right > within.Width) {
637                                 x_diff = within.Width - activeControl.Right;
638                         }
639                         corner_x = hscrollbar.Value - x_diff;
640                         corner_y = vscrollbar.Value - y_diff;
641
642                         if (hscrollbar.VisibleInternal) {
643                                 if (corner_x > hscrollbar.Maximum) {
644                                         corner_x = hscrollbar.Maximum;
645                                 } else if (corner_x < hscrollbar.Minimum) {
646                                         corner_x = hscrollbar.Minimum;
647                                 }
648                                 if (corner_x != hscrollbar.Value) {
649                                         hscrollbar.Value = corner_x;
650                                 }
651                         }
652
653                         if (vscrollbar.VisibleInternal) {
654                                 if (corner_y > vscrollbar.Maximum) {
655                                         corner_y = vscrollbar.Maximum;
656                                 } else if (corner_y < vscrollbar.Minimum) {
657                                         corner_y = vscrollbar.Minimum;
658                                 }
659                                 if (corner_y != vscrollbar.Value) {
660                                         vscrollbar.Value = corner_y;
661                                 }
662                         }
663                 }
664
665                 public void SetAutoScrollMargin(int x, int y) {
666                         if (x < 0) {
667                                 x = 0;
668                         }
669
670                         if (y < 0) {
671                                 y = 0;
672                         }
673
674                         auto_scroll_margin = new Size(x, y);
675                         Recalculate (false);
676                 }
677                 #endregion      // Public Instance Methods
678
679                 #region Protected Instance Methods
680                 [EditorBrowsable(EditorBrowsableState.Advanced)]
681                 protected virtual void AdjustFormScrollbars(bool displayScrollbars) {
682                         Recalculate (false);
683                 }
684
685                 [EditorBrowsable(EditorBrowsableState.Advanced)]
686                 protected bool GetScrollState(int bit) {
687                         // Internal MS
688                         return false;
689                 }
690
691                 [EditorBrowsable(EditorBrowsableState.Advanced)]
692                 protected override void OnLayout(LayoutEventArgs levent) {
693                         CalculateCanvasSize (true);
694
695                         AdjustFormScrollbars(AutoScroll);       // Dunno what the logic is. Passing AutoScroll seems to match MS behaviour
696                         base.OnLayout(levent);
697
698 #if NET_2_0
699                         // The first time through, we just set the canvas to clientsize
700                         // so we could re-layout everything according to the flow.
701                         // This time we want to actually calculate the canvas.
702                         if (this is FlowLayoutPanel) {
703                                 CalculateCanvasSize (false);
704                                 AdjustFormScrollbars (AutoScroll);
705                         }
706 #endif
707                 }
708
709                 [EditorBrowsable(EditorBrowsableState.Advanced)]
710                 protected override void OnMouseWheel(MouseEventArgs e) {
711                         if (vscrollbar.VisibleInternal) {
712                                 if (e.Delta > 0) {
713                                         if (vscrollbar.Minimum < (vscrollbar.Value - vscrollbar.LargeChange)) {
714                                                 vscrollbar.Value -= vscrollbar.LargeChange;
715                                         } else {
716                                                 vscrollbar.Value = vscrollbar.Minimum;
717                                         }
718                                 } else {
719                                         int maximum_scrollbar_value = vscrollbar.Maximum - vscrollbar.LargeChange + 1;
720                                         if (maximum_scrollbar_value > (vscrollbar.Value + vscrollbar.LargeChange)) {
721                                                 vscrollbar.Value += vscrollbar.LargeChange;
722                                         } else {
723                                                 vscrollbar.Value = maximum_scrollbar_value;
724                                         }
725                                 }
726                         }
727                         base.OnMouseWheel(e);
728                 }
729
730                 [EditorBrowsable(EditorBrowsableState.Advanced)]
731                 protected override void OnVisibleChanged(EventArgs e) {
732                         if (Visible) {
733                                 UpdateChildrenZOrder ();
734                                 PerformLayout(this, "Visible");
735                         }
736                         base.OnVisibleChanged(e);
737                 }
738
739 #if NET_2_0
740                 [EditorBrowsable (EditorBrowsableState.Never)]
741 #endif
742                 protected override void ScaleCore(float dx, float dy) {
743                         if (dock_padding != null)
744                                 dock_padding.Scale(dx, dy);
745
746                         base.ScaleCore(dx, dy);
747                 }
748
749 #if NET_2_0
750                 protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
751                 {
752                         base.ScaleControl (factor, specified);
753                 }
754                 
755                 protected virtual Point ScrollToControl (Control activeControl)
756                 {
757                         int corner_x;
758                         int corner_y;
759
760                         Rectangle within = new Rectangle ();
761                         within.Size = ClientSize;
762
763                         if (vscrollbar.Visible)
764                                 within.Width -= vscrollbar.Width;
765
766                         if (hscrollbar.Visible)
767                                 within.Height -= hscrollbar.Height;
768
769                         // If the control is above the top or the left, move it down and right until it aligns 
770                         // with the top/left.
771                         // If the control is below the bottom or to the right, move it up/left until it aligns
772                         // with the bottom/right, but do never move it further than the top/left side.
773                         int x_diff = 0, y_diff = 0;
774                         
775                         if (activeControl.Top <= 0 || activeControl.Height >= within.Height)
776                                 y_diff = -activeControl.Top;
777                         else if (activeControl.Bottom > within.Height)
778                                 y_diff = within.Height - activeControl.Bottom;
779
780                         if (activeControl.Left <= 0 || activeControl.Width >= within.Width)
781                                 x_diff = -activeControl.Left;
782                         else if (activeControl.Right > within.Width)
783                                 x_diff = within.Width - activeControl.Right;
784
785                         corner_x = AutoScrollPosition.X + x_diff;
786                         corner_y = AutoScrollPosition.Y + y_diff;
787                         
788                         return new Point (corner_x, corner_y);
789                 }
790 #endif
791
792                 protected void SetDisplayRectLocation(int x, int y) {
793                         // This method is weird. MS documents that the scrollbars are not
794                         // updated. We need to move stuff, but leave the scrollbars as is
795
796                         if (x > 0) {
797                                 x = 0;
798                         }
799
800                         if (y > 0) {
801                                 y = 0;
802                         }
803
804                         ScrollWindow(scroll_position.X - x , scroll_position.Y - y);
805                 }
806
807                 protected void SetScrollState(int bit, bool value) {
808                         //throw new NotImplementedException();
809                 }
810
811                 [EditorBrowsable(EditorBrowsableState.Advanced)]
812                 protected override void WndProc(ref Message m) {
813                         base.WndProc(ref m);
814                 }
815                 #endregion      // Protected Instance Methods
816
817                 #region Internal & Private Methods
818                 internal override IntPtr AfterTopMostControl ()
819                 {
820                         // order of scrollbars:
821                         // top = vertical
822                         //       sizegrid
823                         // bottom = horizontal
824                         if (hscrollbar != null && hscrollbar.Visible)
825                                 return hscrollbar.Handle;
826                         // no need to check for sizegrip since it will only
827                         // be visible if hbar is visible.
828                         if (vscrollbar != null && vscrollbar.Visible)
829                                 return hscrollbar.Handle;
830
831                         return base.AfterTopMostControl ();
832                 }
833
834                 internal virtual void CalculateCanvasSize (bool canOverride) {
835                         Control         child;
836                         int             num_of_children;
837                         int             width;
838                         int             height;
839                         int             extra_width;
840                         int             extra_height;
841
842                         num_of_children = Controls.Count;
843                         width = 0;
844                         height = 0;
845                         extra_width = hscrollbar.Value;
846                         extra_height = vscrollbar.Value;
847                         if (dock_padding != null) {
848                                 extra_width += dock_padding.Right;
849                                 extra_height += dock_padding.Bottom;
850                         }
851
852                         for (int i = 0; i < num_of_children; i++) {
853                                 child = Controls[i];
854                                 if (child.Dock == DockStyle.Right) {
855                                         extra_width += child.Width;
856                                 } else if (child.Dock == DockStyle.Bottom) {
857                                         extra_height += child.Height;
858                                 }
859                         }
860
861                         if (!auto_scroll_min_size.IsEmpty) {
862                                 width = auto_scroll_min_size.Width;
863                                 height = auto_scroll_min_size.Height;
864                         }
865
866                         for (int i = 0; i < num_of_children; i++) {
867                                 child = Controls[i];
868
869                                 switch(child.Dock) {
870                                         case DockStyle.Left: {
871                                                 if ((child.Right + extra_width) > width) {
872                                                         width = child.Right + extra_width;
873                                                 }
874                                                 continue;
875                                         }
876
877                                         case DockStyle.Top: {
878                                                 if ((child.Bottom + extra_height) > height) {
879                                                         height = child.Bottom + extra_height;
880                                                 }
881                                                 continue;
882                                         }
883
884                                         case DockStyle.Fill:
885                                         case DockStyle.Right:
886                                         case DockStyle.Bottom: {
887                                                 continue;
888                                         }
889
890                                         default: {
891                                                 AnchorStyles    anchor;
892
893                                                 anchor = child.Anchor;
894
895                                                 if (((anchor & AnchorStyles.Left) != 0) && ((anchor & AnchorStyles.Right) == 0)) {
896                                                         if ((child.Right + extra_width) > width) {
897                                                                 width = child.Right + extra_width;
898                                                         }
899                                                 }
900
901                                                 if (((anchor & AnchorStyles.Top) != 0) || ((anchor & AnchorStyles.Bottom) == 0)) {
902                                                         if ((child.Bottom + extra_height) > height) {
903                                                                 height = child.Bottom + extra_height;
904                                                         }
905                                                 }
906                                                 continue;
907                                         }
908                                 }
909                         }
910
911                         canvas_size.Width = width;
912                         canvas_size.Height = height;
913                 }
914
915                 // Normally DockPadding is created lazyly, as observed in the test cases, but some children
916                 // may need to have it always.
917                 internal void CreateDockPadding ()
918                 {
919                         if (dock_padding == null)
920                                 dock_padding = new DockPaddingEdges (this);
921                 }
922
923                 private void Recalculate (object sender, EventArgs e) {
924                         Recalculate (true);
925                 }
926                                 
927                 private void Recalculate (bool doLayout) {
928                         if (!IsHandleCreated) {
929                                 return;
930                         }
931
932                         Size canvas = canvas_size;
933                         Size client = ClientSize;
934
935                         canvas.Width += auto_scroll_margin.Width;
936                         canvas.Height += auto_scroll_margin.Height;
937
938                         int right_edge = client.Width;
939                         int bottom_edge = client.Height;
940                         int prev_right_edge;
941                         int prev_bottom_edge;
942
943                         bool hscroll_visible;
944                         bool vscroll_visible;
945
946                         do {
947                                 prev_right_edge = right_edge;
948                                 prev_bottom_edge = bottom_edge;
949
950                                 if ((force_hscroll_visible || (canvas.Width > right_edge && auto_scroll)) && client.Width > 0) {
951                                         hscroll_visible = true;
952                                         bottom_edge = client.Height - SystemInformation.HorizontalScrollBarHeight;
953                                 } else {
954                                         hscroll_visible = false;
955                                         bottom_edge = client.Height;
956                                 }
957
958                                 if ((force_vscroll_visible || (canvas.Height > bottom_edge && auto_scroll)) && client.Height > 0) {
959                                         vscroll_visible = true;
960                                         right_edge = client.Width - SystemInformation.VerticalScrollBarWidth;
961                                 } else {
962                                         vscroll_visible = false;
963                                         right_edge = client.Width;
964                                 }
965
966                         } while (right_edge != prev_right_edge || bottom_edge != prev_bottom_edge);
967
968                         if (right_edge < 0) right_edge = 0;
969                         if (bottom_edge < 0) bottom_edge = 0;
970
971                         Rectangle hscroll_bounds;
972                         Rectangle vscroll_bounds;
973
974                         hscroll_bounds = new Rectangle (0, client.Height - SystemInformation.HorizontalScrollBarHeight,
975                                                         ClientRectangle.Width, SystemInformation.HorizontalScrollBarHeight);
976                         vscroll_bounds = new Rectangle (client.Width - SystemInformation.VerticalScrollBarWidth, 0,
977                                                         SystemInformation.VerticalScrollBarWidth, ClientRectangle.Height);
978
979                         /* the ScrollWindow calls here are needed
980                          * because (this explanation sucks):
981                          * 
982                          * when we transition from having a scrollbar to
983                          * not having one, we won't receive a scrollbar
984                          * moved (value changed) event, so we need to
985                          * manually scroll the canvas.
986                          * 
987                          * if you can fix this without requiring the
988                          * ScrollWindow calls, pdb and toshok will each
989                          * pay you $5.
990                         */
991
992                         if (!vscrollbar.Visible) {
993                                 vscrollbar.Value = 0;
994                         }
995                         if (!hscrollbar.Visible) {
996                                 hscrollbar.Value = 0;
997                         }
998
999                         /* Manually setting the size of the thumb should be done before
1000                          * the other assignments */
1001                         if (hscroll_visible) {
1002                                 hscrollbar.manual_thumb_size = right_edge;
1003                                 hscrollbar.LargeChange = right_edge;
1004                                 hscrollbar.SmallChange = 5;
1005                                 hscrollbar.Maximum = canvas.Width - 1;
1006                         } else {
1007                                 if (hscrollbar != null && hscrollbar.VisibleInternal) {
1008                                         ScrollWindow (- scroll_position.X, 0);
1009                                 }
1010                                 scroll_position.X = 0;
1011                         }
1012
1013                         if (vscroll_visible) {
1014                                 vscrollbar.manual_thumb_size = bottom_edge;
1015                                 vscrollbar.LargeChange = bottom_edge;
1016                                 vscrollbar.SmallChange = 5;
1017                                 vscrollbar.Maximum = canvas.Height - 1;
1018                         } else {
1019                                 if (vscrollbar != null && vscrollbar.VisibleInternal) {
1020                                         ScrollWindow (0, - scroll_position.Y);
1021                                 }
1022                                 scroll_position.Y = 0;
1023                         }
1024
1025                         if (hscroll_visible && vscroll_visible) {
1026                                 hscroll_bounds.Width -= SystemInformation.VerticalScrollBarWidth;
1027                                 vscroll_bounds.Height -= SystemInformation.HorizontalScrollBarHeight;
1028
1029                                 sizegrip.Bounds = new Rectangle (hscroll_bounds.Right,
1030                                                                  vscroll_bounds.Bottom,
1031                                                                  SystemInformation.VerticalScrollBarWidth,
1032                                                                  SystemInformation.HorizontalScrollBarHeight);
1033                         }
1034                         
1035                         SuspendLayout ();
1036
1037                         hscrollbar.SetBoundsInternal (hscroll_bounds.X, hscroll_bounds.Y, hscroll_bounds.Width, hscroll_bounds.Height, BoundsSpecified.None);
1038                         hscrollbar.Visible = hscroll_visible;
1039                         if (hscrollbar.Visible)
1040                                 XplatUI.SetZOrder (hscrollbar.Handle, IntPtr.Zero, true, false);
1041
1042                         vscrollbar.SetBoundsInternal (vscroll_bounds.X, vscroll_bounds.Y, vscroll_bounds.Width, vscroll_bounds.Height, BoundsSpecified.None);
1043                         vscrollbar.Visible = vscroll_visible;
1044                         if (vscrollbar.Visible)
1045                                 XplatUI.SetZOrder (vscrollbar.Handle, IntPtr.Zero, true, false);
1046
1047                         UpdateSizeGripVisible ();
1048
1049                         ResumeLayout (doLayout);
1050                         
1051                         // We should now scroll the active control into view, 
1052                         // the funny part is that ScrollableControl does not have 
1053                         // the concept of active control.
1054                         ContainerControl container = this as ContainerControl;
1055                         if (container != null && container.ActiveControl != null) {
1056                                 ScrollControlIntoView (container.ActiveControl);
1057                         }
1058                 }
1059
1060                 internal void UpdateSizeGripVisible ()
1061                 {
1062                         if (!IsHandleCreated) {
1063                                 return;
1064                         }
1065
1066                         sizegrip.CapturedControl = Parent;
1067                         // This is really wierd, the size grip is only showing up 
1068                         // if the bottom right corner of the scrollable control is within
1069                         // two pixels from the bottom right corner of its parent.
1070                         bool show_sizegrip = hscrollbar.VisibleInternal && vscrollbar.VisibleInternal;
1071                         bool enable_sizegrip = false;
1072                         if (show_sizegrip && Parent != null) {
1073                                 Point diff = new Point (Parent.ClientRectangle.Bottom - Bottom, Parent.ClientRectangle.Right - Right);
1074                                 enable_sizegrip = diff.X <= 2 && diff.X >= 0 && diff.Y <= 2 && diff.Y >= 0;
1075                         }
1076                         sizegrip.Visible = show_sizegrip;
1077                         sizegrip.Enabled = enable_sizegrip || sizegrip.Capture;
1078                         if (sizegrip.Visible)
1079                                 XplatUI.SetZOrder (sizegrip.Handle, vscrollbar.Handle, false, false);
1080                 }
1081
1082                 private void HandleScrollBar(object sender, EventArgs e) {
1083                         if (sender == vscrollbar) {
1084                                 if (!vscrollbar.Visible)
1085                                         return;
1086                                 ScrollWindow(0, vscrollbar.Value- scroll_position.Y);
1087                         } else {
1088                                 if (!hscrollbar.Visible)
1089                                         return;
1090                                 ScrollWindow(hscrollbar.Value - scroll_position.X, 0);
1091                         }
1092                 }
1093
1094 #if NET_2_0
1095                 private void HandleScrollEvent (object sender, ScrollEventArgs args)
1096                 {
1097                         OnScroll (args);
1098                 }
1099 #endif
1100
1101                 private void AddScrollbars (object o, EventArgs e)
1102                 {
1103                         Controls.AddRangeImplicit (new Control[] {hscrollbar, vscrollbar, sizegrip});
1104                         HandleCreated -= new EventHandler (AddScrollbars);
1105                 }
1106
1107                 private void CreateScrollbars ()
1108                 {
1109                         hscrollbar = new ImplicitHScrollBar ();
1110                         hscrollbar.Visible = false;
1111                         hscrollbar.ValueChanged += new EventHandler (HandleScrollBar);
1112                         hscrollbar.Height = SystemInformation.HorizontalScrollBarHeight;
1113                         hscrollbar.use_manual_thumb_size = true;
1114 #if NET_2_0
1115                         hscrollbar.Scroll += new ScrollEventHandler (HandleScrollEvent);
1116 #endif
1117
1118                         vscrollbar = new ImplicitVScrollBar ();
1119                         vscrollbar.Visible = false;
1120                         vscrollbar.ValueChanged += new EventHandler (HandleScrollBar);
1121                         vscrollbar.Width = SystemInformation.VerticalScrollBarWidth;
1122                         vscrollbar.use_manual_thumb_size = true;
1123 #if NET_2_0
1124                         vscrollbar.Scroll += new ScrollEventHandler (HandleScrollEvent);
1125 #endif
1126
1127                         sizegrip = new SizeGrip (this);
1128                         sizegrip.Visible = false;
1129                 }
1130
1131                 private void ScrollWindow(int XOffset, int YOffset) {
1132                         int     num_of_children;
1133
1134                         if (XOffset == 0 && YOffset == 0) {
1135                                 return;
1136                         }
1137
1138                         SuspendLayout();
1139
1140                         num_of_children = Controls.Count;
1141
1142                         for (int i = 0; i < num_of_children; i++) {
1143                                 Controls[i].Location = new Point (Controls[i].Left - XOffset, Controls[i].Top - YOffset);
1144                                 //Controls[i].Left -= XOffset;
1145                                 //Controls[i].Top -= YOffset;
1146                                 // Is this faster? Controls[i].Location -= new Size(XOffset, YOffset);
1147                         }
1148
1149                         scroll_position.X += XOffset;
1150                         scroll_position.Y += YOffset;
1151
1152                         XplatUI.ScrollWindow (Handle, ClientRectangle, -XOffset, -YOffset, false);
1153                         ResumeLayout(false);
1154                 }
1155                 #endregion      // Internal & Private Methods
1156
1157 #if NET_2_0
1158                 static object OnScrollEvent = new object ();
1159                 
1160                 protected virtual void OnScroll (ScrollEventArgs se)
1161                 {
1162                         ScrollEventHandler eh = (ScrollEventHandler) (Events [OnScrollEvent]);
1163                         if (eh != null)
1164                                 eh (this, se);
1165                 }
1166
1167                 protected override void OnPaddingChanged (EventArgs e)
1168                 {
1169                         base.OnPaddingChanged (e);
1170                 }
1171                 
1172                 protected override void OnPaintBackground (PaintEventArgs e)
1173                 {
1174                         base.OnPaintBackground (e);
1175                 }
1176
1177                 [EditorBrowsable (EditorBrowsableState.Advanced)]
1178                 protected override void OnRightToLeftChanged (EventArgs e)
1179                 {
1180                         base.OnRightToLeftChanged (e);
1181                 }
1182
1183                 public event ScrollEventHandler Scroll {
1184                         add { Events.AddHandler (OnScrollEvent, value); }
1185                         remove { Events.RemoveHandler (OnScrollEvent, value); }
1186                 }
1187 #endif
1188         }
1189 }