1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004 Novell, Inc.
23 // Peter Bartok pbartok@novell.com
27 using System.ComponentModel;
28 using System.ComponentModel.Design;
30 using System.Runtime.InteropServices;
32 namespace System.Windows.Forms {
33 [Designer ("System.Windows.Forms.Design.ScrollableControlDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
34 [ClassInterface (ClassInterfaceType.AutoDispatch)]
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
56 [TypeConverter(typeof(ScrollableControl.DockPaddingEdgesConverter))]
57 #region Subclass DockPaddingEdges
58 public class DockPaddingEdges : ICloneable
60 private Control owner;
62 internal DockPaddingEdges (Control owner)
67 #region DockPaddingEdges Public Instance Properties
68 [RefreshProperties (RefreshProperties.All)]
70 get { return owner.Padding.All; }
71 set { owner.Padding = new Padding (value); }
74 [RefreshProperties (RefreshProperties.All)]
76 get { return owner.Padding.Bottom; }
77 set { owner.Padding = new Padding (Left, Top, Right, value); }
80 [RefreshProperties (RefreshProperties.All)]
82 get { return owner.Padding.Left; }
83 set { owner.Padding = new Padding (value, Top, Right, Bottom); }
86 [RefreshProperties (RefreshProperties.All)]
88 get { return owner.Padding.Right; }
89 set { owner.Padding = new Padding (Left, Top, value, Bottom); }
92 [RefreshProperties (RefreshProperties.All)]
94 get { return owner.Padding.Top; }
95 set { owner.Padding = new Padding (Left, value, Right, Bottom); }
97 #endregion // DockPaddingEdges Public Instance Properties
99 // Public Instance Methods
100 public override bool Equals (object other)
102 if (!(other is DockPaddingEdges)) {
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)) {
115 public override int GetHashCode ()
117 return All * Top * Bottom * Right * Left;
120 public override string ToString ()
122 return "All = " + All.ToString () + " Top = " + Top.ToString () + " Left = " + Left.ToString () + " Bottom = " + Bottom.ToString () + " Right = " + Right.ToString ();
125 internal void Scale (float dx, float dy)
127 Left = (int)(Left * dx);
128 Right = (int)(Right * dx);
129 Top = (int)(Top * dy);
130 Bottom = (int)(Bottom * dy);
133 object ICloneable.Clone ()
135 return new DockPaddingEdges (owner);
138 #endregion // Subclass DockPaddingEdges
140 #region Subclass DockPaddingEdgesConverter
141 public class DockPaddingEdgesConverter : System.ComponentModel.TypeConverter {
142 // Public Constructors
143 public DockPaddingEdgesConverter() {
146 // Public Instance Methods
147 public override PropertyDescriptorCollection GetProperties(System.ComponentModel.ITypeDescriptorContext context, object value, Attribute[] attributes) {
148 return TypeDescriptor.GetProperties(typeof(DockPaddingEdges), attributes);
151 public override bool GetPropertiesSupported(System.ComponentModel.ITypeDescriptorContext context) {
155 #endregion // Subclass DockPaddingEdgesConverter
157 #region Public Constructors
158 public ScrollableControl() {
159 SetStyle(ControlStyles.ContainerControl, true);
160 SetStyle(ControlStyles.AllPaintingInWmPaint, 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);
176 horizontalScroll = new HScrollProperties (this);
177 verticalScroll = new VScrollProperties (this);
180 void VisibleChangedHandler (object sender, EventArgs e)
185 void LocationChangedHandler (object sender, EventArgs e)
187 UpdateSizeGripVisible ();
190 void ParentChangedHandler (object sender, EventArgs e)
193 if (old_parent == Parent)
196 if (old_parent != null) {
197 old_parent.SizeChanged -= new EventHandler (Parent_SizeChanged);
198 old_parent.PaddingChanged -= new EventHandler (Parent_PaddingChanged);
201 if (Parent != null) {
202 Parent.SizeChanged += new EventHandler (Parent_SizeChanged);
203 Parent.PaddingChanged += new EventHandler (Parent_PaddingChanged);
209 void Parent_PaddingChanged (object sender, EventArgs e)
211 UpdateSizeGripVisible ();
214 void Parent_SizeChanged (object sender, EventArgs e)
216 UpdateSizeGripVisible ();
218 #endregion // Public Constructors
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
228 #region Public Instance Properties
229 [DefaultValue(false)]
231 [MWFCategory("Layout")]
232 public virtual bool AutoScroll {
238 if (auto_scroll != value) {
240 PerformLayout (this, "AutoScroll");
246 [MWFCategory("Layout")]
247 public Size AutoScrollMargin {
249 return auto_scroll_margin;
253 if (value.Width < 0) {
254 throw new ArgumentException("Width is assigned less than 0", "value.Width");
257 if (value.Height < 0) {
258 throw new ArgumentException("Height is assigned less than 0", "value.Height");
261 auto_scroll_margin = value;
265 internal bool ShouldSerializeAutoScrollMargin ()
267 return this.AutoScrollMargin != new Size (0, 0);
271 [MWFCategory("Layout")]
272 public Size AutoScrollMinSize {
274 return auto_scroll_min_size;
278 if (value != auto_scroll_min_size) {
279 auto_scroll_min_size = value;
281 PerformLayout (this, "AutoScrollMinSize");
286 internal bool ShouldSerializeAutoScrollMinSize ()
288 return this.AutoScrollMinSize != new Size (0, 0);
292 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
293 public Point AutoScrollPosition {
295 return DisplayRectangle.Location;
299 if (value != AutoScrollPosition) {
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;
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;
319 ScrollWindow(shift_x, shift_y);
321 if (hscrollbar.VisibleInternal) {
322 if (scroll_position.X >= hscrollbar.Minimum && scroll_position.X <= hscrollbar.Maximum)
323 hscrollbar.Value = scroll_position.X;
326 if (vscrollbar.VisibleInternal) {
327 if (scroll_position.Y >= vscrollbar.Minimum && scroll_position.Y <= vscrollbar.Maximum)
328 vscrollbar.Value = scroll_position.Y;
335 public override Rectangle DisplayRectangle {
341 if (canvas_size.Width <= base.DisplayRectangle.Width) {
342 width = base.DisplayRectangle.Width;
343 if (vscrollbar.VisibleInternal) {
344 width -= vscrollbar.Width;
347 width = canvas_size.Width;
350 if (canvas_size.Height <= base.DisplayRectangle.Height) {
351 height = base.DisplayRectangle.Height;
352 if (hscrollbar.VisibleInternal) {
353 height -= hscrollbar.Height;
356 height = canvas_size.Height;
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);
365 display_rectangle = base.DisplayRectangle;
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;
377 return display_rectangle;
381 [MWFCategory("Layout")]
383 [EditorBrowsable (EditorBrowsableState.Never)]
384 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
385 public DockPaddingEdges DockPadding {
387 if (dock_padding == null)
388 CreateDockPadding ();
395 [EditorBrowsable (EditorBrowsableState.Always)]
396 public HScrollProperties HorizontalScroll {
397 get { return horizontalScroll; }
401 [EditorBrowsable (EditorBrowsableState.Always)]
402 public VScrollProperties VerticalScroll {
403 get { return verticalScroll; }
405 #endregion // Public Instance Properties
407 #region Protected Instance Methods
408 protected override CreateParams CreateParams {
410 return base.CreateParams;
414 protected bool HScroll {
416 return hscrollbar.VisibleInternal;
420 if (!AutoScroll && hscrollbar.VisibleInternal != value) {
421 force_hscroll_visible = value;
427 protected bool VScroll {
429 return vscrollbar.VisibleInternal;
433 if (!AutoScroll && vscrollbar.VisibleInternal != value) {
434 force_vscroll_visible = value;
439 #endregion // Protected Instance Methods
441 #region Public Instance Methods
442 public void ScrollControlIntoView(Control activeControl) {
446 Rectangle within = new Rectangle ();
447 within.Size = ClientSize;
449 if (!AutoScroll || (!hscrollbar.VisibleInternal && !vscrollbar.VisibleInternal)) {
453 if (!Contains(activeControl)) {
457 if (vscrollbar.Visible) {
458 within.Width -= vscrollbar.Width;
460 if (hscrollbar.Visible) {
461 within.Height -= hscrollbar.Height;
464 // Don't scroll if already visible
465 if (within.Contains (activeControl.Location) && within.Contains (activeControl.Right, activeControl.Bottom)) {
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;
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;
484 corner_x = hscrollbar.Value - x_diff;
485 corner_y = vscrollbar.Value - y_diff;
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;
493 if (corner_x != hscrollbar.Value) {
494 hscrollbar.Value = corner_x;
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;
504 if (corner_y != vscrollbar.Value) {
505 vscrollbar.Value = corner_y;
510 public void SetAutoScrollMargin(int x, int y) {
519 auto_scroll_margin = new Size(x, y);
522 #endregion // Public Instance Methods
524 #region Protected Instance Methods
525 [EditorBrowsable(EditorBrowsableState.Advanced)]
526 protected virtual void AdjustFormScrollbars(bool displayScrollbars) {
530 [EditorBrowsable(EditorBrowsableState.Advanced)]
531 protected bool GetScrollState(int bit) {
536 [EditorBrowsable(EditorBrowsableState.Advanced)]
537 protected override void OnLayout(LayoutEventArgs levent) {
538 CalculateCanvasSize (true);
540 AdjustFormScrollbars(AutoScroll); // Dunno what the logic is. Passing AutoScroll seems to match MS behaviour
541 base.OnLayout(levent);
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);
553 [EditorBrowsable(EditorBrowsableState.Advanced)]
554 protected override void OnMouseWheel(MouseEventArgs e) {
555 if (vscrollbar.VisibleInternal) {
557 if (vscrollbar.Minimum < (vscrollbar.Value - vscrollbar.LargeChange)) {
558 vscrollbar.Value -= vscrollbar.LargeChange;
560 vscrollbar.Value = vscrollbar.Minimum;
563 int maximum_scrollbar_value = vscrollbar.Maximum - vscrollbar.LargeChange + 1;
564 if (maximum_scrollbar_value > (vscrollbar.Value + vscrollbar.LargeChange)) {
565 vscrollbar.Value += vscrollbar.LargeChange;
567 vscrollbar.Value = maximum_scrollbar_value;
571 base.OnMouseWheel(e);
574 [EditorBrowsable(EditorBrowsableState.Advanced)]
575 protected override void OnVisibleChanged(EventArgs e) {
577 UpdateChildrenZOrder ();
578 PerformLayout(this, "Visible");
580 base.OnVisibleChanged(e);
583 [EditorBrowsable (EditorBrowsableState.Never)]
584 protected override void ScaleCore(float dx, float dy) {
585 if (dock_padding != null)
586 dock_padding.Scale(dx, dy);
588 base.ScaleCore(dx, dy);
591 protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
593 base.ScaleControl (factor, specified);
596 protected virtual Point ScrollToControl (Control activeControl)
601 Rectangle within = new Rectangle ();
602 within.Size = ClientSize;
604 if (vscrollbar.Visible)
605 within.Width -= vscrollbar.Width;
607 if (hscrollbar.Visible)
608 within.Height -= hscrollbar.Height;
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;
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;
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;
626 corner_x = AutoScrollPosition.X + x_diff;
627 corner_y = AutoScrollPosition.Y + y_diff;
629 return new Point (corner_x, corner_y);
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
644 ScrollWindow(scroll_position.X - x , scroll_position.Y - y);
647 protected void SetScrollState(int bit, bool value) {
648 //throw new NotImplementedException();
651 [EditorBrowsable(EditorBrowsableState.Advanced)]
652 protected override void WndProc(ref Message m) {
655 #endregion // Protected Instance Methods
657 #region Internal & Private Methods
658 internal override IntPtr AfterTopMostControl ()
660 // order of scrollbars:
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;
671 return base.AfterTopMostControl ();
674 internal virtual void CalculateCanvasSize (bool canOverride) {
682 num_of_children = Controls.Count;
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;
692 autosized_child = false;
693 for (int i = 0; i < num_of_children; i++) {
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;
704 if (!auto_scroll_min_size.IsEmpty) {
705 width = auto_scroll_min_size.Width;
706 height = auto_scroll_min_size.Height;
709 for (int i = 0; i < num_of_children; i++) {
713 case DockStyle.Left: {
714 if ((child.Right + extra_width) > width) {
715 width = child.Right + extra_width;
720 case DockStyle.Top: {
721 if ((child.Bottom + extra_height) > height) {
722 height = child.Bottom + extra_height;
728 case DockStyle.Right:
729 case DockStyle.Bottom: {
736 anchor = child.Anchor;
738 if (((anchor & AnchorStyles.Left) != 0) && ((anchor & AnchorStyles.Right) == 0)) {
739 if ((child.Right + extra_width) > width) {
740 width = child.Right + extra_width;
744 if (((anchor & AnchorStyles.Top) != 0) || ((anchor & AnchorStyles.Bottom) == 0)) {
745 if ((child.Bottom + extra_height) > height) {
746 height = child.Bottom + extra_height;
754 canvas_size.Width = width;
755 canvas_size.Height = height;
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 ()
762 if (dock_padding == null)
763 dock_padding = new DockPaddingEdges (this);
766 private void Recalculate (object sender, EventArgs e) {
770 private void Recalculate (bool doLayout) {
771 if (!IsHandleCreated) {
775 Size canvas = canvas_size;
776 Size client = ClientSize;
778 canvas.Width += auto_scroll_margin.Width;
779 canvas.Height += auto_scroll_margin.Height;
781 int right_edge = client.Width;
782 int bottom_edge = client.Height;
784 int prev_bottom_edge;
786 bool hscroll_visible;
787 bool vscroll_visible;
790 prev_right_edge = right_edge;
791 prev_bottom_edge = bottom_edge;
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;
797 hscroll_visible = false;
798 bottom_edge = client.Height;
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;
805 vscroll_visible = false;
806 right_edge = client.Width;
809 } while (right_edge != prev_right_edge || bottom_edge != prev_bottom_edge);
811 if (right_edge < 0) right_edge = 0;
812 if (bottom_edge < 0) bottom_edge = 0;
814 Rectangle hscroll_bounds;
815 Rectangle vscroll_bounds;
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);
822 /* the ScrollWindow calls here are needed
823 * because (this explanation sucks):
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.
830 * if you can fix this without requiring the
831 * ScrollWindow calls, pdb and toshok will each
835 if (!vscrollbar.Visible) {
836 vscrollbar.Value = 0;
838 if (!hscrollbar.Visible) {
839 hscrollbar.Value = 0;
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;
850 if (hscrollbar != null && hscrollbar.VisibleInternal) {
851 ScrollWindow (- scroll_position.X, 0);
853 scroll_position.X = 0;
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;
862 if (vscrollbar != null && vscrollbar.VisibleInternal) {
863 ScrollWindow (0, - scroll_position.Y);
865 scroll_position.Y = 0;
868 if (hscroll_visible && vscroll_visible) {
869 hscroll_bounds.Width -= SystemInformation.VerticalScrollBarWidth;
870 vscroll_bounds.Height -= SystemInformation.HorizontalScrollBarHeight;
872 sizegrip.Bounds = new Rectangle (hscroll_bounds.Right,
873 vscroll_bounds.Bottom,
874 SystemInformation.VerticalScrollBarWidth,
875 SystemInformation.HorizontalScrollBarHeight);
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);
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);
890 UpdateSizeGripVisible ();
892 ResumeLayout (doLayout);
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);
903 internal void UpdateSizeGripVisible ()
905 if (!IsHandleCreated) {
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;
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);
925 private void HandleScrollBar(object sender, EventArgs e) {
926 if (sender == vscrollbar) {
927 if (!vscrollbar.Visible)
929 ScrollWindow(0, vscrollbar.Value- scroll_position.Y);
931 if (!hscrollbar.Visible)
933 ScrollWindow(hscrollbar.Value - scroll_position.X, 0);
937 private void HandleScrollEvent (object sender, ScrollEventArgs args)
942 private void AddScrollbars (object o, EventArgs e)
944 Controls.AddRangeImplicit (new Control[] {hscrollbar, vscrollbar, sizegrip});
945 HandleCreated -= new EventHandler (AddScrollbars);
948 private void CreateScrollbars ()
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);
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);
964 sizegrip = new SizeGrip (this);
965 sizegrip.Visible = false;
968 private void ScrollWindow(int XOffset, int YOffset) {
971 if (XOffset == 0 && YOffset == 0) {
977 num_of_children = Controls.Count;
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);
986 scroll_position.X += XOffset;
987 scroll_position.Y += YOffset;
989 XplatUI.ScrollWindow (Handle, ClientRectangle, -XOffset, -YOffset, false);
992 #endregion // Internal & Private Methods
994 static object OnScrollEvent = new object ();
996 protected virtual void OnScroll (ScrollEventArgs se)
998 ScrollEventHandler eh = (ScrollEventHandler) (Events [OnScrollEvent]);
1003 protected override void OnPaddingChanged (EventArgs e)
1005 base.OnPaddingChanged (e);
1008 protected override void OnPaintBackground (PaintEventArgs e)
1010 base.OnPaintBackground (e);
1013 [EditorBrowsable (EditorBrowsableState.Advanced)]
1014 protected override void OnRightToLeftChanged (EventArgs e)
1016 base.OnRightToLeftChanged (e);
1019 public event ScrollEventHandler Scroll {
1020 add { Events.AddHandler (OnScrollEvent, value); }
1021 remove { Events.RemoveHandler (OnScrollEvent, value); }