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
30 using System.ComponentModel;
31 using System.ComponentModel.Design;
34 namespace System.Windows.Forms {
35 [Designer ("System.Windows.Forms.Design.ScrollableControlDesigner, " + Consts.AssemblySystem_Design, (string)null)]
36 public class ScrollableControl : Control {
37 #region Local Variables
38 private bool auto_vscroll;
39 private bool auto_hscroll;
40 private bool hscroll_visible;
41 private bool vscroll_visible;
42 private bool force_hscroll_visible;
43 private bool force_vscroll_visible;
44 private bool auto_scroll;
45 private Size auto_scroll_margin;
46 private Size auto_scroll_min_size;
47 private Point scroll_position;
48 private DockPaddingEdges dock_padding;
49 private SizeGrip sizegrip;
50 private HScrollBar hscrollbar;
51 private VScrollBar vscrollbar;
52 #endregion // Local Variables
54 [MonoTODO("Need to use the edge values when performing the layout")]
55 [TypeConverter(typeof(ScrollableControl.DockPaddingEdgesConverter))]
56 #region Subclass DockPaddingEdges
57 public class DockPaddingEdges : ICloneable {
58 #region DockPaddingEdges Local Variables
64 #endregion // DockPaddingEdges Local Variables
66 #region DockPaddingEdges Constructor
67 internal DockPaddingEdges() {
74 #endregion // DockPaddingEdges Constructor
76 #region DockPaddingEdges Public Instance Properties
77 [RefreshProperties(RefreshProperties.All)]
92 [RefreshProperties(RefreshProperties.All)]
104 [RefreshProperties(RefreshProperties.All)]
116 [RefreshProperties(RefreshProperties.All)]
128 [RefreshProperties(RefreshProperties.All)]
140 #endregion // DockPaddingEdges Public Instance Properties
142 // Public Instance Methods
143 public override bool Equals(object other) {
144 if (! (other is DockPaddingEdges)) {
148 if ( (this.all == ((DockPaddingEdges)other).all) && (this.left == ((DockPaddingEdges)other).left) &&
149 (this.right == ((DockPaddingEdges)other).right) && (this.top == ((DockPaddingEdges)other).top) &&
150 (this.bottom == ((DockPaddingEdges)other).bottom)) {
157 public override int GetHashCode() {
158 return all*top*bottom*right*left;
161 public override string ToString() {
162 return "All = "+all.ToString()+" Top = "+top.ToString()+" Left = "+left.ToString()+" Bottom = "+bottom.ToString()+" Right = "+right.ToString();
165 object ICloneable.Clone() {
166 DockPaddingEdges padding_edge;
168 padding_edge=new DockPaddingEdges();
170 padding_edge.all=all;
171 padding_edge.left=left;
172 padding_edge.right=right;
173 padding_edge.top=top;
174 padding_edge.bottom=bottom;
179 #endregion // Subclass DockPaddingEdges
181 #region Subclass DockPaddingEdgesConverter
182 public class DockPaddingEdgesConverter : System.ComponentModel.TypeConverter {
183 // Public Constructors
184 public DockPaddingEdgesConverter() {
187 // Public Instance Methods
188 public override PropertyDescriptorCollection GetProperties(System.ComponentModel.ITypeDescriptorContext context, object value, Attribute[] attributes) {
189 return TypeDescriptor.GetProperties(typeof(DockPaddingEdges), attributes);
192 public override bool GetPropertiesSupported(System.ComponentModel.ITypeDescriptorContext context) {
196 #endregion // Subclass DockPaddingEdgesConverter
198 #region Public Constructors
199 public ScrollableControl() {
200 SetStyle(ControlStyles.ContainerControl, true);
202 auto_hscroll = false;
203 auto_vscroll = false;
204 hscroll_visible = false;
205 vscroll_visible = false;
206 force_hscroll_visible = false;
207 force_vscroll_visible = false;
208 auto_scroll_margin = new Size(0, 0);
209 auto_scroll_min_size = new Size(0, 0);
210 scroll_position = new Point(0, 0);
211 dock_padding = new DockPaddingEdges();
212 SizeChanged +=new EventHandler(Recalculate);
213 VisibleChanged += new EventHandler(Recalculate);
215 #endregion // Public Constructors
217 #region Protected Static Fields
218 protected const int ScrollStateAutoScrolling = 1;
219 protected const int ScrollStateFullDrag = 16;
220 protected const int ScrollStateHScrollVisible = 2;
221 protected const int ScrollStateUserHasScrolled = 8;
222 protected const int ScrollStateVScrollVisible = 4;
223 #endregion // Protected Static Fields
225 #region Public Instance Properties
226 [DefaultValue(false)]
228 public virtual bool AutoScroll {
234 if (auto_scroll == value) {
240 Controls.Remove(hscrollbar);
241 hscrollbar.Dispose();
244 Controls.Remove(vscrollbar);
245 vscrollbar.Dispose();
248 Controls.Remove(sizegrip);
252 hscrollbar = new HScrollBar();
253 hscrollbar.Visible = false;
254 hscrollbar.ValueChanged += new EventHandler(HandleScrollBar);
255 hscrollbar.Height = SystemInformation.HorizontalScrollBarHeight;
256 this.Controls.Add(hscrollbar);
258 vscrollbar = new VScrollBar();
259 vscrollbar.Visible = false;
260 vscrollbar.ValueChanged += new EventHandler(HandleScrollBar);
261 vscrollbar.Width = SystemInformation.VerticalScrollBarWidth;
262 this.Controls.Add(vscrollbar);
264 sizegrip = new SizeGrip();
265 sizegrip.Visible = false;
266 this.Controls.Add(sizegrip);
272 public Size AutoScrollMargin {
274 return auto_scroll_margin;
278 if (value.Width < 0) {
279 throw new ArgumentException("Width is assigned less than 0", "value.Width");
282 if (value.Height < 0) {
283 throw new ArgumentException("Height is assigned less than 0", "value.Height");
286 auto_scroll_margin = value;
291 public Size AutoScrollMinSize {
293 return auto_scroll_min_size;
297 auto_scroll_min_size = value;
302 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
303 public Point AutoScrollPosition {
305 return new Point(-scroll_position.X, -scroll_position.Y);
309 if ((value.X != scroll_position.X) || (value.Y != scroll_position.Y)) {
315 if (hscroll_visible) {
316 shift_x = value.X - scroll_position.X;
319 if (vscroll_visible) {
320 shift_y = value.Y - scroll_position.Y;
323 ScrollWindow(shift_x, shift_y);
325 if (hscroll_visible) {
326 hscrollbar.Value = scroll_position.X;
329 if (vscroll_visible) {
330 vscrollbar.Value = scroll_position.Y;
337 public override Rectangle DisplayRectangle {
341 rect = base.DisplayRectangle;
343 if (vscroll_visible) {
344 rect.Width -= vscrollbar.Width;
345 if (rect.Width < 0) {
350 if (hscroll_visible) {
351 rect.Height -= hscrollbar.Height;
352 if (rect.Height < 0) {
360 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
362 public DockPaddingEdges DockPadding {
367 // DockPadding is documented as 'get' only ( http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsScrollableControlClassAutoScrollTopic.asp )
368 // but Microsoft's examples on that page show 'set' usage
370 // dock_padding = value;
373 #endregion // Public Instance Properties
375 #region Protected Instance Methods
376 protected override CreateParams CreateParams {
380 ret = base.CreateParams;
382 ret.Style |= (int)(WindowStyles.WS_CLIPCHILDREN | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_VISIBLE);
388 protected bool HScroll {
390 return hscroll_visible;
394 if (hscroll_visible != value) {
395 force_hscroll_visible = value;
396 Recalculate(this, EventArgs.Empty);
401 protected bool VScroll {
403 return vscroll_visible;
407 if (vscroll_visible != value) {
408 force_vscroll_visible = value;
409 Recalculate(this, EventArgs.Empty);
413 #endregion // Protected Instance Methods
415 #region Public Instance Methods
416 public void ScrollControlIntoView(Control activeControl) {
419 public void SetAutoScrollMargin(int x, int y) {
428 auto_scroll_margin = new Size(x, y);
429 Recalculate(this, EventArgs.Empty);
431 #endregion // Public Instance Methods
433 #region Protected Instance Methods
434 [EditorBrowsable(EditorBrowsableState.Advanced)]
435 protected virtual void AdjustFormScrollbars(bool displayScrollbars) {
439 [EditorBrowsable(EditorBrowsableState.Advanced)]
440 protected bool GetScrollState(int bit) {
445 [EditorBrowsable(EditorBrowsableState.Advanced)]
446 protected override void OnLayout(LayoutEventArgs levent) {
447 base.OnLayout(levent);
450 [EditorBrowsable(EditorBrowsableState.Advanced)]
451 protected override void OnMouseWheel(MouseEventArgs e) {
452 if (vscroll_visible) {
454 if (vscrollbar.Minimum < (vscrollbar.Value - vscrollbar.LargeChange)) {
455 vscrollbar.Value -= vscrollbar.LargeChange;
457 vscrollbar.Value = vscrollbar.Minimum;
460 if (vscrollbar.Maximum > (vscrollbar.Value + vscrollbar.LargeChange)) {
461 vscrollbar.Value += vscrollbar.LargeChange;
463 vscrollbar.Value = vscrollbar.Maximum;
467 base.OnMouseWheel(e);
470 [EditorBrowsable(EditorBrowsableState.Advanced)]
471 protected override void OnVisibleChanged(EventArgs e) {
472 base.OnVisibleChanged(e);
475 protected override void ScaleCore(float dx, float dy) {
476 base.ScaleCore(dx, dy);
479 protected void SetDisplayRectLocation(int x, int y) {
480 throw new NotImplementedException();
483 protected void SetScrollState(int bit, bool value) {
484 throw new NotImplementedException();
487 [EditorBrowsable(EditorBrowsableState.Advanced)]
488 protected override void WndProc(ref Message m) {
491 #endregion // Protected Instance Methods
493 #region Internal & Private Methods
494 private Size Canvas {
500 num_of_children = child_controls.Count;
504 for (int i = 0; i < num_of_children; i++) {
505 if ((child_controls[i].Visible == false) || (child_controls[i] == hscrollbar) || (child_controls[i] == vscrollbar) || (child_controls[i] == sizegrip)) {
508 if (child_controls[i].Right > width) {
509 width = child_controls[i].Right;
512 if (child_controls[i].Bottom > height) {
513 height = child_controls[i].Bottom;
517 return new Size(width, height);
521 private void Recalculate(object sender, EventArgs e) {
525 // FIXME - this whole function begs for optimizations, all the math
526 // shouldn't have to be done over and over
528 // Check if we need scrollbars
529 if (!this.auto_scroll && !force_hscroll_visible && !force_vscroll_visible) {
534 client = ClientRectangle.Size;
536 canvas.Width += auto_scroll_margin.Width + SystemInformation.VerticalScrollBarWidth;
537 canvas.Height += auto_scroll_margin.Height + SystemInformation.HorizontalScrollBarHeight;
539 // || (scroll_position.X == 0 && scroll_position.Y == 0)
541 if ((canvas.Width >= client.Width) || (auto_scroll_min_size.Width > client.Width) || force_hscroll_visible) {
545 hscrollbar.Top = client.Height - SystemInformation.HorizontalScrollBarHeight;
546 hscrollbar.Maximum = Math.Max(0, canvas.Width - client.Width + SystemInformation.VerticalScrollBarWidth);
548 hscroll_visible = true;
550 hscroll_visible = false;
551 scroll_position.X = 0;
554 if ((canvas.Height >= client.Height) || (auto_scroll_min_size.Height > client.Height) || force_vscroll_visible) {
556 vscrollbar.Left = client.Width - SystemInformation.VerticalScrollBarWidth;
559 // FIXME - Working around some scrollbar bugs here; shouldn't have to add the height again (see canvas+= above)
560 vscrollbar.Maximum = Math.Max(0, canvas.Height - client.Height + SystemInformation.HorizontalScrollBarHeight);
561 vscroll_visible = true;
563 vscroll_visible = false;
564 scroll_position.Y = 0;
567 if (hscroll_visible && vscroll_visible) {
568 hscrollbar.Width = ClientRectangle.Width - SystemInformation.VerticalScrollBarWidth;
569 vscrollbar.Height = ClientRectangle.Height - SystemInformation.HorizontalScrollBarHeight;
571 sizegrip.Left = hscrollbar.Right;
572 sizegrip.Top = vscrollbar.Bottom;
573 sizegrip.Width = SystemInformation.VerticalScrollBarWidth;
574 sizegrip.Height = SystemInformation.HorizontalScrollBarHeight;
576 hscrollbar.Visible = true;
577 vscrollbar.Visible = true;
578 sizegrip.Visible = true;
580 sizegrip.Visible = false;
581 if (hscroll_visible) {
582 hscrollbar.Width = ClientRectangle.Width;
583 hscrollbar.Visible = true;
585 hscrollbar.Visible = false;
588 if (vscroll_visible) {
589 vscrollbar.Height = ClientRectangle.Height;
590 vscrollbar.Visible = true;
592 vscrollbar.Visible = false;
597 private void HandleScrollBar(object sender, EventArgs e) {
598 if (sender == vscrollbar) {
599 ScrollWindow(0, vscrollbar.Value- scroll_position.Y);
601 ScrollWindow(hscrollbar.Value - scroll_position.X, 0);
605 private void ScrollWindow(int XOffset, int YOffset) {
610 num_of_children = child_controls.Count;
612 for (int i = 0; i < num_of_children; i++) {
613 if (child_controls[i] == hscrollbar || child_controls[i] == vscrollbar || child_controls[i] == sizegrip) {
616 child_controls[i].Left -= XOffset;
617 child_controls[i].Top -= YOffset;
618 // Is this faster? child_controls[i].Location -= new Size(XOffset, YOffset);
621 scroll_position.X += XOffset;
622 scroll_position.Y += YOffset;
624 // Should we call XplatUI.ScrollWindow???
628 #endregion // Internal & Private Methods