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, "System.ComponentModel.Design.IDesigner")]
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);
201 SetStyle(ControlStyles.AllPaintingInWmPaint, false);
203 auto_hscroll = false;
204 auto_vscroll = false;
205 hscroll_visible = false;
206 vscroll_visible = false;
207 force_hscroll_visible = false;
208 force_vscroll_visible = false;
209 auto_scroll_margin = new Size(0, 0);
210 auto_scroll_min_size = new Size(0, 0);
211 scroll_position = new Point(0, 0);
212 dock_padding = new DockPaddingEdges();
213 SizeChanged +=new EventHandler(Recalculate);
214 VisibleChanged += new EventHandler(Recalculate);
216 #endregion // Public Constructors
218 #region Protected Static Fields
219 protected const int ScrollStateAutoScrolling = 1;
220 protected const int ScrollStateFullDrag = 16;
221 protected const int ScrollStateHScrollVisible = 2;
222 protected const int ScrollStateUserHasScrolled = 8;
223 protected const int ScrollStateVScrollVisible = 4;
224 #endregion // Protected Static Fields
226 #region Public Instance Properties
227 [DefaultValue(false)]
229 public virtual bool AutoScroll {
235 if (auto_scroll == value) {
243 Controls.RemoveImplicit (hscrollbar);
244 hscrollbar.Dispose();
246 hscroll_visible = false;
248 Controls.RemoveImplicit (vscrollbar);
249 vscrollbar.Dispose();
251 vscroll_visible = false;
253 Controls.RemoveImplicit (sizegrip);
261 hscrollbar = new HScrollBar();
262 hscrollbar.Visible = false;
263 hscrollbar.ValueChanged += new EventHandler(HandleScrollBar);
264 hscrollbar.Height = SystemInformation.HorizontalScrollBarHeight;
265 this.Controls.AddImplicit (hscrollbar);
267 vscrollbar = new VScrollBar();
268 vscrollbar.Visible = false;
269 vscrollbar.ValueChanged += new EventHandler(HandleScrollBar);
270 vscrollbar.Width = SystemInformation.VerticalScrollBarWidth;
271 this.Controls.AddImplicit (vscrollbar);
273 sizegrip = new SizeGrip();
274 sizegrip.Visible = false;
275 this.Controls.AddImplicit (sizegrip);
283 public Size AutoScrollMargin {
285 return auto_scroll_margin;
289 if (value.Width < 0) {
290 throw new ArgumentException("Width is assigned less than 0", "value.Width");
293 if (value.Height < 0) {
294 throw new ArgumentException("Height is assigned less than 0", "value.Height");
297 auto_scroll_margin = value;
302 public Size AutoScrollMinSize {
304 return auto_scroll_min_size;
308 auto_scroll_min_size = value;
313 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
314 public Point AutoScrollPosition {
316 return new Point(-scroll_position.X, -scroll_position.Y);
320 if ((value.X != scroll_position.X) || (value.Y != scroll_position.Y)) {
326 if (hscroll_visible) {
327 shift_x = value.X - scroll_position.X;
330 if (vscroll_visible) {
331 shift_y = value.Y - scroll_position.Y;
334 ScrollWindow(shift_x, shift_y);
336 if (hscroll_visible) {
337 hscrollbar.Value = scroll_position.X;
340 if (vscroll_visible) {
341 vscrollbar.Value = scroll_position.Y;
348 public override Rectangle DisplayRectangle {
352 rect = base.DisplayRectangle;
353 if (vscroll_visible) {
354 rect.Width -= vscrollbar.Width;
355 if (rect.Width < 0) {
360 if (hscroll_visible) {
361 rect.Height -= hscrollbar.Height;
362 if (rect.Height < 0) {
367 //return new Rectangle(-scroll_position.X, -scroll_position.Y, auto_scroll_min_size.Width, auto_scroll_min_size.Height);
371 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
373 public DockPaddingEdges DockPadding {
378 // DockPadding is documented as 'get' only ( http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsScrollableControlClassAutoScrollTopic.asp )
379 // but Microsoft's examples on that page show 'set' usage
381 // dock_padding = value;
384 #endregion // Public Instance Properties
386 #region Protected Instance Methods
387 protected override CreateParams CreateParams {
389 return base.CreateParams;
393 protected bool HScroll {
395 return hscroll_visible;
399 if (hscroll_visible != value) {
400 force_hscroll_visible = value;
401 Recalculate(this, EventArgs.Empty);
406 protected bool VScroll {
408 return vscroll_visible;
412 if (vscroll_visible != value) {
413 force_vscroll_visible = value;
414 Recalculate(this, EventArgs.Empty);
418 #endregion // Protected Instance Methods
420 #region Public Instance Methods
421 public void ScrollControlIntoView(Control activeControl) {
424 public void SetAutoScrollMargin(int x, int y) {
433 auto_scroll_margin = new Size(x, y);
434 Recalculate(this, EventArgs.Empty);
436 #endregion // Public Instance Methods
438 #region Protected Instance Methods
439 [EditorBrowsable(EditorBrowsableState.Advanced)]
440 protected virtual void AdjustFormScrollbars(bool displayScrollbars) {
444 [EditorBrowsable(EditorBrowsableState.Advanced)]
445 protected bool GetScrollState(int bit) {
450 [EditorBrowsable(EditorBrowsableState.Advanced)]
451 protected override void OnLayout(LayoutEventArgs levent) {
452 base.OnLayout(levent);
455 [EditorBrowsable(EditorBrowsableState.Advanced)]
456 protected override void OnMouseWheel(MouseEventArgs e) {
457 if (vscroll_visible) {
459 if (vscrollbar.Minimum < (vscrollbar.Value - vscrollbar.LargeChange)) {
460 vscrollbar.Value -= vscrollbar.LargeChange;
462 vscrollbar.Value = vscrollbar.Minimum;
465 if (vscrollbar.Maximum > (vscrollbar.Value + vscrollbar.LargeChange)) {
466 vscrollbar.Value += vscrollbar.LargeChange;
468 vscrollbar.Value = vscrollbar.Maximum;
472 base.OnMouseWheel(e);
475 [EditorBrowsable(EditorBrowsableState.Advanced)]
476 protected override void OnVisibleChanged(EventArgs e) {
477 base.OnVisibleChanged(e);
480 protected override void ScaleCore(float dx, float dy) {
481 base.ScaleCore(dx, dy);
484 protected void SetDisplayRectLocation(int x, int y) {
485 throw new NotImplementedException();
488 protected void SetScrollState(int bit, bool value) {
489 throw new NotImplementedException();
492 [EditorBrowsable(EditorBrowsableState.Advanced)]
493 protected override void WndProc(ref Message m) {
496 #endregion // Protected Instance Methods
498 #region Internal & Private Methods
499 private Size Canvas {
505 num_of_children = child_controls.Count;
509 for (int i = 0; i < num_of_children; i++) {
510 if ((child_controls[i].Visible == false) || (child_controls[i] == hscrollbar) || (child_controls[i] == vscrollbar) || (child_controls[i] == sizegrip)) {
513 if (child_controls[i].Right > width) {
514 width = child_controls[i].Right;
517 if (child_controls[i].Bottom > height) {
518 height = child_controls[i].Bottom;
522 return new Size(width, height);
526 private void Recalculate(object sender, EventArgs e) {
530 // FIXME - this whole function begs for optimizations, all the math
531 // shouldn't have to be done over and over
533 // Check if we need scrollbars
534 if (!this.auto_scroll && !force_hscroll_visible && !force_vscroll_visible) {
539 client = ClientRectangle.Size;
541 canvas.Width += auto_scroll_margin.Width + SystemInformation.VerticalScrollBarWidth;
542 canvas.Height += auto_scroll_margin.Height + SystemInformation.HorizontalScrollBarHeight;
544 // || (scroll_position.X == 0 && scroll_position.Y == 0)
546 if ((canvas.Width >= client.Width) || (auto_scroll_min_size.Width > client.Width) || force_hscroll_visible) {
550 hscrollbar.Top = client.Height - SystemInformation.HorizontalScrollBarHeight;
551 hscrollbar.Maximum = Math.Max(0, canvas.Width - client.Width + SystemInformation.VerticalScrollBarWidth);
553 hscroll_visible = true;
555 hscroll_visible = false;
556 scroll_position.X = 0;
559 if ((canvas.Height >= client.Height) || (auto_scroll_min_size.Height > client.Height) || force_vscroll_visible) {
561 vscrollbar.Left = client.Width - SystemInformation.VerticalScrollBarWidth;
564 // FIXME - Working around some scrollbar bugs here; shouldn't have to add the height again (see canvas+= above)
565 vscrollbar.Maximum = Math.Max(0, canvas.Height - client.Height + SystemInformation.HorizontalScrollBarHeight);
566 vscroll_visible = true;
568 vscroll_visible = false;
569 scroll_position.Y = 0;
572 if (hscroll_visible && vscroll_visible) {
573 hscrollbar.Width = ClientRectangle.Width - SystemInformation.VerticalScrollBarWidth;
574 vscrollbar.Height = ClientRectangle.Height - SystemInformation.HorizontalScrollBarHeight;
576 sizegrip.Left = hscrollbar.Right;
577 sizegrip.Top = vscrollbar.Bottom;
578 sizegrip.Width = SystemInformation.VerticalScrollBarWidth;
579 sizegrip.Height = SystemInformation.HorizontalScrollBarHeight;
581 hscrollbar.Visible = true;
582 vscrollbar.Visible = true;
583 sizegrip.Visible = true;
585 sizegrip.Visible = false;
586 if (hscroll_visible) {
587 hscrollbar.Width = ClientRectangle.Width;
588 hscrollbar.Visible = true;
590 hscrollbar.Visible = false;
593 if (vscroll_visible) {
594 vscrollbar.Height = ClientRectangle.Height;
595 vscrollbar.Visible = true;
597 vscrollbar.Visible = false;
602 private void HandleScrollBar(object sender, EventArgs e) {
603 if (sender == vscrollbar) {
604 ScrollWindow(0, vscrollbar.Value- scroll_position.Y);
606 ScrollWindow(hscrollbar.Value - scroll_position.X, 0);
610 private void ScrollWindow(int XOffset, int YOffset) {
615 num_of_children = child_controls.Count;
617 for (int i = 0; i < num_of_children; i++) {
618 if (child_controls[i] == hscrollbar || child_controls[i] == vscrollbar || child_controls[i] == sizegrip) {
621 child_controls[i].Left -= XOffset;
622 child_controls[i].Top -= YOffset;
623 // Is this faster? child_controls[i].Location -= new Size(XOffset, YOffset);
626 scroll_position.X += XOffset;
627 scroll_position.Y += YOffset;
629 // Should we call XplatUI.ScrollWindow???
633 #endregion // Internal & Private Methods