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