SplitContainer.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  1. //
  2. // SplitContainer.cs
  3. //
  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:
  11. //
  12. // The above copyright notice and this permission notice shall be
  13. // included in all copies or substantial portions of the Software.
  14. //
  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.
  22. //
  23. // Copyright (c) 2006 Jonathan Pobst
  24. // Copyright (c) 2007 Ivan N. Zlatev
  25. //
  26. // Authors:
  27. // Jonathan Pobst ([email protected])
  28. // Ivan N. Zlatev ([email protected])
  29. //
  30. using System;
  31. using System.Runtime.InteropServices;
  32. using System.ComponentModel;
  33. using System.Drawing;
  34. using System.Drawing.Drawing2D;
  35. namespace System.Windows.Forms
  36. {
  37. [ComVisibleAttribute (true)]
  38. [ClassInterfaceAttribute (ClassInterfaceType.AutoDispatch)]
  39. [DefaultEvent ("SplitterMoved")]
  40. [Docking (DockingBehavior.AutoDock)]
  41. [Designer ("System.Windows.Forms.Design.SplitContainerDesigner, " + Consts.AssemblySystem_Design)]
  42. public class SplitContainer : ContainerControl
  43. , ISupportInitialize
  44. {
  45. #region Local Variables
  46. private FixedPanel fixed_panel;
  47. private Orientation orientation;
  48. private int splitter_increment;
  49. private Rectangle splitter_rectangle;
  50. private Rectangle splitter_rectangle_moving;
  51. private Rectangle splitter_rectangle_before_move;
  52. private bool splitter_fixed;
  53. private bool splitter_dragging;
  54. private int splitter_prev_move;
  55. private Cursor restore_cursor;
  56. private double fixed_none_ratio;
  57. private SplitterPanel panel1;
  58. private bool panel1_collapsed;
  59. private int panel1_min_size;
  60. private SplitterPanel panel2;
  61. private bool panel2_collapsed;
  62. private int panel2_min_size;
  63. #endregion
  64. #region Public Events
  65. static object SplitterMovedEvent = new object ();
  66. static object SplitterMovingEvent = new object ();
  67. [Browsable (false)]
  68. [EditorBrowsable (EditorBrowsableState.Never)]
  69. public new event EventHandler AutoSizeChanged {
  70. add { base.AutoSizeChanged += value; }
  71. remove { base.AutoSizeChanged -= value; }
  72. }
  73. [Browsable (true)]
  74. [EditorBrowsable (EditorBrowsableState.Always)]
  75. public new event EventHandler BackgroundImageChanged {
  76. add { base.BackgroundImageChanged += value; }
  77. remove { base.BackgroundImageChanged -= value; }
  78. }
  79. [Browsable (false)]
  80. [EditorBrowsable (EditorBrowsableState.Never)]
  81. public new event EventHandler BackgroundImageLayoutChanged {
  82. add { base.BackgroundImageLayoutChanged += value; }
  83. remove { base.BackgroundImageLayoutChanged -= value; }
  84. }
  85. [Browsable (false)]
  86. [EditorBrowsable (EditorBrowsableState.Never)]
  87. public new event ControlEventHandler ControlAdded {
  88. add { base.ControlAdded += value; }
  89. remove { base.ControlAdded -= value; }
  90. }
  91. [Browsable (false)]
  92. [EditorBrowsable (EditorBrowsableState.Never)]
  93. public new event ControlEventHandler ControlRemoved {
  94. add { base.ControlRemoved += value; }
  95. remove { base.ControlRemoved -= value; }
  96. }
  97. [Browsable (false)]
  98. [EditorBrowsable (EditorBrowsableState.Never)]
  99. public new event EventHandler PaddingChanged {
  100. add { base.PaddingChanged += value; }
  101. remove { base.PaddingChanged -= value; }
  102. }
  103. public event SplitterEventHandler SplitterMoved {
  104. add { Events.AddHandler (SplitterMovedEvent, value); }
  105. remove { Events.RemoveHandler (SplitterMovedEvent, value); }
  106. }
  107. public event SplitterCancelEventHandler SplitterMoving {
  108. add { Events.AddHandler (SplitterMovingEvent, value); }
  109. remove { Events.RemoveHandler (SplitterMovingEvent, value); }
  110. }
  111. [Browsable (false)]
  112. [EditorBrowsable (EditorBrowsableState.Never)]
  113. public new event EventHandler TextChanged {
  114. add { base.TextChanged += value; }
  115. remove { base.TextChanged -= value; }
  116. }
  117. #endregion
  118. #region UIA Framework Events
  119. static object UIACanResizeChangedEvent = new object ();
  120. internal event EventHandler UIACanResizeChanged {
  121. add { Events.AddHandler (UIACanResizeChangedEvent, value); }
  122. remove { Events.RemoveHandler (UIACanResizeChangedEvent, value); }
  123. }
  124. internal void OnUIACanResizeChanged (EventArgs e)
  125. {
  126. EventHandler eh = (EventHandler) Events [UIACanResizeChangedEvent];
  127. if (eh != null)
  128. eh (this, e);
  129. }
  130. #endregion
  131. #region Public Constructors
  132. public SplitContainer ()
  133. {
  134. SetStyle (ControlStyles.SupportsTransparentBackColor, true);
  135. SetStyle (ControlStyles.OptimizedDoubleBuffer, true);
  136. fixed_panel = FixedPanel.None;
  137. orientation = Orientation.Vertical;
  138. splitter_rectangle = new Rectangle (50, 0, 4, this.Height);
  139. splitter_increment = 1;
  140. splitter_prev_move = -1;
  141. restore_cursor = null;
  142. splitter_fixed = false;
  143. panel1_collapsed = false;
  144. panel2_collapsed = false;
  145. panel1_min_size = 25;
  146. panel2_min_size = 25;
  147. panel1 = new SplitterPanel (this);
  148. panel2 = new SplitterPanel (this);
  149. panel1.Size = new Size (50, 50);
  150. UpdateSplitter ();
  151. this.Controls.Add (panel2);
  152. this.Controls.Add (panel1);
  153. }
  154. #endregion
  155. #region Public Properties
  156. [Browsable (false)]
  157. [EditorBrowsable (EditorBrowsableState.Never)]
  158. [Localizable (true)]
  159. [DefaultValue (false)]
  160. public override bool AutoScroll {
  161. get { return base.AutoScroll; }
  162. set { base.AutoScroll = value; }
  163. }
  164. [Browsable (false)]
  165. [EditorBrowsable (EditorBrowsableState.Never)]
  166. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  167. new public Size AutoScrollMargin {
  168. get { return base.AutoScrollMargin; }
  169. set { base.AutoScrollMargin = value; }
  170. }
  171. [Browsable (false)]
  172. [EditorBrowsable (EditorBrowsableState.Never)]
  173. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  174. new public Size AutoScrollMinSize {
  175. get { return base.AutoScrollMinSize; }
  176. set { base.AutoScrollMinSize = value; }
  177. }
  178. [Browsable (false)]
  179. [DefaultValue ("{X=0,Y=0}")]
  180. [EditorBrowsable (EditorBrowsableState.Never)]
  181. public override Point AutoScrollOffset {
  182. get { return base.AutoScrollOffset; }
  183. set { base.AutoScrollOffset = value; }
  184. }
  185. [Browsable (false)]
  186. [EditorBrowsable (EditorBrowsableState.Never)]
  187. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  188. new public Point AutoScrollPosition {
  189. get { return base.AutoScrollPosition; }
  190. set { base.AutoScrollPosition = value; }
  191. }
  192. [Browsable (false)]
  193. [EditorBrowsable (EditorBrowsableState.Never)]
  194. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  195. public override bool AutoSize {
  196. get { return base.AutoSize; }
  197. set { base.AutoSize = value; }
  198. }
  199. [Browsable (true)]
  200. [EditorBrowsable (EditorBrowsableState.Always)]
  201. public override Image BackgroundImage {
  202. get { return base.BackgroundImage; }
  203. set { base.BackgroundImage = value; }
  204. }
  205. [Browsable (false)]
  206. [EditorBrowsable (EditorBrowsableState.Never)]
  207. public override ImageLayout BackgroundImageLayout {
  208. get { return base.BackgroundImageLayout; }
  209. set { base.BackgroundImageLayout = value; }
  210. }
  211. [Browsable (false)]
  212. public override BindingContext BindingContext {
  213. get { return base.BindingContext; }
  214. set { base.BindingContext = value; }
  215. }
  216. // MSDN says default is Fixed3D, creating a new SplitContainer says otherwise.
  217. [DefaultValue (BorderStyle.None)]
  218. [DispId (-504)]
  219. public BorderStyle BorderStyle {
  220. get { return panel1.BorderStyle; }
  221. set {
  222. if (!Enum.IsDefined (typeof (BorderStyle), value))
  223. throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for BorderStyle", value));
  224. panel1.BorderStyle = value;
  225. panel2.BorderStyle = value;
  226. }
  227. }
  228. [EditorBrowsable (EditorBrowsableState.Never)]
  229. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  230. new public ControlCollection Controls { get { return base.Controls; } }
  231. new public DockStyle Dock {
  232. get { return base.Dock; }
  233. set { base.Dock = value; }
  234. }
  235. [DefaultValue (FixedPanel.None)]
  236. public FixedPanel FixedPanel {
  237. get { return this.fixed_panel; }
  238. set {
  239. if (!Enum.IsDefined (typeof (FixedPanel), value))
  240. throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for FixedPanel", value));
  241. this.fixed_panel = value;
  242. }
  243. }
  244. [Localizable (true)]
  245. [DefaultValue (false)]
  246. public bool IsSplitterFixed {
  247. get { return splitter_fixed; }
  248. set { splitter_fixed = value; }
  249. }
  250. [Localizable (true)]
  251. [DefaultValue (Orientation.Vertical)]
  252. public Orientation Orientation {
  253. get { return this.orientation; }
  254. set {
  255. if (!Enum.IsDefined (typeof (Orientation), value))
  256. throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for Orientation", value));
  257. if (this.orientation != value) {
  258. if (value == Orientation.Vertical) {
  259. splitter_rectangle.Width = splitter_rectangle.Height;
  260. splitter_rectangle.X = splitter_rectangle.Y;
  261. } else {
  262. splitter_rectangle.Height = splitter_rectangle.Width;
  263. splitter_rectangle.Y = splitter_rectangle.X;
  264. }
  265. this.orientation = value;
  266. this.UpdateSplitter ();
  267. }
  268. }
  269. }
  270. [Browsable (false)]
  271. [EditorBrowsable (EditorBrowsableState.Never)]
  272. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  273. new public Padding Padding {
  274. get { return base.Padding; }
  275. set { base.Padding = value; }
  276. }
  277. [Localizable (false)]
  278. [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
  279. public SplitterPanel Panel1 { get { return this.panel1; } }
  280. [DefaultValue (false)]
  281. public bool Panel1Collapsed {
  282. get { return this.panel1_collapsed; }
  283. set {
  284. if (panel1_collapsed != value) {
  285. this.panel1_collapsed = value;
  286. panel1.Visible = !value;
  287. // UIA Framework Event: CanResize Changed
  288. OnUIACanResizeChanged (EventArgs.Empty);
  289. PerformLayout ();
  290. }
  291. }
  292. }
  293. [Localizable (true)]
  294. [DefaultValue (25)]
  295. [RefreshProperties (RefreshProperties.All)]
  296. public int Panel1MinSize {
  297. get { return this.panel1_min_size; }
  298. set {
  299. this.panel1_min_size = value;
  300. }
  301. }
  302. [Localizable (false)]
  303. [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
  304. public SplitterPanel Panel2 { get { return this.panel2; } }
  305. [DefaultValue (false)]
  306. public bool Panel2Collapsed {
  307. get { return this.panel2_collapsed; }
  308. set {
  309. if (panel2_collapsed != value) {
  310. this.panel2_collapsed = value;
  311. panel2.Visible = !value;
  312. // UIA Framework Event: CanResize Changed
  313. OnUIACanResizeChanged (EventArgs.Empty);
  314. PerformLayout ();
  315. }
  316. }
  317. }
  318. [Localizable (true)]
  319. [DefaultValue (25)]
  320. [RefreshProperties (RefreshProperties.All)]
  321. public int Panel2MinSize {
  322. get { return this.panel2_min_size; }
  323. set { this.panel2_min_size = value; }
  324. }
  325. // MSDN says the default is 40, MS's implementation defaults to 50.
  326. [Localizable (true)]
  327. [DefaultValue (50)]
  328. [SettingsBindable (true)]
  329. public int SplitterDistance {
  330. get {
  331. if (orientation == Orientation.Vertical)
  332. return this.splitter_rectangle.X;
  333. else
  334. return this.splitter_rectangle.Y;
  335. }
  336. set {
  337. if (value < 0)
  338. throw new ArgumentOutOfRangeException ();
  339. if (value < panel1_min_size)
  340. value = panel1_min_size;
  341. bool updated = true;
  342. if (orientation == Orientation.Vertical) {
  343. if (this.Width - (this.SplitterWidth + value) < panel2_min_size)
  344. value = this.Width - (this.SplitterWidth + panel2_min_size);
  345. if (splitter_rectangle.X != value) {
  346. splitter_rectangle.X = value;
  347. updated = true;
  348. }
  349. } else {
  350. if (this.Height - (this.SplitterWidth + value) < panel2_min_size)
  351. value = this.Height - (this.SplitterWidth + panel2_min_size);
  352. if (splitter_rectangle.Y != value) {
  353. splitter_rectangle.Y = value;
  354. updated = true;
  355. }
  356. }
  357. if (updated) {
  358. UpdateSplitter ();
  359. OnSplitterMoved (new SplitterEventArgs (Left, Top, splitter_rectangle.X, splitter_rectangle.Y));
  360. }
  361. }
  362. }
  363. [Localizable (true)]
  364. [DefaultValue (1)]
  365. [MonoTODO ("Stub, never called")]
  366. public int SplitterIncrement {
  367. get { return this.splitter_increment; }
  368. set { this.splitter_increment = value; }
  369. }
  370. [Browsable (false)]
  371. public Rectangle SplitterRectangle { get { return splitter_rectangle; } }
  372. [Localizable (true)]
  373. [DefaultValue (4)]
  374. public int SplitterWidth {
  375. get {
  376. if (orientation == Orientation.Vertical)
  377. return this.splitter_rectangle.Width;
  378. else
  379. return this.splitter_rectangle.Height;
  380. }
  381. set {
  382. if (value < 1)
  383. throw new ArgumentOutOfRangeException ();
  384. if (orientation == Orientation.Vertical)
  385. this.splitter_rectangle.Width = value;
  386. else
  387. this.splitter_rectangle.Height = value;
  388. UpdateSplitter ();
  389. }
  390. }
  391. [DispId (-516)]
  392. [DefaultValue (true)]
  393. [MonoTODO ("Stub, never called")]
  394. new public bool TabStop {
  395. get { return false; }
  396. set { }
  397. }
  398. [Browsable (false)]
  399. [EditorBrowsable (EditorBrowsableState.Never)]
  400. [Bindable (false)]
  401. public override string Text {
  402. get { return base.Text; }
  403. set { base.Text = value; }
  404. }
  405. #endregion
  406. #region Protected Properties
  407. protected override Size DefaultSize { get { return new Size (150, 100); } }
  408. #endregion
  409. #region Public Methods
  410. [MonoTODO]
  411. public void BeginInit ()
  412. {
  413. }
  414. [MonoTODO]
  415. public void EndInit ()
  416. {
  417. }
  418. public void OnSplitterMoved (SplitterEventArgs e)
  419. {
  420. SplitterEventHandler eh = (SplitterEventHandler)(Events [SplitterMovedEvent]);
  421. if (eh != null)
  422. eh (this, e);
  423. }
  424. public void OnSplitterMoving (SplitterCancelEventArgs e)
  425. {
  426. SplitterCancelEventHandler eh = (SplitterCancelEventHandler)(Events [SplitterMovingEvent]);
  427. if (eh != null)
  428. eh (this, e);
  429. }
  430. #endregion
  431. #region Protected Methods
  432. [EditorBrowsable (EditorBrowsableState.Advanced)]
  433. protected override ControlCollection CreateControlsInstance ()
  434. {
  435. return new SplitContainerTypedControlCollection (this);
  436. }
  437. protected override void OnGotFocus (EventArgs e)
  438. {
  439. base.OnGotFocus (e);
  440. }
  441. protected override void OnKeyDown (KeyEventArgs e)
  442. {
  443. base.OnKeyDown (e);
  444. }
  445. protected override void OnKeyUp (KeyEventArgs e)
  446. {
  447. base.OnKeyUp (e);
  448. }
  449. protected override void OnLayout (LayoutEventArgs e)
  450. {
  451. UpdateLayout ();
  452. base.OnLayout (e);
  453. }
  454. protected override void OnLostFocus (EventArgs e)
  455. {
  456. base.OnLostFocus (e);
  457. }
  458. protected override void OnMouseCaptureChanged (EventArgs e)
  459. {
  460. base.OnMouseCaptureChanged (e);
  461. }
  462. protected override void OnMouseDown (MouseEventArgs e)
  463. {
  464. base.OnMouseDown (e);
  465. if (!splitter_fixed && SplitterHitTest (e.Location)) {
  466. splitter_dragging = true;
  467. SplitterBeginMove (e.Location);
  468. }
  469. }
  470. protected override void OnMouseLeave (EventArgs e)
  471. {
  472. base.OnMouseLeave (e);
  473. SplitterRestoreCursor ();
  474. }
  475. [EditorBrowsable (EditorBrowsableState.Advanced)]
  476. protected override void OnMouseMove (MouseEventArgs e)
  477. {
  478. base.OnMouseMove (e);
  479. if (splitter_dragging)
  480. SplitterMove (e.Location);
  481. if (!splitter_fixed && SplitterHitTest (e.Location))
  482. SplitterSetCursor (orientation);
  483. }
  484. protected override void OnMouseUp (MouseEventArgs e)
  485. {
  486. base.OnMouseUp (e);
  487. if (splitter_dragging) {
  488. SplitterEndMove (e.Location, false);
  489. SplitterRestoreCursor ();
  490. splitter_dragging = false;
  491. }
  492. }
  493. protected override void OnPaint (PaintEventArgs e)
  494. {
  495. base.OnPaint (e);
  496. }
  497. [EditorBrowsable (EditorBrowsableState.Advanced)]
  498. protected override void OnRightToLeftChanged (EventArgs e)
  499. {
  500. base.OnRightToLeftChanged (e);
  501. }
  502. protected override bool ProcessDialogKey (Keys keyData)
  503. {
  504. return base.ProcessDialogKey (keyData);
  505. }
  506. protected override bool ProcessTabKey (bool forward)
  507. {
  508. return base.ProcessTabKey (forward);
  509. }
  510. [EditorBrowsable (EditorBrowsableState.Advanced)]
  511. protected override void ScaleControl (SizeF factor, BoundsSpecified specified)
  512. {
  513. base.ScaleControl (factor, specified);
  514. }
  515. protected override void Select (bool directed, bool forward)
  516. {
  517. base.Select (directed, forward);
  518. }
  519. protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
  520. {
  521. base.SetBoundsCore (x, y, width, height, specified);
  522. }
  523. protected override void WndProc (ref Message msg)
  524. {
  525. base.WndProc (ref msg);
  526. }
  527. #endregion
  528. #region Private Methods
  529. private bool SplitterHitTest (Point location)
  530. {
  531. if (location.X >= splitter_rectangle.X &&
  532. location.X <= splitter_rectangle.X + splitter_rectangle.Width &&
  533. location.Y >= splitter_rectangle.Y &&
  534. location.Y <= splitter_rectangle.Y + splitter_rectangle.Height) {
  535. return true;
  536. }
  537. return false;
  538. }
  539. private void SplitterBeginMove (Point location)
  540. {
  541. splitter_prev_move = orientation == Orientation.Vertical ? location.X : location.Y;
  542. splitter_rectangle_moving = splitter_rectangle;
  543. splitter_rectangle_before_move = splitter_rectangle;
  544. }
  545. private void SplitterMove (Point location)
  546. {
  547. int currentMove = orientation == Orientation.Vertical ? location.X : location.Y;
  548. int delta = currentMove - splitter_prev_move;
  549. Rectangle prev_location = splitter_rectangle_moving;
  550. bool moved = false;
  551. if (orientation == Orientation.Vertical) {
  552. int min = panel1_min_size;
  553. int max = panel2.Location.X + (panel2.Width - this.panel2_min_size) - splitter_rectangle_moving.Width;
  554. if (splitter_rectangle_moving.X + delta > min && splitter_rectangle_moving.X + delta < max) {
  555. splitter_rectangle_moving.X += delta;
  556. moved = true;
  557. } else {
  558. // Ensure that the splitter is set to minimum or maximum position,
  559. // even if the mouse "skips".
  560. //
  561. if (splitter_rectangle_moving.X + delta <= min && splitter_rectangle_moving.X != min) {
  562. splitter_rectangle_moving.X = min;
  563. moved = true;
  564. } else if (splitter_rectangle_moving.X + delta >= max && splitter_rectangle_moving.X != max) {
  565. splitter_rectangle_moving.X = max;
  566. moved = true;
  567. }
  568. }
  569. } else if (orientation == Orientation.Horizontal) {
  570. int min = panel1_min_size;
  571. int max = panel2.Location.Y + (panel2.Height - this.panel2_min_size) - splitter_rectangle_moving.Height;
  572. if (splitter_rectangle_moving.Y + delta > min && splitter_rectangle_moving.Y + delta < max) {
  573. splitter_rectangle_moving.Y += delta;
  574. moved = true;
  575. } else {
  576. // Ensure that the splitter is set to minimum or maximum position,
  577. // even if the mouse "skips".
  578. //
  579. if (splitter_rectangle_moving.Y + delta <= min && splitter_rectangle_moving.Y != min) {
  580. splitter_rectangle_moving.Y = min;
  581. moved = true;
  582. } else if (splitter_rectangle_moving.Y + delta >= max && splitter_rectangle_moving.Y != max) {
  583. splitter_rectangle_moving.Y = max;
  584. moved = true;
  585. }
  586. }
  587. }
  588. if (moved) {
  589. splitter_prev_move = currentMove;
  590. OnSplitterMoving (new SplitterCancelEventArgs (location.X, location.Y,
  591. splitter_rectangle.X, splitter_rectangle.Y));
  592. XplatUI.DrawReversibleRectangle (this.Handle, prev_location, 1);
  593. XplatUI.DrawReversibleRectangle (this.Handle, splitter_rectangle_moving, 1);
  594. }
  595. }
  596. private void SplitterEndMove (Point location, bool cancel)
  597. {
  598. if (!cancel) {
  599. // Prevent updating the splitter distance if the user changes it in e.g. the
  600. // DoubleClick handler, but no delta move has happened in our drag-handling.
  601. // We don't compare to splitter_rectangle for exactly that reason here
  602. // (if it gets changed externally) and compare to a cached value.
  603. //
  604. if (splitter_rectangle_before_move != splitter_rectangle_moving) {
  605. splitter_rectangle = splitter_rectangle_moving;
  606. UpdateSplitter ();
  607. }
  608. }
  609. SplitterEventArgs args = new SplitterEventArgs (location.X, location.Y,
  610. splitter_rectangle.X, splitter_rectangle.Y);
  611. OnSplitterMoved (args);
  612. }
  613. private void SplitterSetCursor (Orientation orientation)
  614. {
  615. if (restore_cursor == null)
  616. restore_cursor = this.Cursor;
  617. this.Cursor = orientation == Orientation.Vertical ? Cursors.VSplit : Cursors.HSplit;
  618. }
  619. private void SplitterRestoreCursor ()
  620. {
  621. if (restore_cursor != null) {
  622. this.Cursor = restore_cursor;
  623. restore_cursor = null;
  624. }
  625. }
  626. private void UpdateSplitter ()
  627. {
  628. this.SuspendLayout ();
  629. panel1.SuspendLayout ();
  630. panel2.SuspendLayout ();
  631. if (panel1_collapsed) {
  632. panel2.Size = this.Size;
  633. panel2.Location = new Point (0, 0);
  634. } else if (panel2_collapsed) {
  635. panel1.Size = this.Size;
  636. panel1.Location = new Point (0, 0);
  637. } else {
  638. panel1.Location = new Point (0, 0);
  639. if (orientation == Orientation.Vertical) {
  640. splitter_rectangle.Y = 0;
  641. panel1.InternalHeight = panel2.InternalHeight = this.Height;
  642. panel1.InternalWidth = Math.Max (this.SplitterDistance, panel1_min_size);
  643. panel2.Location = new Point (this.SplitterWidth + this.SplitterDistance, 0);
  644. panel2.InternalWidth = Math.Max (this.Width - (this.SplitterWidth + this.SplitterDistance), panel2_min_size);
  645. fixed_none_ratio = (double) this.Width / (double)this.SplitterDistance;
  646. } else if (orientation == Orientation.Horizontal) {
  647. splitter_rectangle.X = 0;
  648. panel1.InternalWidth = panel2.InternalWidth = this.Width;
  649. panel1.InternalHeight = Math.Max (this.SplitterDistance, panel1_min_size);
  650. panel2.Location = new Point (0, this.SplitterWidth + this.SplitterDistance);
  651. panel2.InternalHeight = Math.Max (this.Height - (this.SplitterWidth + this.SplitterDistance), panel2_min_size);
  652. fixed_none_ratio = (double) this.Height / (double)this.SplitterDistance;
  653. }
  654. }
  655. panel1.ResumeLayout ();
  656. panel2.ResumeLayout ();
  657. this.ResumeLayout ();
  658. }
  659. private void UpdateLayout ()
  660. {
  661. panel1.SuspendLayout ();
  662. panel2.SuspendLayout ();
  663. if (panel1_collapsed) {
  664. panel2.Size = this.Size;
  665. panel2.Location = new Point (0, 0);
  666. } else if (panel2_collapsed) {
  667. panel1.Size = this.Size;
  668. panel1.Location = new Point (0, 0);
  669. } else {
  670. panel1.Location = new Point (0, 0);
  671. if (orientation == Orientation.Vertical) {
  672. panel1.Location = new Point (0, 0);
  673. panel1.InternalHeight = panel2.InternalHeight = this.Height;
  674. splitter_rectangle.Height = this.Height;
  675. if (fixed_panel == FixedPanel.None) {
  676. splitter_rectangle.X = Math.Max ((int)Math.Floor (((double)this.Width) / fixed_none_ratio), panel1_min_size); //set distance
  677. panel1.InternalWidth = this.SplitterDistance;
  678. panel2.InternalWidth = this.Width - (this.SplitterWidth + this.SplitterDistance);
  679. panel2.Location = new Point (this.SplitterWidth + this.SplitterDistance, 0);
  680. } else if (fixed_panel == FixedPanel.Panel1) {
  681. panel1.InternalWidth = this.SplitterDistance;
  682. panel2.InternalWidth = Math.Max (this.Width - (this.SplitterWidth + this.SplitterDistance), panel2_min_size);
  683. panel2.Location = new Point (this.SplitterWidth + this.SplitterDistance, 0);
  684. } else if (fixed_panel == FixedPanel.Panel2) {
  685. splitter_rectangle.X = Math.Max (this.Width - (this.SplitterWidth + panel2.Width), panel1_min_size); //set distance
  686. panel1.InternalWidth = this.SplitterDistance;
  687. panel2.Location = new Point (this.SplitterWidth + this.SplitterDistance, 0);
  688. }
  689. } else if (orientation == Orientation.Horizontal) {
  690. panel1.Location = new Point (0, 0);
  691. panel1.InternalWidth = panel2.InternalWidth = this.Width;
  692. splitter_rectangle.Width = this.Width;
  693. if (fixed_panel == FixedPanel.None) {
  694. splitter_rectangle.Y = Math.Max ((int) Math.Floor ((double)this.Height / fixed_none_ratio), panel1_min_size); //set distance
  695. panel1.InternalHeight = this.SplitterDistance;
  696. panel2.InternalHeight = this.Height - (this.SplitterWidth + this.SplitterDistance);
  697. panel2.Location = new Point (0, this.SplitterWidth + this.SplitterDistance);
  698. } else if (fixed_panel == FixedPanel.Panel1) {
  699. panel1.InternalHeight = this.SplitterDistance;
  700. panel2.InternalHeight = Math.Max (this.Height - (this.SplitterWidth + this.SplitterDistance), panel2_min_size);
  701. panel2.Location = new Point (0, this.SplitterWidth + this.SplitterDistance);
  702. } else if (fixed_panel == FixedPanel.Panel2) {
  703. splitter_rectangle.Y = Math.Max (this.Height - (this.SplitterWidth + panel2.Height), panel1_min_size); //set distance
  704. panel1.InternalHeight = this.SplitterDistance;
  705. panel2.Location = new Point (0, this.SplitterWidth + this.SplitterDistance);
  706. }
  707. }
  708. }
  709. panel1.ResumeLayout ();
  710. panel2.ResumeLayout ();
  711. }
  712. #endregion
  713. #region Internal Classes
  714. internal class SplitContainerTypedControlCollection : ControlCollection
  715. {
  716. public SplitContainerTypedControlCollection (Control owner) : base (owner)
  717. {
  718. }
  719. }
  720. #endregion
  721. }
  722. }