updating to the latest module.
[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
27 // NOT COMPLETE
28
29 using System;
30 using System.ComponentModel;
31 using System.ComponentModel.Design;
32 using System.Drawing;
33
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
53
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
59                         private int all;
60                         private int left;
61                         private int right;
62                         private int top;
63                         private int bottom;
64                         #endregion      // DockPaddingEdges Local Variables
65
66                         #region DockPaddingEdges Constructor
67                         internal DockPaddingEdges() {
68                                 all = 0;
69                                 left = 0;
70                                 right = 0;
71                                 top = 0;
72                                 bottom = 0;
73                         }
74                         #endregion      // DockPaddingEdges Constructor
75
76                         #region DockPaddingEdges Public Instance Properties
77                         [RefreshProperties(RefreshProperties.All)]
78                         public int All {
79                                 get {
80                                         return all;
81                                 }
82
83                                 set {
84                                         all = value;
85                                         left = value;
86                                         right = value;
87                                         top = value;
88                                         bottom = value;
89                                 }
90                         }
91
92                         [RefreshProperties(RefreshProperties.All)]
93                         public int Bottom {
94                                 get {
95                                         return bottom;
96                                 }
97
98                                 set {
99                                         bottom = value;
100                                         all = 0;
101                                 }
102                         }
103
104                         [RefreshProperties(RefreshProperties.All)]
105                         public int Left {
106                                 get {
107                                         return left;
108                                 }
109
110                                 set {
111                                         left=value;
112                                         all = 0;
113                                 }
114                         }
115
116                         [RefreshProperties(RefreshProperties.All)]
117                         public int Right {
118                                 get {
119                                         return right;
120                                 }
121
122                                 set {
123                                         right=value;
124                                         all = 0;
125                                 }
126                         }
127
128                         [RefreshProperties(RefreshProperties.All)]
129                         public int Top {
130                                 get {
131                                         return top;
132                                 }
133
134                                 set {
135                                         top=value;
136                                         all = 0;
137                                 }
138                         }
139
140                         #endregion      // DockPaddingEdges Public Instance Properties
141
142                         // Public Instance Methods
143                         public override bool Equals(object other) {
144                                 if (! (other is DockPaddingEdges)) {
145                                         return false;
146                                 }
147
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)) {
151                                         return true;
152                                 }
153
154                                 return false;
155                         }
156
157                         public override int GetHashCode() {
158                                 return all*top*bottom*right*left;
159                         }
160
161                         public override string ToString() {
162                                 return "All = "+all.ToString()+" Top = "+top.ToString()+" Left = "+left.ToString()+" Bottom = "+bottom.ToString()+" Right = "+right.ToString();
163                         }
164
165                         object ICloneable.Clone() {
166                                 DockPaddingEdges padding_edge;
167
168                                 padding_edge=new DockPaddingEdges();
169
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;
175
176                                 return padding_edge;
177                         }
178                 }
179                 #endregion      // Subclass DockPaddingEdges
180
181                 #region Subclass DockPaddingEdgesConverter
182                 public class DockPaddingEdgesConverter : System.ComponentModel.TypeConverter {
183                         // Public Constructors
184                         public DockPaddingEdgesConverter() {
185                         }
186
187                         // Public Instance Methods
188                         public override PropertyDescriptorCollection GetProperties(System.ComponentModel.ITypeDescriptorContext context, object value, Attribute[] attributes) {
189                                 return TypeDescriptor.GetProperties(typeof(DockPaddingEdges), attributes);
190                         }
191
192                         public override bool GetPropertiesSupported(System.ComponentModel.ITypeDescriptorContext context) {
193                                 return true;
194                         }
195                 }
196                 #endregion      // Subclass DockPaddingEdgesConverter
197
198                 #region Public Constructors
199                 public ScrollableControl() {
200                         SetStyle(ControlStyles.ContainerControl, true);
201                         auto_scroll = false;
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);
214                 }
215                 #endregion      // Public Constructors
216
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
224
225                 #region Public Instance Properties
226                 [DefaultValue(false)]
227                 [Localizable(true)]
228                 public virtual bool AutoScroll {
229                         get {
230                                 return  auto_scroll;
231                         }
232
233                         set {
234                                 if (auto_scroll == value) {
235                                         return;
236                                 }
237
238                                 auto_scroll = value;
239                                 if (!auto_scroll) {
240                                         Controls.Remove(hscrollbar);
241                                         hscrollbar.Dispose();
242                                         hscrollbar = null;
243
244                                         Controls.Remove(vscrollbar);
245                                         vscrollbar.Dispose();
246                                         vscrollbar = null;
247
248                                         Controls.Remove(sizegrip);
249                                         sizegrip.Dispose();
250                                         sizegrip = null;
251                                 } else {
252                                         hscrollbar = new HScrollBar();
253                                         hscrollbar.Visible = false;
254                                         hscrollbar.ValueChanged += new EventHandler(HandleScrollBar);
255                                         hscrollbar.Height = SystemInformation.HorizontalScrollBarHeight;
256                                         this.Controls.Add(hscrollbar);
257
258                                         vscrollbar = new VScrollBar();
259                                         vscrollbar.Visible = false;
260                                         vscrollbar.ValueChanged += new EventHandler(HandleScrollBar);
261                                         vscrollbar.Width = SystemInformation.VerticalScrollBarWidth;
262                                         this.Controls.Add(vscrollbar);
263
264                                         sizegrip = new SizeGrip();
265                                         sizegrip.Visible = false;
266                                         this.Controls.Add(sizegrip);
267                                 }
268                         }
269                 }
270
271                 [Localizable(true)]
272                 public Size AutoScrollMargin {
273                         get {
274                                 return auto_scroll_margin;
275                         }
276
277                         set {
278                                 if (value.Width < 0) {
279                                         throw new ArgumentException("Width is assigned less than 0", "value.Width");
280                                 }
281
282                                 if (value.Height < 0) {
283                                         throw new ArgumentException("Height is assigned less than 0", "value.Height");
284                                 }
285
286                                 auto_scroll_margin = value;
287                         }
288                 }
289
290                 [Localizable(true)]
291                 public Size AutoScrollMinSize {
292                         get {
293                                 return auto_scroll_min_size;
294                         }
295
296                         set {
297                                 auto_scroll_min_size = value;
298                         }
299                 }
300
301                 [Browsable(false)]
302                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
303                 public Point AutoScrollPosition {
304                         get {
305                                 return new Point(-scroll_position.X, -scroll_position.Y);
306                         }
307
308                         set {
309                                 if ((value.X != scroll_position.X) || (value.Y != scroll_position.Y)) {
310                                         int     shift_x;
311                                         int     shift_y;
312
313                                         shift_x = 0;
314                                         shift_y = 0;
315                                         if (hscroll_visible) {
316                                                 shift_x = value.X - scroll_position.X;
317                                         }
318
319                                         if (vscroll_visible) {
320                                                 shift_y = value.Y - scroll_position.Y;
321                                         }
322
323                                         ScrollWindow(shift_x, shift_y);
324
325                                         if (hscroll_visible) {
326                                                 hscrollbar.Value = scroll_position.X;
327                                         }
328
329                                         if (vscroll_visible) {
330                                                 vscrollbar.Value = scroll_position.Y;
331                                         }
332
333                                 }
334                         }
335                 }
336
337                 public override Rectangle DisplayRectangle {
338                         get {
339                                 Rectangle       rect;
340
341                                 rect = base.DisplayRectangle;
342
343                                 if (vscroll_visible) {
344                                         rect.Width -= vscrollbar.Width;
345                                         if (rect.Width < 0) {
346                                                 rect.Width = 0;
347                                         }
348                                 }
349
350                                 if (hscroll_visible) {
351                                         rect.Height -= hscrollbar.Height;
352                                         if (rect.Height < 0) {
353                                                 rect.Height = 0;
354                                         }
355                                 }
356                                 return rect;
357                         }
358                 }
359
360                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
361                 [Localizable(true)]
362                 public DockPaddingEdges DockPadding {
363                         get {
364                                 return dock_padding;
365                         }
366
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
369 //                      set {
370 //                              dock_padding = value;
371 //                      }
372                 }
373                 #endregion      // Public Instance Properties
374
375                 #region Protected Instance Methods
376                 protected override CreateParams CreateParams {
377                         get {
378                                 CreateParams    ret;
379
380                                 ret = base.CreateParams;
381
382                                 ret.Style |= (int)(WindowStyles.WS_CLIPCHILDREN | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_VISIBLE);
383
384                                 return ret;
385                         }
386                 }
387
388                 protected bool HScroll {
389                         get {
390                                 return hscroll_visible;
391                         }
392
393                         set {
394                                 if (hscroll_visible != value) {
395                                         force_hscroll_visible = value;
396                                         Recalculate(this, EventArgs.Empty);
397                                 }
398                         }
399                 }
400
401                 protected bool VScroll {
402                         get {
403                                 return vscroll_visible;
404                         }
405
406                         set {
407                                 if (vscroll_visible != value) {
408                                         force_vscroll_visible = value;
409                                         Recalculate(this, EventArgs.Empty);
410                                 }
411                         }
412                 }
413                 #endregion      // Protected Instance Methods
414
415                 #region Public Instance Methods
416                 public void ScrollControlIntoView(Control activeControl) {
417                 }
418
419                 public void SetAutoScrollMargin(int x, int y) {
420                         if (x < 0) {
421                                 x = 0;
422                         }
423
424                         if (y < 0) {
425                                 y = 0;
426                         }
427
428                         auto_scroll_margin = new Size(x, y);
429                         Recalculate(this, EventArgs.Empty);
430                 }
431                 #endregion      // Public Instance Methods
432
433                 #region Protected Instance Methods
434                 [EditorBrowsable(EditorBrowsableState.Advanced)]
435                 protected virtual void AdjustFormScrollbars(bool displayScrollbars) {
436                         // Internal MS
437                 }
438
439                 [EditorBrowsable(EditorBrowsableState.Advanced)]
440                 protected bool GetScrollState(int bit) {
441                         return false;
442                         // Internal MS
443                 }
444
445                 [EditorBrowsable(EditorBrowsableState.Advanced)]
446                 protected override void OnLayout(LayoutEventArgs levent) {
447                         base.OnLayout(levent);
448                 }
449
450                 [EditorBrowsable(EditorBrowsableState.Advanced)]
451                 protected override void OnMouseWheel(MouseEventArgs e) {
452                         if (vscroll_visible) {
453                                 if (e.Delta > 0) {
454                                         if (vscrollbar.Minimum < (vscrollbar.Value - vscrollbar.LargeChange)) {
455                                                 vscrollbar.Value -= vscrollbar.LargeChange;
456                                         } else {
457                                                 vscrollbar.Value = vscrollbar.Minimum;
458                                         }
459                                 } else {
460                                         if (vscrollbar.Maximum > (vscrollbar.Value + vscrollbar.LargeChange)) {
461                                                         vscrollbar.Value += vscrollbar.LargeChange;
462                                                 } else {
463                                                         vscrollbar.Value = vscrollbar.Maximum;
464                                                 }
465                                         }
466                         }
467                         base.OnMouseWheel(e);
468                 }
469
470                 [EditorBrowsable(EditorBrowsableState.Advanced)]
471                 protected override void OnVisibleChanged(EventArgs e) {
472                         base.OnVisibleChanged(e);
473                 }
474
475                 protected override void ScaleCore(float dx, float dy) {
476                         base.ScaleCore(dx, dy);
477                 }
478
479                 protected void SetDisplayRectLocation(int x, int y) {
480                         throw new NotImplementedException();
481                 }
482
483                 protected void SetScrollState(int bit, bool value) {
484                         throw new NotImplementedException();
485                 }
486
487                 [EditorBrowsable(EditorBrowsableState.Advanced)]
488                 protected override void WndProc(ref Message m) {
489                         base.WndProc(ref m);
490                 }
491                 #endregion      // Protected Instance Methods
492
493                 #region Internal & Private Methods
494                 private Size Canvas {
495                         get {
496                                 int     num_of_children;
497                                 int     width;
498                                 int     height;
499
500                                 num_of_children = child_controls.Count;
501                                 width = 0;
502                                 height = 0;
503
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)) {
506                                                 continue;
507                                         }
508                                         if (child_controls[i].Right > width) {
509                                                 width = child_controls[i].Right;
510                                         }
511
512                                         if (child_controls[i].Bottom > height) {
513                                                 height = child_controls[i].Bottom;
514                                         }
515                                 }
516
517                                 return new Size(width, height);
518                         }
519                 }
520
521                 private void Recalculate(object sender, EventArgs e) {
522                         Size    canvas;
523                         Size    client;
524
525                         // FIXME - this whole function begs for optimizations, all the math
526                         // shouldn't have to be done over and over
527
528                         // Check if we need scrollbars
529                         if (!this.auto_scroll && !force_hscroll_visible && !force_vscroll_visible) {
530                                 return;
531                         }
532
533                         canvas = Canvas;
534                         client = ClientRectangle.Size;
535
536                         canvas.Width += auto_scroll_margin.Width + SystemInformation.VerticalScrollBarWidth;
537                         canvas.Height += auto_scroll_margin.Height + SystemInformation.HorizontalScrollBarHeight;
538
539                         //  || (scroll_position.X == 0 && scroll_position.Y == 0)
540
541                         if ((canvas.Width >= client.Width) || (auto_scroll_min_size.Width > client.Width) || force_hscroll_visible) {
542                                 // Need horz
543
544                                 hscrollbar.Left = 0;
545                                 hscrollbar.Top = client.Height - SystemInformation.HorizontalScrollBarHeight;
546                                 hscrollbar.Maximum = Math.Max(0, canvas.Width - client.Width + SystemInformation.VerticalScrollBarWidth);
547
548                                 hscroll_visible = true;
549                         } else {
550                                 hscroll_visible = false;
551                                 scroll_position.X = 0;
552                         }
553
554                         if ((canvas.Height >= client.Height) || (auto_scroll_min_size.Height > client.Height) || force_vscroll_visible) {
555                                 // Need vert
556                                 vscrollbar.Left = client.Width - SystemInformation.VerticalScrollBarWidth;
557                                 vscrollbar.Top = 0;
558
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;
562                         } else {
563                                 vscroll_visible = false;
564                                 scroll_position.Y = 0;
565                         }
566
567                         if (hscroll_visible && vscroll_visible) {
568                                 hscrollbar.Width = ClientRectangle.Width - SystemInformation.VerticalScrollBarWidth;
569                                 vscrollbar.Height = ClientRectangle.Height - SystemInformation.HorizontalScrollBarHeight;
570
571                                 sizegrip.Left =  hscrollbar.Right;
572                                 sizegrip.Top =  vscrollbar.Bottom;
573                                 sizegrip.Width = SystemInformation.VerticalScrollBarWidth;
574                                 sizegrip.Height = SystemInformation.HorizontalScrollBarHeight;
575
576                                 hscrollbar.Visible = true;
577                                 vscrollbar.Visible = true;
578                                 sizegrip.Visible = true;
579                         } else {
580                                 sizegrip.Visible = false;
581                                 if (hscroll_visible) {
582                                         hscrollbar.Width = ClientRectangle.Width;
583                                         hscrollbar.Visible = true;
584                                 } else {
585                                         hscrollbar.Visible = false;
586                                 }
587
588                                 if (vscroll_visible) {
589                                         vscrollbar.Height = ClientRectangle.Height;
590                                         vscrollbar.Visible = true;
591                                 } else {
592                                         vscrollbar.Visible = false;
593                                 }
594                         }
595                 }
596
597                 private void HandleScrollBar(object sender, EventArgs e) {
598                         if (sender == vscrollbar) {
599                                 ScrollWindow(0, vscrollbar.Value- scroll_position.Y);
600                         } else {
601                                 ScrollWindow(hscrollbar.Value - scroll_position.X, 0);
602                         }
603                 }
604
605                 private void ScrollWindow(int XOffset, int YOffset) {
606                         int     num_of_children;
607
608                         SuspendLayout();
609
610                         num_of_children = child_controls.Count;
611
612                         for (int i = 0; i < num_of_children; i++) {
613                                 if (child_controls[i] == hscrollbar || child_controls[i] == vscrollbar || child_controls[i] == sizegrip) {
614                                         continue;
615                                 }
616                                 child_controls[i].Left -= XOffset;
617                                 child_controls[i].Top -= YOffset;
618                                 // Is this faster? child_controls[i].Location -= new Size(XOffset, YOffset);
619                         }
620
621                         scroll_position.X += XOffset;
622                         scroll_position.Y += YOffset;
623
624                         // Should we call XplatUI.ScrollWindow???
625                         Invalidate();
626                         ResumeLayout();
627                 }
628                 #endregion      // Internal & Private Methods
629
630         }
631 }