4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 // Copyright (c) 2006 Jonathan Pobst
26 // Jonathan Pobst (monkey@jpobst.com)
31 using System.Runtime.InteropServices;
32 using System.ComponentModel;
34 using System.Drawing.Drawing2D;
36 namespace System.Windows.Forms
38 [ComVisibleAttribute (true)]
39 [ClassInterfaceAttribute (ClassInterfaceType.AutoDispatch)]
40 [DefaultEvent ("SplitterMoved")]
41 [Docking (DockingBehavior.AutoDock)]
42 public class SplitContainer : ContainerControl
44 #region Local Variables
45 private FixedPanel fixed_panel;
46 private int splitter_distance;
47 private int splitter_width;
48 private int splitter_increment;
49 private Orientation orientation;
50 private bool binding_context_set;
52 private SplitterPanel panel1;
53 private bool panel1_collapsed;
54 private int panel1_min_size;
56 private SplitterPanel panel2;
57 private bool panel2_collapsed;
58 private int panel2_min_size;
60 private Splitter splitter;
64 static object SplitterMovedEvent = new object ();
65 static object SplitterMovingEvent = new object ();
68 //[EditorBrowsable (EditorBrowsableState.Never)]
69 //new public event EventHandler AutoSizeChanged;
72 [EditorBrowsable (EditorBrowsableState.Never)]
73 public new event EventHandler BackgroundImageChanged {
74 add { base.BackgroundImageChanged += value; }
75 remove { base.BackgroundImageChanged -= value; }
79 [EditorBrowsable (EditorBrowsableState.Never)]
80 public new event EventHandler BackgroundImageLayoutChanged {
81 add { base.BackgroundImageLayoutChanged += value; }
82 remove { base.BackgroundImageLayoutChanged -= value; }
86 [EditorBrowsable (EditorBrowsableState.Never)]
87 public new event ControlEventHandler ControlAdded {
88 add { base.ControlAdded += value; }
89 remove { base.ControlAdded -= value; }
93 [EditorBrowsable (EditorBrowsableState.Never)]
94 public new event ControlEventHandler ControlRemoved {
95 add { base.ControlRemoved += value; }
96 remove { base.ControlRemoved -= value; }
100 [EditorBrowsable (EditorBrowsableState.Never)]
101 public new event EventHandler PaddingChanged {
102 add { base.PaddingChanged += value; }
103 remove { base.PaddingChanged -= value; }
106 public event SplitterEventHandler SplitterMoved {
107 add { Events.AddHandler (SplitterMovedEvent, value); }
108 remove { Events.RemoveHandler (SplitterMovedEvent, value); }
111 public event SplitterCancelEventHandler SplitterMoving {
112 add { Events.AddHandler (SplitterMovingEvent, value); }
113 remove { Events.RemoveHandler (SplitterMovingEvent, value); }
117 [EditorBrowsable (EditorBrowsableState.Never)]
118 public new event EventHandler TextChanged {
119 add { base.TextChanged += value; }
120 remove { base.TextChanged -= value; }
124 #region Public Constructors
125 public SplitContainer ()
127 fixed_panel = FixedPanel.None;
128 orientation = Orientation.Vertical;
129 splitter_distance = 50;
131 splitter_increment = 1;
132 panel1_collapsed = false;
133 panel2_collapsed = false;
134 panel1_min_size = 25;
135 panel2_min_size = 25;
136 binding_context_set = false;
138 panel1 = new SplitterPanel (this);
139 panel2 = new SplitterPanel (this);
140 splitter = new Splitter ();
142 splitter.TabStop = true;
143 splitter.Size = new System.Drawing.Size (4, 4);
144 splitter.SplitterMoved += new SplitterEventHandler (splitter_SplitterMoved);
145 splitter.SplitterMoving += new SplitterEventHandler (splitter_SplitterMoving);
147 panel1.Size = new Size (50, 50);
149 this.Controls.Add (panel2);
150 this.Controls.Add (splitter);
151 this.Controls.Add (panel1);
153 panel1.Dock = DockStyle.Left;
154 panel2.Dock = DockStyle.Fill;
155 splitter.Dock = DockStyle.Left;
159 #region Public Properties
161 [EditorBrowsable (EditorBrowsableState.Never)]
163 [DefaultValue (false)]
164 public override bool AutoScroll {
165 get { return base.AutoScroll; }
166 set { base.AutoScroll = value; }
170 [EditorBrowsable (EditorBrowsableState.Never)]
171 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
172 new public Size AutoScrollMargin {
173 get { return base.AutoScrollMargin; }
174 set { base.AutoScrollMargin = value; }
178 [EditorBrowsable (EditorBrowsableState.Never)]
179 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
180 new public Size AutoScrollMinSize {
181 get { return base.AutoScrollMinSize; }
182 set { base.AutoScrollMinSize = value; }
185 //Uncomment once this has been implemented in Control.cs
186 //[Browsable (false)]
187 //[EditorBrowsable (EditorBrowsableState.Never)]
188 //public override Point AutoScrollOffset {
189 // get { return base.AutoScrollOffset; }
190 // set { base.AutoScrollOffset = value; }
194 [EditorBrowsable (EditorBrowsableState.Never)]
195 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
196 new public Point AutoScrollPosition {
197 get { return base.AutoScrollPosition; }
198 set { base.AutoScrollPosition = value; }
202 [EditorBrowsable (EditorBrowsableState.Never)]
203 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
204 public override bool AutoSize {
205 get { return base.AutoSize; }
206 set { base.AutoSize = value; }
210 [EditorBrowsable (EditorBrowsableState.Never)]
211 public override Image BackgroundImage {
212 get { return base.BackgroundImage; }
214 base.BackgroundImage = value;
215 UpdateSplitterBackground ();
220 [EditorBrowsable (EditorBrowsableState.Never)]
221 public override ImageLayout BackgroundImageLayout {
222 get { return base.BackgroundImageLayout; }
223 set { base.BackgroundImageLayout = value; }
227 public override BindingContext BindingContext {
228 get { return binding_context_set ? base.BindingContext : null; }
230 binding_context_set = true;
231 base.BindingContext = value;
235 // MSDN says default is Fixed3D, creating a new SplitContainer says otherwise.
236 [DefaultValue (BorderStyle.None)]
237 public BorderStyle BorderStyle
239 get { return panel1.BorderStyle; }
241 if (!Enum.IsDefined (typeof (BorderStyle), value))
242 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for BorderStyle", value));
244 panel1.BorderStyle = value;
245 panel2.BorderStyle = value;
249 [EditorBrowsable (EditorBrowsableState.Never)]
250 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
251 new public ControlCollection Controls { get { return base.Controls; } }
253 new public DockStyle Dock {
254 get { return base.Dock; }
255 set { base.Dock = value; }
258 [DefaultValue (FixedPanel.None)]
259 public FixedPanel FixedPanel {
260 get { return this.fixed_panel; }
262 if (!Enum.IsDefined (typeof (FixedPanel), value))
263 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for FixedPanel", value));
265 this.fixed_panel = value;
270 [DefaultValue (false)]
271 public bool IsSplitterFixed {
272 get { return !splitter.Enabled; }
273 set { splitter.Enabled = !value; }
277 [DefaultValue (Orientation.Vertical)]
278 public Orientation Orientation {
279 get { return this.orientation; }
281 if (!Enum.IsDefined (typeof (Orientation), value))
282 throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for Orientation", value));
284 if (this.orientation != value) {
285 this.orientation = value;
288 case Orientation.Vertical:
289 panel1.Dock = DockStyle.Left;
290 panel2.Dock = DockStyle.Fill;
291 splitter.Dock = DockStyle.Left;
292 splitter.Width = this.splitter_width;
293 panel1.InternalWidth = this.splitter_distance;
294 if (panel2.Width < panel2_min_size)
295 panel1.InternalWidth = this.Width - this.splitter_width - panel2_min_size;
297 case Orientation.Horizontal:
299 panel1.Dock = DockStyle.Top;
300 panel2.Dock = DockStyle.Fill;
301 splitter.Dock = DockStyle.Top;
302 splitter.Height = this.splitter_width;
303 panel1.InternalHeight = this.splitter_distance;
304 if (panel2.Height < panel2_min_size)
305 panel1.InternalHeight = this.Height - this.splitter_width - panel2_min_size;
309 this.PerformLayout ();
315 [EditorBrowsable (EditorBrowsableState.Never)]
316 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
317 new public Padding Padding {
318 get { return base.Padding; }
319 set { base.Padding = value; }
322 [Localizable (false)]
323 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
324 public SplitterPanel Panel1 { get { return this.panel1; } }
326 [DefaultValue (false)]
327 public bool Panel1Collapsed {
328 get { return this.panel1_collapsed; }
330 this.panel1_collapsed = value;
331 this.panel1.Visible = !value;
332 this.splitter.Visible = !value;
338 [RefreshProperties (RefreshProperties.All)]
339 public int Panel1MinSize {
340 get { return this.panel1_min_size; }
342 this.panel1_min_size = value;
343 this.splitter.MinSize = value;
347 [Localizable (false)]
348 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
349 public SplitterPanel Panel2 { get { return this.panel2; } }
351 [DefaultValue (false)]
352 public bool Panel2Collapsed {
353 get { return this.panel2_collapsed; }
355 this.panel2_collapsed = value;
356 this.panel2.Visible = !value;
357 this.splitter.Visible = !value;
363 [RefreshProperties (RefreshProperties.All)]
364 public int Panel2MinSize {
365 get { return this.panel2_min_size; }
366 set { this.panel2_min_size = value; this.splitter.MinExtra = value; }
369 // MSDN says the default is 40, MS's implementation defaults to 50.
372 [SettingsBindable (true)]
373 public int SplitterDistance {
374 get { return this.splitter_distance; }
377 throw new ArgumentOutOfRangeException ();
379 if (value < this.panel1_min_size)
380 value = this.panel1_min_size;
382 switch (this.orientation) {
383 case Orientation.Vertical:
384 if (value > this.Width - this.panel2_min_size - this.splitter_width)
385 value = this.Width - this.panel2_min_size - this.splitter_width;
386 panel1.InternalWidth = value;
388 case Orientation.Horizontal:
390 if (value > this.Height - this.panel2_min_size - this.splitter_width)
391 value = this.Height - this.panel2_min_size - this.splitter_width;
392 panel1.InternalHeight = value;
396 this.splitter_distance = value;
398 UpdateSplitterBackground ();
404 [MonoTODO ("Not implemented.")]
405 public int SplitterIncrement {
406 get { return this.splitter_increment; }
407 set { this.splitter_increment = value; }
411 public Rectangle SplitterRectangle { get { return splitter.Bounds; } }
415 public int SplitterWidth {
416 get { return this.splitter_width; }
419 throw new ArgumentOutOfRangeException ();
421 this.splitter_width = value;
423 switch (this.orientation) {
424 case Orientation.Horizontal:
425 splitter.Height = value;
427 case Orientation.Vertical:
429 splitter.Width = value;
435 [DefaultValue (true)]
436 new public bool TabStop {
437 get { return splitter.TabStop; }
438 set { splitter.TabStop = value; }
442 [EditorBrowsable (EditorBrowsableState.Never)]
444 public override string Text {
445 get { return base.Text; }
446 set { base.Text = value; }
450 #region Protected Properties
451 protected override Size DefaultSize { get { return new Size (150, 100); } }
454 #region Public Methods
455 public void OnSplitterMoved (SplitterEventArgs e)
457 SplitterEventHandler eh = (SplitterEventHandler)(Events [SplitterMovedEvent]);
462 public void OnSplitterMoving (SplitterCancelEventArgs e)
464 SplitterCancelEventHandler eh = (SplitterCancelEventHandler)(Events [SplitterMovingEvent]);
468 if (e.Cancel == true) {
469 e.SplitX = splitter.Location.X;
470 e.SplitY = splitter.Location.Y;
475 #region Protected Methods
476 protected override ControlCollection CreateControlsInstance ()
478 return new SplitContainerTypedControlCollection (this);
481 [MonoTODO ("Special focus semantics not implemented")]
482 protected override void OnGotFocus (EventArgs e)
487 protected override void OnKeyDown (KeyEventArgs e)
492 protected override void OnKeyUp (KeyEventArgs e)
497 protected override void OnLayout (LayoutEventArgs levent)
499 base.OnLayout (levent);
502 protected override void OnMouseDown (MouseEventArgs e)
504 base.OnMouseDown (e);
507 protected override void OnMouseLeave (EventArgs e)
509 base.OnMouseLeave (e);
512 protected override void OnMouseMove (MouseEventArgs e)
514 base.OnMouseMove (e);
517 protected override void OnMouseUp (MouseEventArgs e)
522 protected override void OnPaint (PaintEventArgs e)
527 protected override void OnRightToLeftChanged (EventArgs e)
529 base.OnRightToLeftChanged (e);
532 [MonoTODO ("Special focus semantics not implemented")]
533 protected override bool ProcessDialogKey (Keys keyData)
535 return base.ProcessDialogKey (keyData);
538 [MonoTODO ("Special focus semantics not implemented")]
539 protected override bool ProcessTabKey (bool forward)
541 return base.ProcessTabKey (forward);
544 [MonoTODO ("Special focus semantics not implemented")]
545 protected override void Select (bool directed, bool forward)
547 base.Select (directed, forward);
550 protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
552 base.SetBoundsCore (x, y, width, height, specified);
555 protected override void WndProc (ref Message m)
557 base.WndProc (ref m);
561 #region Private Methods
562 private void splitter_SplitterMoving (object sender, SplitterEventArgs e)
564 SplitterCancelEventArgs ea = new SplitterCancelEventArgs (e.X, e.Y, e.SplitX, e.SplitY);
565 this.OnSplitterMoving (ea);
566 e.SplitX = ea.SplitX;
567 e.SplitY = ea.SplitY;
570 private void splitter_SplitterMoved (object sender, SplitterEventArgs e)
572 this.OnSplitterMoved (e);
575 private void UpdateSplitterBackground ()
577 if (this.BackgroundImage != null) {
578 Bitmap b = new Bitmap (splitter.Width, splitter.Height);
579 Graphics.FromImage (b).DrawImage (base.BackgroundImage, new Rectangle (0, 0, b.Width, b.Height), this.SplitterRectangle, GraphicsUnit.Pixel);
580 splitter.BackgroundImage = b;
583 splitter.BackgroundImage = this.BackgroundImage;
587 #region Internal Classes
588 internal class SplitContainerTypedControlCollection : ControlCollection
590 public SplitContainerTypedControlCollection (Control owner) : base (owner)