[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mcs / class / System.Windows.Forms / System.Windows.Forms / Splitter.cs
blobb465b8418d1ec561c0fb619f0384062dc4a0e1ed
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.
20 // Copyright (c) 2005-2008 Novell, Inc. (http://www.novell.com)
22 // Authors:
23 // Peter Dennis Bartok (pbartok@novell.com)
24 // Ivan N. Zlatev (contact i-nz.net)
28 // COMPLETE
30 #undef Debug
32 using System;
33 using System.ComponentModel;
34 using System.Drawing;
35 using System.Reflection;
36 using System.Runtime.InteropServices;
38 namespace System.Windows.Forms {
39 [ComVisible (true)]
40 [ClassInterface (ClassInterfaceType.AutoDispatch)]
41 [DefaultEvent("SplitterMoved")]
42 [Designer("System.Windows.Forms.Design.SplitterDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
43 [DefaultProperty("Dock")]
44 public class Splitter : Control
46 #region Local Variables
47 static private Cursor splitter_ns;
48 static private Cursor splitter_we;
49 // XXX this "new" shouldn't be here. Control shouldn't define border_style as internal.
50 new private BorderStyle border_style;
51 private int min_extra;
52 private int min_size;
53 private int max_size;
54 private int splitter_size; // Size (width or height) of our splitter control
55 private bool horizontal; // true if we've got a horizontal splitter
56 private Control affected; // The control that the splitter resizes
57 private int split_requested; // If the user requests a position before we have ever laid out the doc
58 private int splitter_prev_move;
59 private Rectangle splitter_rectangle_moving;
60 private int moving_offset;
61 #endregion // Local Variables
63 #region Constructors
64 static Splitter() {
65 splitter_ns = Cursors.HSplit;
66 splitter_we = Cursors.VSplit;
69 public Splitter() {
71 min_extra = 25;
72 min_size = 25;
73 split_requested = -1;
74 splitter_size = 3;
75 horizontal = false;
77 SetStyle(ControlStyles.Selectable, false);
78 Anchor = AnchorStyles.None;
79 Dock = DockStyle.Left;
81 Layout += new LayoutEventHandler(LayoutSplitter);
82 this.ParentChanged += new EventHandler(ReparentSplitter);
83 Cursor = splitter_we;
85 #endregion // Constructors
87 #region Public Instance Properties
88 [Browsable(false)]
89 [EditorBrowsable(EditorBrowsableState.Never)]
90 public override bool AllowDrop {
91 get {
92 return base.AllowDrop;
95 set {
96 base.AllowDrop = value;
100 [Browsable(false)]
101 [DefaultValue(AnchorStyles.None)]
102 [EditorBrowsable(EditorBrowsableState.Never)]
103 public override AnchorStyles Anchor {
104 get {
105 return AnchorStyles.None;
108 set {
109 ; // MS doesn't set it
113 [Browsable(false)]
114 [EditorBrowsable(EditorBrowsableState.Never)]
115 public override Image BackgroundImage {
116 get {
117 return base.BackgroundImage;
120 set {
121 base.BackgroundImage = value;
125 [Browsable (false)]
126 [EditorBrowsable (EditorBrowsableState.Never)]
127 public override ImageLayout BackgroundImageLayout {
128 get { return base.BackgroundImageLayout; }
129 set { base.BackgroundImageLayout = value; }
132 [DispId(-504)]
133 [DefaultValue (BorderStyle.None)]
134 [MWFDescription("Sets the border style for the splitter")]
135 [MWFCategory("Appearance")]
136 public BorderStyle BorderStyle {
137 get {
138 return border_style;
141 set {
142 border_style = value;
144 switch(value) {
145 case BorderStyle.FixedSingle:
146 splitter_size = 4; // We don't get motion events for 1px wide windows on X11. sigh.
147 break;
149 case BorderStyle.Fixed3D:
150 value = BorderStyle.None;
151 splitter_size = 3;
152 break;
154 case BorderStyle.None:
155 splitter_size = 3;
156 break;
158 default:
159 throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for BorderStyle", value));
162 base.InternalBorderStyle = value;
166 [DefaultValue(DockStyle.Left)]
167 [Localizable(true)]
168 public override DockStyle Dock {
169 get {
170 return base.Dock;
173 set {
174 if (!Enum.IsDefined (typeof (DockStyle), value) || (value == DockStyle.None) || (value == DockStyle.Fill)) {
175 throw new ArgumentException("Splitter must be docked left, top, bottom or right");
178 if ((value == DockStyle.Top) || (value == DockStyle.Bottom)) {
179 horizontal = true;
180 Cursor = splitter_ns;
181 } else {
182 horizontal = false;
183 Cursor = splitter_we;
185 base.Dock = value;
189 [Browsable(false)]
190 [EditorBrowsable(EditorBrowsableState.Never)]
191 public override Font Font {
192 get {
193 return base.Font;
196 set {
197 base.Font = value;
201 [Browsable(false)]
202 [EditorBrowsable(EditorBrowsableState.Never)]
203 public override Color ForeColor {
204 get {
205 return base.ForeColor;
208 set {
209 base.ForeColor = value;
213 [Browsable(false)]
214 [EditorBrowsable(EditorBrowsableState.Never)]
215 public new ImeMode ImeMode {
216 get {
217 return base.ImeMode;
220 set {
221 base.ImeMode = value;
225 [DefaultValue(25)]
226 [Localizable(true)]
227 [MWFDescription("Sets minimum size of undocked window")]
228 [MWFCategory("Behaviour")]
229 public int MinExtra {
230 get {
231 return min_extra;
234 set {
235 min_extra = value;
239 [DefaultValue(25)]
240 [Localizable(true)]
241 [MWFDescription("Sets minimum size of the resized control")]
242 [MWFCategory("Behaviour")]
243 public int MinSize {
244 get {
245 return min_size;
248 set {
249 min_size = value;
253 internal int MaxSize {
254 get {
255 if (this.Parent == null)
256 return 0;
258 if (affected == null)
259 affected = AffectedControl;
261 int widths = 0;
262 int heights = 0;
263 int vert_offset = 0;
264 int horiz_offset = 0;
265 foreach (Control c in this.Parent.Controls) {
266 if (c != affected) {
267 switch (c.Dock) {
268 case DockStyle.Left:
269 case DockStyle.Right:
270 widths += c.Width;
272 if (c.Location.X < this.Location.X)
273 vert_offset += c.Width;
274 break;
275 case DockStyle.Top:
276 case DockStyle.Bottom:
277 heights += c.Height;
279 if (c.Location.Y < this.Location.Y)
280 horiz_offset += c.Height;
281 break;
286 if (horizontal) {
287 moving_offset = horiz_offset;
289 return Parent.ClientSize.Height - heights - MinExtra;
290 } else {
291 moving_offset = vert_offset;
293 return Parent.ClientSize.Width - widths - MinExtra;
298 [Browsable(false)]
299 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
300 [MWFDescription("Current splitter position")]
301 [MWFCategory("Layout")]
302 public int SplitPosition {
303 get {
304 affected = AffectedControl;
305 if (affected == null) {
306 return -1;
309 if (Capture) {
310 return CalculateSplitPosition();
313 if (horizontal) {
314 return affected.Height;
315 } else {
316 return affected.Width;
320 set {
321 if (value > MaxSize)
322 value = MaxSize;
323 if (value < MinSize)
324 value = MinSize;
326 affected = AffectedControl;
327 if (affected == null)
328 split_requested = value;
329 else {
330 if (horizontal)
331 affected.Height = value;
332 else
333 affected.Width = value;
334 OnSplitterMoved (new SplitterEventArgs (Left, Top, value, value));
339 [Browsable(false)]
340 [EditorBrowsable(EditorBrowsableState.Never)]
341 public new bool TabStop {
342 get { return base.TabStop; }
343 set { base.TabStop = value; }
346 [Bindable(false)]
347 [Browsable(false)]
348 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
349 [EditorBrowsable(EditorBrowsableState.Never)]
350 public override string Text {
351 get {
352 return base.Text;
355 set {
356 base.Text = value;
360 #endregion // Public Instance Properties
362 #region Protected Instance Properties
363 protected override CreateParams CreateParams {
364 get {
365 return base.CreateParams;
369 protected override Cursor DefaultCursor {
370 get { return base.DefaultCursor; }
373 protected override ImeMode DefaultImeMode {
374 get {
375 return ImeMode.Disable;
379 protected override Size DefaultSize {
380 get {
381 return new Size (3, 3);
384 #endregion // Protected Instance Properties
386 #region Public Instance Methods
387 public override string ToString() {
388 return base.ToString () + String.Format(", MinExtra: {0}, MinSize: {1}", min_extra, min_size);
390 #endregion // Public Instance Methods
392 #region Protected Instance Methods
393 protected override void OnKeyDown(KeyEventArgs e) {
394 base.OnKeyDown (e);
395 if (Capture && (e.KeyCode == Keys.Escape)) {
396 Capture = false;
397 SplitterEndMove (Point.Empty, true);
401 protected override void OnMouseDown(MouseEventArgs e) {
402 base.OnMouseDown (e);
404 // Only allow if we are set up properly
405 if (affected == null)
406 affected = AffectedControl;
407 max_size = MaxSize;
409 if (affected == null || e.Button != MouseButtons.Left)
410 return;
412 Capture = true;
413 SplitterBeginMove (Parent.PointToClient (PointToScreen (new Point (e.X, e.Y))));
416 protected override void OnMouseMove (MouseEventArgs e)
418 base.OnMouseMove (e);
420 if (!Capture || e.Button != MouseButtons.Left || affected == null)
421 return;
423 // We need our mouse coordinates relative to our parent
424 SplitterMove (Parent.PointToClient (PointToScreen (e.Location)));
427 protected override void OnMouseUp (MouseEventArgs e)
429 base.OnMouseUp (e);
430 if (!Capture || e.Button != MouseButtons.Left || affected == null)
431 return;
433 SplitterEndMove (Parent.PointToClient (PointToScreen (e.Location)), false);
434 Capture = false;
437 private void SplitterBeginMove (Point location)
439 splitter_rectangle_moving = new Rectangle (Bounds.X, Bounds.Y,
440 Width, Height);
441 splitter_prev_move = horizontal ? location.Y : location.X;
444 private void SplitterMove (Point location)
446 int currentMove = horizontal ? location.Y : location.X;
447 int delta = currentMove - splitter_prev_move;
448 Rectangle prev_location = splitter_rectangle_moving;
449 bool moved = false;
450 int min = this.MinSize + moving_offset;
451 int max = max_size + moving_offset;
453 if (horizontal) {
454 if (splitter_rectangle_moving.Y + delta > min && splitter_rectangle_moving.Y + delta < max) {
455 splitter_rectangle_moving.Y += delta;
456 moved = true;
457 } else {
458 // Ensure that the splitter is set to minimum or maximum position,
459 // even if the mouse "skips".
461 if (splitter_rectangle_moving.Y + delta <= min && splitter_rectangle_moving.Y != min) {
462 splitter_rectangle_moving.Y = min;
463 moved = true;
464 } else if (splitter_rectangle_moving.Y + delta >= max && splitter_rectangle_moving.Y != max) {
465 splitter_rectangle_moving.Y = max;
466 moved = true;
469 } else {
470 if (splitter_rectangle_moving.X + delta > min && splitter_rectangle_moving.X + delta < max) {
471 splitter_rectangle_moving.X += delta;
472 moved = true;
473 } else {
474 // Ensure that the splitter is set to minimum or maximum position,
475 // even if the mouse "skips".
477 if (splitter_rectangle_moving.X + delta <= min && splitter_rectangle_moving.X != min) {
478 splitter_rectangle_moving.X = min;
479 moved = true;
480 } else if (splitter_rectangle_moving.X + delta >= max && splitter_rectangle_moving.X != max) {
481 splitter_rectangle_moving.X = max;
482 moved = true;
487 if (moved) {
488 splitter_prev_move = currentMove;
489 OnSplitterMoving (new SplitterEventArgs (location.X, location.Y,
490 splitter_rectangle_moving.X,
491 splitter_rectangle_moving.Y));
492 XplatUI.DrawReversibleRectangle (this.Parent.Handle, prev_location, 1);
493 XplatUI.DrawReversibleRectangle (this.Parent.Handle, splitter_rectangle_moving, 1);
497 private void SplitterEndMove (Point location, bool cancel)
499 if (!cancel) {
500 // Resize the affected window
501 if (horizontal)
502 affected.Height = CalculateSplitPosition();
503 else
504 affected.Width = CalculateSplitPosition();
507 this.Parent.Refresh (); // to clean up the drag handle artifacts from all controls
508 SplitterEventArgs args = new SplitterEventArgs (location.X, location.Y,
509 splitter_rectangle_moving.X,
510 splitter_rectangle_moving.Y);
511 OnSplitterMoved (args);
514 protected virtual void OnSplitterMoved(SplitterEventArgs sevent) {
515 SplitterEventHandler eh = (SplitterEventHandler)(Events [SplitterMovedEvent]);
516 if (eh != null)
517 eh (this, sevent);
520 protected virtual void OnSplitterMoving(SplitterEventArgs sevent) {
521 SplitterEventHandler eh = (SplitterEventHandler)(Events [SplitterMovingEvent]);
522 if (eh != null)
523 eh (this, sevent);
526 protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
527 // enforce our width / height
528 if (horizontal) {
529 splitter_size = height;
530 if (splitter_size < 1) {
531 splitter_size = 3;
533 base.SetBoundsCore (x, y, width, splitter_size, specified);
534 } else {
535 splitter_size = width;
536 if (splitter_size < 1) {
537 splitter_size = 3;
539 base.SetBoundsCore (x, y, splitter_size, height, specified);
542 #endregion // Protected Instance Methods
544 #region Private Properties and Methods
545 private Control AffectedControl {
546 get {
547 if (Parent == null)
548 return null;
550 // Doc says the first control preceeding us in the zorder
551 for (int i = Parent.Controls.GetChildIndex(this) + 1; i < Parent.Controls.Count; i++) {
552 switch (Dock) {
553 case DockStyle.Top:
554 if (Top == Parent.Controls[i].Bottom)
555 return Parent.Controls[i];
556 break;
557 case DockStyle.Bottom:
558 if (Bottom == Parent.Controls[i].Top)
559 return Parent.Controls[i];
560 break;
561 case DockStyle.Left:
562 if (Left == Parent.Controls[i].Right)
563 return Parent.Controls[i];
564 break;
565 case DockStyle.Right:
566 if (Right == Parent.Controls[i].Left)
567 return Parent.Controls[i];
568 break;
571 return null;
575 private int CalculateSplitPosition() {
576 if (horizontal) {
577 if (Dock == DockStyle.Top)
578 return splitter_rectangle_moving.Y - affected.Top;
579 else
580 return affected.Bottom - splitter_rectangle_moving.Y - splitter_size;
581 } else {
582 if (Dock == DockStyle.Left)
583 return splitter_rectangle_moving.X - affected.Left;
584 else
585 return affected.Right - splitter_rectangle_moving.X - splitter_size;
589 internal override void OnPaintInternal (PaintEventArgs e) {
590 e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(this.BackColor), e.ClipRectangle);
593 private void LayoutSplitter(object sender, LayoutEventArgs e) {
594 affected = AffectedControl;
595 if (split_requested != -1) {
596 SplitPosition = split_requested;
597 split_requested = -1;
601 private void ReparentSplitter(object sender, EventArgs e) {
602 affected = null;
605 #endregion // Private Properties and Methods
607 #region Events
608 [Browsable(false)]
609 [EditorBrowsable(EditorBrowsableState.Never)]
610 public new event EventHandler BackgroundImageChanged {
611 add { base.BackgroundImageChanged += value; }
612 remove { base.BackgroundImageChanged -= value; }
615 [Browsable (false)]
616 [EditorBrowsable (EditorBrowsableState.Never)]
617 public new event EventHandler BackgroundImageLayoutChanged
619 add { base.BackgroundImageLayoutChanged += value; }
620 remove { base.BackgroundImageLayoutChanged -= value; }
623 [Browsable(false)]
624 [EditorBrowsable(EditorBrowsableState.Never)]
625 public new event EventHandler Enter {
626 add { base.Enter += value; }
627 remove { base.Enter -= value; }
630 [Browsable(false)]
631 [EditorBrowsable(EditorBrowsableState.Never)]
632 public new event EventHandler FontChanged {
633 add { base.FontChanged += value; }
634 remove { base.FontChanged -= value; }
637 [Browsable(false)]
638 [EditorBrowsable(EditorBrowsableState.Never)]
639 public new event EventHandler ForeColorChanged {
640 add { base.ForeColorChanged += value; }
641 remove { base.ForeColorChanged -= value; }
644 [Browsable(false)]
645 [EditorBrowsable(EditorBrowsableState.Never)]
646 public new event EventHandler ImeModeChanged {
647 add { base.ImeModeChanged += value; }
648 remove { base.ImeModeChanged -= value; }
651 [Browsable(false)]
652 [EditorBrowsable(EditorBrowsableState.Never)]
653 public new event KeyEventHandler KeyDown {
654 add { base.KeyDown += value; }
655 remove { base.KeyDown -= value; }
658 [Browsable(false)]
659 [EditorBrowsable(EditorBrowsableState.Never)]
660 public new event KeyPressEventHandler KeyPress {
661 add { base.KeyPress += value; }
662 remove { base.KeyPress -= value; }
665 [Browsable(false)]
666 [EditorBrowsable(EditorBrowsableState.Never)]
667 public new event KeyEventHandler KeyUp {
668 add { base.KeyUp += value; }
669 remove { base.KeyUp -= value; }
672 [Browsable(false)]
673 [EditorBrowsable(EditorBrowsableState.Never)]
674 public new event EventHandler Leave {
675 add { base.Leave += value; }
676 remove { base.Leave -= value; }
679 [Browsable(false)]
680 [EditorBrowsable(EditorBrowsableState.Never)]
681 public new event EventHandler TabStopChanged {
682 add { base.TabStopChanged += value; }
683 remove { base.TabStopChanged -= value; }
686 [Browsable(false)]
687 [EditorBrowsable(EditorBrowsableState.Never)]
688 public new event EventHandler TextChanged {
689 add { base.TextChanged += value; }
690 remove { base.TextChanged -= value; }
693 static object SplitterMovedEvent = new object ();
694 static object SplitterMovingEvent = new object ();
696 public event SplitterEventHandler SplitterMoved {
697 add { Events.AddHandler (SplitterMovedEvent, value); }
698 remove { Events.RemoveHandler (SplitterMovedEvent, value); }
701 public event SplitterEventHandler SplitterMoving {
702 add { Events.AddHandler (SplitterMovingEvent, value); }
703 remove { Events.RemoveHandler (SplitterMovingEvent, value); }
705 #endregion // Events