using DevComponents.DotNetBar.Rendering; using DevComponents.Editors; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Reflection; using System.Text; using System.Windows.Forms; namespace DevComponents.DotNetBar.Controls { [ToolboxBitmap(typeof(CollapsibleSplitContainer), "Controls.CollapsibleSplitContainer.ico")] public class CollapsibleSplitContainer : SplitContainer { #region Constructor /// /// Initializes a new instance of the CollapsibleSplitContainer class. /// public CollapsibleSplitContainer() { ControlStyles cs = ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer; this.SetStyle(cs, true); object[] objArgs = new object[] { cs, true }; MethodInfo mi = typeof(Control).GetMethod("SetStyle", BindingFlags.NonPublic | BindingFlags.Instance); if (mi != null) { mi.Invoke(this.Panel1, objArgs); mi.Invoke(this.Panel2, objArgs); } this.SplitterWidth = 20; _OverrideCursorPropInfo = typeof(SplitContainer).GetProperty("OverrideCursor", BindingFlags.NonPublic | BindingFlags.Instance); this.SplitterMoved += SplitterMovedHandler; } protected override void Dispose(bool disposing) { this.SplitterMoved -= SplitterMovedHandler; base.Dispose(disposing); } #endregion #region Implementation private Rectangle _NearCollapseButton = Rectangle.Empty; private Rectangle _FarCollapseButton = Rectangle.Empty; private eButtonState _NearCollapseButtonState = eButtonState.Normal, _FarCollapseButtonState = eButtonState.Normal; private const int ButtonSpacing = 2; private void UpdateButtonLayout() { Rectangle r = this.SplitterRectangle; Size buttonSize = new Size(this.SplitterWidth, this.SplitterWidth); if (this.Orientation == System.Windows.Forms.Orientation.Horizontal) { if (_ButtonPosition == eSplitterButtonPosition.Near) { _NearCollapseButton = new Rectangle(r.X, r.Y, buttonSize.Width, buttonSize.Height); _FarCollapseButton = new Rectangle(_NearCollapseButton.Right + ButtonSpacing, r.Y, buttonSize.Width, buttonSize.Height); } else if (_ButtonPosition == eSplitterButtonPosition.Center) { _NearCollapseButton = new Rectangle(r.X + (r.Width - (buttonSize.Width * 2 + ButtonSpacing)) / 2, r.Y, buttonSize.Width, buttonSize.Height); _FarCollapseButton = new Rectangle(_NearCollapseButton.Right + ButtonSpacing, r.Y, buttonSize.Width, buttonSize.Height); } else if (_ButtonPosition == eSplitterButtonPosition.Far) { _NearCollapseButton = new Rectangle(r.Right - buttonSize.Width * 2 - ButtonSpacing, r.Y, buttonSize.Width, buttonSize.Height); _FarCollapseButton = new Rectangle(_NearCollapseButton.Right + ButtonSpacing, r.Y, buttonSize.Width, buttonSize.Height); } } else { if (_ButtonPosition == eSplitterButtonPosition.Near) { _NearCollapseButton = new Rectangle(r.X, r.Y, buttonSize.Width, buttonSize.Height); _FarCollapseButton = new Rectangle(r.X, _NearCollapseButton.Bottom + ButtonSpacing, buttonSize.Width, buttonSize.Height); } else if (_ButtonPosition == eSplitterButtonPosition.Center) { _NearCollapseButton = new Rectangle(r.X, r.Y + (r.Height - (buttonSize.Height * 2 + ButtonSpacing)) / 2, buttonSize.Width, buttonSize.Height); _FarCollapseButton = new Rectangle(r.X, _NearCollapseButton.Bottom + ButtonSpacing, buttonSize.Width, buttonSize.Height); } else if (_ButtonPosition == eSplitterButtonPosition.Far) { _NearCollapseButton = new Rectangle(r.X, r.Bottom - buttonSize.Height * 2 - ButtonSpacing, buttonSize.Width, buttonSize.Height); _FarCollapseButton = new Rectangle(r.X, _NearCollapseButton.Bottom + ButtonSpacing, buttonSize.Width, buttonSize.Height); } } } protected override void OnPaint(PaintEventArgs e) { UpdateButtonLayout(); base.OnPaint(e); Graphics g = e.Graphics; bool isHorizontal = this.Orientation == System.Windows.Forms.Orientation.Horizontal; if (_NearCollapseButtonState != eButtonState.Hidden) { Office2007ButtonItemStateColorTable ct = GetOffice2007StateColorTable(_NearCollapseButtonState); Office2007ButtonItemPainter.PaintBackground(g, ct, _NearCollapseButton, RoundRectangleShapeDescriptor.RectangleShape); Rectangle r = _NearCollapseButton; r.Inflate(-2, -2); TextDrawing.DrawStringLegacy(g, isHorizontal ? "\uf077" : "\uf053", Symbols.GetFont(9f, eSymbolSet.Awesome), ct.Text, r, eTextFormat.HorizontalCenter | eTextFormat.VerticalCenter); } if (_FarCollapseButtonState != eButtonState.Hidden) { Office2007ButtonItemStateColorTable ct = GetOffice2007StateColorTable(_FarCollapseButtonState); Office2007ButtonItemPainter.PaintBackground(g, ct, _FarCollapseButton, RoundRectangleShapeDescriptor.RectangleShape); Rectangle r = _FarCollapseButton; r.Inflate(-2, -2); TextDrawing.DrawStringLegacy(g, isHorizontal ? "\uf078" : "\uf054", Symbols.GetFont(9f, eSymbolSet.Awesome), ct.Text, r, eTextFormat.HorizontalCenter | eTextFormat.VerticalCenter); } } protected Office2007ButtonItemStateColorTable GetOffice2007StateColorTable(eButtonState state) { if (GlobalManager.Renderer is Office2007Renderer) { Office2007ColorTable ct = ((Office2007Renderer)GlobalManager.Renderer).ColorTable; Office2007ButtonItemColorTable buttonColorTable = ct.ButtonItemColors[Enum.GetName(typeof(eButtonColor), eButtonColor.OrangeWithBackground)]; if (!this.Enabled || state == eButtonState.Disabled) return buttonColorTable.Disabled; else if (state == eButtonState.MouseDownLeft) return buttonColorTable.Pressed; else if (state == eButtonState.MouseOver) return buttonColorTable.MouseOver; else return buttonColorTable.Default; } return null; } private Orientation _CurrentOrientation = Orientation.Vertical; protected override void OnLayout(LayoutEventArgs e) { base.OnLayout(e); if (_CurrentOrientation != this.Orientation) { _CurrentOrientation = this.Orientation; UpdateButtonLayout(); } Invalidate(); } private bool IsButtonActive(eButtonState state) { return state != eButtonState.Hidden && state != eButtonState.Disabled; } private Cursor _OriginalCursor = null; protected override void OnMouseMove(MouseEventArgs e) { if (IsButtonActive(_NearCollapseButtonState)) { if (_NearCollapseButton.Contains(e.Location)) { if (_NearCollapseButtonState == eButtonState.Normal) { _NearCollapseButtonState = eButtonState.MouseOver; this.Invalidate(); } } else { _NearCollapseButtonState = eButtonState.Normal; this.Invalidate(); } } if (IsButtonActive(_FarCollapseButtonState)) { if (_FarCollapseButton.Contains(e.Location)) { if (_FarCollapseButtonState == eButtonState.Normal) { _FarCollapseButtonState = eButtonState.MouseOver; this.Invalidate(); } } else { _FarCollapseButtonState = eButtonState.Normal; this.Invalidate(); } } if (_NearCollapseButton.Contains(e.Location) || _FarCollapseButton.Contains(e.Location)) { if (_OriginalCursor == null && _OverrideCursorPropInfo != null) { _OriginalCursor = (Cursor)_OverrideCursorPropInfo.GetValue(this, null); _OverrideCursorPropInfo.SetValue(this, Cursors.Default, null); } return; } RestoreOriginalCursor(); base.OnMouseMove(e); } private PropertyInfo _OverrideCursorPropInfo = null; private void RestoreOriginalCursor() { if (_OriginalCursor != null) { _OverrideCursorPropInfo.SetValue(this, _OriginalCursor, null); ; _OriginalCursor = null; } } protected override void OnMouseDown(MouseEventArgs e) { if (IsButtonActive(_NearCollapseButtonState)) { if (_NearCollapseButton.Contains(e.Location) && e.Button == System.Windows.Forms.MouseButtons.Left) { _NearCollapseButtonState = eButtonState.MouseDownLeft; this.Invalidate(); } } if (IsButtonActive(_FarCollapseButtonState)) { if (_FarCollapseButton.Contains(e.Location) && e.Button == System.Windows.Forms.MouseButtons.Left) { _FarCollapseButtonState = eButtonState.MouseDownLeft; this.Invalidate(); } } if (_NearCollapseButton.Contains(e.Location) || _FarCollapseButton.Contains(e.Location)) return; base.OnMouseDown(e); } protected override void OnMouseUp(MouseEventArgs e) { if (IsButtonActive(_NearCollapseButtonState)) { if (_NearCollapseButton.Contains(e.Location)) { if (_NearCollapseButtonState == eButtonState.MouseDownLeft) { _NearCollapseButtonState = eButtonState.MouseOver; // Trigger button action NearCollapseButtonClick(); } this.Invalidate(); } } if (IsButtonActive(_FarCollapseButtonState)) { if (_FarCollapseButton.Contains(e.Location)) { if (_FarCollapseButtonState == eButtonState.MouseDownLeft) { _FarCollapseButtonState = eButtonState.MouseOver; // Trigger button action FarCollapseButtonClick(); } this.Invalidate(); } } if (_NearCollapseButton.Contains(e.Location) || _FarCollapseButton.Contains(e.Location)) return; base.OnMouseUp(e); } protected override void OnKeyUp(KeyEventArgs e) { base.OnKeyUp(e); this.Invalidate(); } // /// Occurs before near collapse button is clicked and allows you to cancel its action. /// [Description("Occurs before near collapse button is clicked and allows you to cancel its action.")] public event CancelEventHandler BeforeNearCollapseButtonClick; /// /// Raises BeforeNearCollapseButtonClick event. /// /// Provides event arguments. protected virtual void OnBeforeNearCollapseButtonClick(CancelEventArgs e) { CancelEventHandler handler = BeforeNearCollapseButtonClick; if (handler != null) handler(this, e); } /// /// Occurs after near collapse button is clicked. /// [Description("Occurs after near collapse button is clicked.")] public event EventHandler NearCollapseButtonClicked; /// /// Raises NearCollapseButtonClick event. /// /// Provides event arguments. protected virtual void OnNearCollapseButtonClicked(EventArgs e) { EventHandler handler = NearCollapseButtonClicked; if (handler != null) handler(this, e); } private int _OriginalSplitterDistance = 0; private bool _IsPanel1Minimized = false; private bool _IsPanel2Minimized = false; private bool _InternalDistanceChange = false; private void NearCollapseButtonClick() { CancelEventArgs e = new CancelEventArgs(); OnBeforeNearCollapseButtonClick(e); if (e.Cancel) return; if (_CollapseMode == eCollapseMode.PanelMinSize) { _InternalDistanceChange = true; try { if (_IsPanel2Minimized) { this.SplitterDistance = _OriginalSplitterDistance; _IsPanel2Minimized = false; _FarCollapseButtonState = eButtonState.Normal; } else if (!_IsPanel1Minimized) { _OriginalSplitterDistance = this.SplitterDistance; this.SplitterDistance = this.Panel1MinSize; _IsPanel1Minimized = true; _NearCollapseButtonState = eButtonState.Disabled; } } finally { _InternalDistanceChange = false; } } else { this.Panel1Collapsed = true; } OnNearCollapseButtonClicked(EventArgs.Empty); } /// /// Occurs before far collapse button is clicked and allows you to cancel its action. /// [Description("Occurs before far collapse button is clicked and allows you to cancel its action.")] public event CancelEventHandler BeforeFarCollapseButtonClick; /// /// Raises BeforeFarCollapseButtonClick event. /// /// Provides event arguments. protected virtual void OnBeforeFarCollapseButtonClick(CancelEventArgs e) { CancelEventHandler handler = BeforeFarCollapseButtonClick; if (handler != null) handler(this, e); } /// /// Occurs after far collapse button is clicked. /// [Description("Occurs after far collapse button is clicked.")] public event EventHandler FarCollapseButtonClicked; /// /// Raises FarCollapseButtonClick event. /// /// Provides event arguments. protected virtual void OnFarCollapseButtonClicked(EventArgs e) { EventHandler handler = FarCollapseButtonClicked; if (handler != null) handler(this, e); } private void FarCollapseButtonClick() { CancelEventArgs e=new CancelEventArgs(); OnBeforeFarCollapseButtonClick(e); if (e.Cancel) return; if (_CollapseMode == eCollapseMode.PanelMinSize) { _InternalDistanceChange = true; try { if (_IsPanel1Minimized) { this.SplitterDistance = _OriginalSplitterDistance; _IsPanel1Minimized = false; _NearCollapseButtonState = eButtonState.Normal; } else if (!_IsPanel2Minimized) { _OriginalSplitterDistance = this.SplitterDistance; if (this.Orientation == System.Windows.Forms.Orientation.Vertical) this.SplitterDistance = this.Width - this.Panel2MinSize; else this.SplitterDistance = this.Height - this.Panel2MinSize; _IsPanel2Minimized = true; _FarCollapseButtonState = eButtonState.Disabled; } } finally { _InternalDistanceChange = false; } } else { this.Panel2Collapsed = true; } OnFarCollapseButtonClicked(EventArgs.Empty); } private void SplitterMovedHandler(object sender, SplitterEventArgs e) { if (_InternalDistanceChange) return; if(_IsPanel1Minimized) { _IsPanel1Minimized = false; _NearCollapseButtonState = eButtonState.Normal; } else if (_IsPanel2Minimized) { _IsPanel2Minimized = false; _FarCollapseButtonState = eButtonState.Normal; } } protected override void OnMouseEnter(EventArgs e) { base.OnMouseEnter(e); } protected override void OnMouseLeave(EventArgs e) { if (IsButtonActive(_NearCollapseButtonState)) { _NearCollapseButtonState = eButtonState.Normal; } if (IsButtonActive(_FarCollapseButtonState)) { _FarCollapseButtonState = eButtonState.Normal; } RestoreOriginalCursor(); Invalidate(); base.OnMouseLeave(e); } private eSplitterButtonPosition _ButtonPosition = eSplitterButtonPosition.Near; /// /// Indicates position of buttons inside container. /// [DefaultValue(eSplitterButtonPosition.Near), Category("Appearance"), Description("Indicates position of buttons inside container.")] public eSplitterButtonPosition ButtonPosition { get { return _ButtonPosition; } set { if (value != _ButtonPosition) { eSplitterButtonPosition oldValue = _ButtonPosition; _ButtonPosition = value; OnButtonPositionChanged(oldValue, value); } } } /// /// Called when ButtonPosition property has changed. /// /// Old property value /// New property value protected virtual void OnButtonPositionChanged(eSplitterButtonPosition oldValue, eSplitterButtonPosition newValue) { UpdateButtonLayout(); this.Invalidate(); //OnPropertyChanged(new PropertyChangedEventArgs("ButtonPosition")); } private eCollapseMode _CollapseMode = eCollapseMode.PanelMinSize; /// /// Specifies how panels are collapsed when collapse buttons are pressed. /// [DefaultValue(eCollapseMode.PanelMinSize), Category("Behavior"), Description("Specifies how panels are collapsed when collapse buttons are pressed.")] public eCollapseMode CollapseMode { get { return _CollapseMode; } set { if (value !=_CollapseMode) { eCollapseMode oldValue = _CollapseMode; _CollapseMode = value; OnCollapseModeChanged(oldValue, value); } } } /// /// Called when CollapseMode property has changed. /// /// Old property value /// New property value protected virtual void OnCollapseModeChanged(eCollapseMode oldValue, eCollapseMode newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("CollapseMode")); } #endregion } /// /// Defines available positions for buttons inside CollapsibleSplitterContainer. /// public enum eSplitterButtonPosition { /// /// Buttons are positioned on left or top side depending on orientation. /// Near, /// /// Buttons are positioned in center of container. /// Center, /// /// Buttons are positioned on right or bottom side depending on orientation. /// Far, } /// /// Defines collapse mode for the CollapsibleSplitContainer control. /// public enum eCollapseMode { /// /// When buttons are pressed the splitter is positioned at the PanelMinSize. /// PanelMinSize, /// /// When buttons are pressed associated panel is collapsed through Panel1Collapsed or Panel2Collapsed properties. /// PanelCollapse } }