using System; using System.Collections.Generic; using System.ComponentModel; using System.Data.SqlTypes; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Windows.Forms.VisualStyles; using DevComponents.DotNetBar.Metro; using DevComponents.DotNetBar.Rendering; namespace DevComponents.DotNetBar.Controls { /// /// Represents SideNav control to create "hamburger" menus. /// [ToolboxBitmap(typeof(SideNav), "Controls.SideNav.ico"), ToolboxItem(true),Designer("DevComponents.DotNetBar.Design.SideNavDesigner, DevComponents.DotNetBar.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf"), System.Runtime.InteropServices.ComVisible(false)] public class SideNav : System.Windows.Forms.ContainerControl { #region Constructor private SideNavStrip _Strip = null; private Bar _TitleBar = null; private LabelItem _TitleLabel = null; private ButtonItem _CloseButton = null; private ButtonItem _MaximizeButton = null; private ButtonItem _RestoreButton = null; private Control _Splitter = null; public SideNav() { this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | DisplayHelp.DoubleBufferFlag | ControlStyles.UserPaint | ControlStyles.Opaque , true); this.Padding = new System.Windows.Forms.Padding(1); _Splitter = new Control(); _Splitter.Width = 4; _Splitter.Name = "splitter"; _Splitter.Cursor = Cursors.VSplit; _Splitter.Dock = DockStyle.Right; _Splitter.MouseMove += SplitterMouseMove; _Splitter.MouseDown += SplitterMouseDown; this.Controls.Add(_Splitter); // Title bar and fold/extend buttons Bar titleBar = new Bar(); titleBar.Name = "titleBar"; titleBar.AntiAlias = true; titleBar.Name = "titleBar"; titleBar.PaddingBottom = 7; titleBar.PaddingTop = 5; titleBar.PaddingLeft = 6; titleBar.RoundCorners = false; titleBar.Dock = DockStyle.Top; titleBar.Stretch = true; titleBar.Style = DevComponents.DotNetBar.eDotNetBarStyle.StyleManagerControlled; titleBar.TabIndex = 0; titleBar.TabStop = false; titleBar.BarType = eBarType.StatusBar; titleBar.ItemsContainer.OverflowEnabled = false; LabelItem titleLabel=new LabelItem(); titleLabel.Name = "titleLabel"; titleLabel.Text = "Title"; titleLabel.FontBold = true; _TitleLabel = titleLabel; titleBar.Items.Add(titleLabel); _TitleBar = titleBar; _CloseButton = new ButtonItem("openCloseButton"); _CloseButton.Symbol = "\uf0d9"; _CloseButton.ImagePaddingHorizontal = 18; _CloseButton.ItemAlignment= eItemAlignment.Far; _CloseButton.SymbolSize = 12f; _CloseButton.Click+=CloseButtonClick; titleBar.Items.Add(_CloseButton); _MaximizeButton = new ButtonItem("maximizeButton"); _MaximizeButton.Symbol = "\uf090"; _MaximizeButton.ItemAlignment = eItemAlignment.Far; _MaximizeButton.SymbolSize = 12f; _MaximizeButton.Click += MaximizeButtonClick; titleBar.Items.Add(_MaximizeButton); _RestoreButton = new ButtonItem("restoreButton"); _RestoreButton.Symbol = "\uf100"; _RestoreButton.ItemAlignment = eItemAlignment.Far; _RestoreButton.SymbolSize = 12f; _RestoreButton.Click += RestoreButtonClick; _RestoreButton.Visible = false; titleBar.Items.Add(_RestoreButton); this.Controls.Add(titleBar); _Strip = new SideNavStrip(); _Strip.Dock = DockStyle.Left; _Strip.AutoSize = true; _Strip.AutoSyncSizeOrientation = eOrientation.Horizontal; _Strip.ButtonCheckedChanged += StripButtonCheckedChanged; //SideNavItem menuItem=new SideNavItem(); //menuItem.Name = "menuItem"; //menuItem.Text = "Menu"; //menuItem.Symbol = "\uf0c9"; //menuItem.IsSystemMenu = true; //_Strip.Items.Add(menuItem); //Separator sep = new Separator(); //sep.SeparatorOrientation = eDesignMarkerOrientation.Vertical; //sep.FixedSize = new Size(3,1); //sep.Padding.Left = 6; //sep.Padding.Right = 6; //_Strip.Items.Add(sep); //SideNavItem item = new SideNavItem(); //item.Text = "Home"; //item.Symbol = "\uf015"; //_Strip.Items.Add(item); //SideNavPanel panel=new SideNavPanel(); //panel.Dock = DockStyle.Fill; //this.Controls.Add(panel); //item.Panel = panel; //item = new SideNavItem(); //item.Text = "Explore"; //item.Symbol = "\uf002"; //_Strip.Items.Add(item); //ButtonItem button=new ButtonItem(); //button.Text = "Button"; //button.Symbol = "\uf003"; //button.ButtonStyle = eButtonStyle.ImageAndText; //_Strip.Items.Add(button); this.Controls.Add(_Strip); _Strip.Width = 48; StyleManager.Register(this); UpdateColors(); } protected override void Dispose(bool disposing) { if (_IsMaximized && disposing && this.Parent!=null) { this.Parent.Resize -= ParentResize; } base.Dispose(disposing); } #endregion #region Implementation /// /// Called by StyleManager to notify control that style on manager has changed and that control should refresh its appearance if /// its style is controlled by StyleManager. /// /// New active style. [EditorBrowsable(EditorBrowsableState.Never)] public void StyleManagerStyleChanged(eDotNetBarStyle newStyle) { UpdateColors(); } /// /// Updates the control colors from the global color table. /// public void UpdateColors() { SideNavColorTable ct = GetColorTable(); _TitleBar.BackColor = ct.TitleBackColor; _TitleBar.BorderColors = ct.TitleBorderColors; this.Invalidate(true); } protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; DisplayHelp.FillRectangle(g,this.ClientRectangle, this.BackColor); SideNavColorTable table = GetColorTable(); DisplayHelp.DrawRoundedRectangle(g, this.ClientRectangle, table.BorderColors, 0); } private SideNavColorTable GetColorTable() { return ((Office2007Renderer)GlobalManager.Renderer).ColorTable.SideNav; } [EditorBrowsable(EditorBrowsableState.Never)] public void SetDesignMode() { _Strip.SetDesignMode(true); } private bool _EnableSplitter = true; /// /// Indicates whether splitter that is located on right hand side of open control is visible and enabled. /// [DefaultValue(true), Category("Appearance"), Description("Indicates whether splitter that is located on right hand side of open control is visible and enabled.")] public bool EnableSplitter { get { return _EnableSplitter; } set { if (_EnableSplitter != value) { bool oldValue = _EnableSplitter; _EnableSplitter = value; OnEnableSplitterChanged(value, oldValue); } } } protected virtual void OnEnableSplitterChanged(bool newValue, bool oldValue) { _Splitter.Visible = newValue; } private bool _EnableClose = true; /// /// Indicates whether button which folds/closes the control is visible. /// [DefaultValue(true), Category("Appearance"), Description("Indicates whether button which folds/closes the control is visible.")] public bool EnableClose { get { return _EnableClose; } set { if (_EnableClose != value) { bool oldValue = _EnableClose; _EnableClose = value; OnEnableCloseChanged(value, oldValue); } } } protected virtual void OnEnableCloseChanged(bool newValue, bool oldValue) { _CloseButton.Visible = newValue; _TitleBar.RecalcLayout(); } private bool _EnableMaximize = true; // /// Indicates whether buttons which maximize and restore the control are visible. /// [DefaultValue(true), Category("Apeparance"), Description("Indicates whether buttons which maximize and restore the control are visible.")] public bool EnableMaximize { get { return _EnableMaximize; } set { if (_EnableMaximize != value) { bool oldValue = _EnableMaximize; _EnableMaximize = value; OnEnableMaximizeChanged(value, oldValue); } } } protected virtual void OnEnableMaximizeChanged(bool newValue, bool oldValue) { if (!newValue) { _MaximizeButton.Visible = false; _RestoreButton.Visible = false; } else { if (_IsMaximized) _RestoreButton.Visible = true; else _MaximizeButton.Visible = true; } _TitleBar.RecalcLayout(); } /// /// Returns collection of items on a bar. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Browsable(false)] public SubItemsCollection Items { get { return _Strip.Items; } } private void CloseButtonClick(object sender, EventArgs e) { Close(eEventSource.Mouse); } private void MaximizeButtonClick(object sender, EventArgs e) { Maximize(eEventSource.Mouse); } private bool _IsMaximized = false; private int _RestoredWidth = 0; /// /// Maximizes control width so it fills up space to the right of the control. /// /// Source of the event. public void Maximize(eEventSource source) { if(_IsMaximized) return; if (this.Parent == null) return; if (this.Bounds.Right >= this.Parent.ClientRectangle.Right) return; CancelSourceEventArgs args=new CancelSourceEventArgs(source); OnBeforeMaximize(args); if(args.Cancel) return; _IsMaximized = true; int maxWidth = GetMaxWidth(); _RestoredWidth = this.Width; BarFunctions.AnimateControl(this, true, _AnimationTime, this.Bounds, new Rectangle(this.Location, new Size(maxWidth, this.Height))); _RestoreButton.Visible = true; _MaximizeButton.Visible = false; _TitleBar.RecalcLayout(); _Splitter.Visible = false; this.Invalidate(); this.Parent.Resize += ParentResize; } void ParentResize(object sender, EventArgs e) { if (this.Parent.Width > 0) this.Width = GetMaxWidth(); } private int GetMaxWidth() { int width = this.Width + this.Parent.ClientRectangle.Right - this.Bounds.Right; if (this.Parent is MetroAppForm) { MetroAppForm form = (MetroAppForm) this.Parent; if (form.BorderThickness.Right > 0) width -= (int)form.BorderThickness.Right; else width -= 3; } return width; } private void RestoreButtonClick(object sender, EventArgs e) { Restore(eEventSource.Mouse); } /// /// Restores the control to previous size if it was maximized before. /// /// Source of event. public void Restore(eEventSource source) { if (!_IsMaximized || _RestoredWidth == 0) return; _IsMaximized = false; CancelSourceEventArgs args = new CancelSourceEventArgs(source); OnBeforeRestore(args); if (args.Cancel) return; BarFunctions.AnimateControl(this, true, _AnimationTime, this.Bounds, new Rectangle(this.Location, new Size(_RestoredWidth, this.Height))); _RestoredWidth = 0; _RestoreButton.Visible = false; _MaximizeButton.Visible = true; _TitleBar.RecalcLayout(); _Splitter.Visible = _EnableSplitter; this.Invalidate(); if(this.Parent!=null) this.Parent.Resize -= ParentResize; } private bool _IsOpen = true; private int _OpenWidth = 0; /// /// Gets or sets whether control is closed, i.e. whether selected item panel is shown or not. When closed /// any selected item is unselected and selected panel hidden. /// [DefaultValue(false), Browsable(false)] public bool IsClosed { get { return !_IsOpen; } set { if (value) { if(_IsOpen) Close(eEventSource.Code); } else { if (!_IsOpen) { SideNavItem item = FirstVisibleSideNavItem??_LastOpenItem; if (item != null) Open(item, eEventSource.Code); } } } } private SideNavItem FirstVisibleSideNavItem { get { for (int i = 0; i < _Strip.Items.Count; i++) { if (_Strip.Items[i] is SideNavItem && _Strip.Items[i].Visible) return (SideNavItem)_Strip.Items[i]; } return null; } } private void StripButtonCheckedChanged(object sender, EventArgs e) { if (sender is SideNavItem && ((SideNavItem)sender).Checked) { OnSelectedItemChanged(EventArgs.Empty); if (!_IsOpen) Open((SideNavItem)sender, eEventSource.Code); } } /// /// Opens the control, i.e. expands it, selects specified item and shows its associated panel. /// /// Item to select. /// Source of the event. public void Open(SideNavItem item, eEventSource source) { if (item == null) throw new ArgumentException("item must be set to valid item to select"); if (_IsOpen) return; CancelSourceEventArgs args=new CancelSourceEventArgs(source, item); OnBeforeOpen(args); if(args.Cancel) return; if (!item.Checked) item.Checked = true; BarFunctions.AnimateControl(this, true, _AnimationTime, this.Bounds, new Rectangle(this.Location, new Size(_OpenWidth, this.Height))); _IsOpen = true; _Splitter.Visible = _EnableSplitter; this.Invalidate(); } private SideNavItem _LastOpenItem = null; /// /// Closes the control, i.e. unselects any selected item, hide its associated panel and folds the control. /// /// Source of the event. public void Close(eEventSource source) { if(!_IsOpen) return; CancelSourceEventArgs args = new CancelSourceEventArgs(source); OnBeforeClose(args); if (args.Cancel) return; _OpenWidth = this.Width; int closedWidth = _Strip.Width + this.Padding.Horizontal; _Splitter.Visible = false; BarFunctions.AnimateControl(this, true, _AnimationTime, this.Bounds, new Rectangle(this.Location, new Size(closedWidth, this.Height))); _IsOpen = false; if (_Strip.SelectedItem != null) { _LastOpenItem = _Strip.SelectedItem; _Strip.SelectedItem.Checked = false; } else _LastOpenItem = null; this.Invalidate(); } private bool _IsMenuExpanded = true; /// /// Indicates whether side menu is expanded, i.e. shows both image and text. When menu is collapsed only image is shown. /// [DefaultValue(true), Category("Appearance"), Description("Indicates whether side menu is expanded, i.e. shows both image and text. When menu is collapsed only image is shown.")] public bool IsMenuExpanded { get { return _IsMenuExpanded; } set { if (_IsMenuExpanded != value) { bool oldValue = _IsMenuExpanded; _IsMenuExpanded = value; OnIsMenuExpandedChanged(value, oldValue); } } } protected virtual void OnIsMenuExpandedChanged(bool newValue, bool oldValue) { ExpandMenu(newValue); OnIsMenuExpandedChanged(EventArgs.Empty); } /// /// Occurs when IsMenuExpanded property has changed its value. /// [Description("Occurs when IsMenuExpanded property has changed.")] public event EventHandler IsMenuExpandedChanged; /// /// Raises IsMenuExpandedChanged event. /// /// Provides event arguments. protected virtual void OnIsMenuExpandedChanged(EventArgs e) { EventHandler h = IsMenuExpandedChanged; if (h != null) h(this, e); } private bool _IsMenuExpandedDelayedSet = false; /// /// Expands or collapses the control items menu. /// /// private void ExpandMenu(bool expand) { if (!this.IsHandleCreated) { _IsMenuExpandedDelayedSet = true; return; } for (int i = 0; i < _Strip.Items.Count; i++) { ButtonItem button = _Strip.Items[i] as ButtonItem; if (button != null) { button.ButtonStyle = (expand ? eButtonStyle.ImageAndText : eButtonStyle.Default); } } _Strip.RecalcLayout(); if (!_IsOpen) this.Width = _Strip.Width + this.Padding.Horizontal; } private int _AnimationTime = 250; /// /// Indicates the animation time in milliseconds for operations that perform visual animation of transition. Set to zero to disable animation. /// [DefaultValue(250), Category("Behavior"), Description("Indicates the animation time in milliseconds for operations that perform visual animation of transition. Set to zero to disable animation.")] public int AnimationTime { get { return _AnimationTime; } set { if (value != _AnimationTime) { int oldValue = _AnimationTime; _AnimationTime = value; OnAnimationTimeChanged(oldValue, value); } } } /// /// Called when AnimationTime property has changed. /// /// Old property value /// New property value protected virtual void OnAnimationTimeChanged(int oldValue, int newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("AnimationTime")); } /// /// Occurs before the control is maximized and allows you to cancel that. /// [Description("Occurs before the control is maximized and allows you to cancel that.")] public event CancelSourceEventHandler BeforeMaximize; /// /// Raises BeforeMaximize event. /// /// Provides event arguments. protected virtual void OnBeforeMaximize(CancelSourceEventArgs e) { CancelSourceEventHandler h = BeforeMaximize; if (h != null) h(this, e); } /// /// Occurs before the control is restored and allows you to cancel that. /// [Description("Occurs before the control is restored and allows you to cancel that.")] public event CancelSourceEventHandler BeforeRestore; /// /// Raises BeforeRestore event. /// /// Provides event arguments. protected virtual void OnBeforeRestore(CancelSourceEventArgs e) { CancelSourceEventHandler h = BeforeRestore; if (h != null) h(this, e); } /// /// Occurs before the control is opened and allows you to cancel that. /// [Description("Occurs before the control is opened and allows you to cancel that.")] public event CancelSourceEventHandler BeforeOpen; /// /// Raises BeforeOpen event. /// /// Provides event arguments. protected virtual void OnBeforeOpen(CancelSourceEventArgs e) { CancelSourceEventHandler h = BeforeOpen; if (h != null) h(this, e); } /// /// Occurs before the control is closed and allows you to cancel that. /// [Description("Occurs before the control is closed and allows you to cancel that.")] public event CancelSourceEventHandler BeforeClose; /// /// Raises BeforeClose event. /// /// Provides event arguments. protected virtual void OnBeforeClose(CancelSourceEventArgs e) { CancelSourceEventHandler h = BeforeClose; if (h != null) h(this, e); } protected override void OnHandleCreated(EventArgs e) { UpdateSelectedItemTitle(); UpdateColors(); if (_IsMenuExpandedDelayedSet) { ExpandMenu(_IsMenuExpanded); _IsMenuExpandedDelayedSet = false; } base.OnHandleCreated(e); } internal void UpdateSelectedItemTitle() { SideNavItem item = _Strip.SelectedItem; if (item == null) return; if (!string.IsNullOrEmpty(item.Title)) _TitleLabel.Text = item.Title; else _TitleLabel.Text = item.Text; } private Point _SplitterMouseDownPoint = Point.Empty; private void SplitterMouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) _SplitterMouseDownPoint = e.Location; } private void SplitterMouseMove(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { int maxWidth = GetMaxWidth(); int minWidth = _Strip.Width + 64; int newWidth = this.Width + (e.X - _SplitterMouseDownPoint.X); if (newWidth > maxWidth) newWidth = maxWidth; else if (newWidth < minWidth) newWidth = minWidth; this.Width = newWidth; } } /// /// Gets currently selected item. Only items with Panel assigned can be selected. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public SideNavItem SelectedItem { get { foreach (BaseItem item in this.Items) { if (item is SideNavItem && ((SideNavItem)item).Checked) { return (SideNavItem)item; } } return null; } set { if (value != null && value.Panel != null) value.Checked = true; } } /// /// Occurs when SelectedItem changes. /// [Description("Occurs when SelectedItem changes.")] public event EventHandler SelectedItemChanged; /// /// Raises SelectedItemChanged event. /// /// Provides event arguments. protected virtual void OnSelectedItemChanged(EventArgs e) { EventHandler h = SelectedItemChanged; if (h != null) h(this, e); } /// /// Gets reference to internal SideNavStrip control. /// [Browsable(false)] public SideNavStrip SideNavStrip { get { return _Strip; } } #endregion } /// /// Defines delegate for the CancelSource events. /// /// /// public delegate void CancelSourceEventHandler(object sender, CancelSourceEventArgs e); /// /// Event arguments for CancelSourceEventHandler /// public class CancelSourceEventArgs : CancelEventArgs { /// /// Gets the source of the event. /// public eEventSource Source = eEventSource.Code; /// /// Gets any optional data that is associated with the event. /// public object Data = null; /// /// Creates new instance of the object. /// /// Source of event public CancelSourceEventArgs(eEventSource source) { this.Source = source; } /// /// Creates new instance of the object. /// /// Source of event /// Optional data associated with the event. public CancelSourceEventArgs(eEventSource source, object data) { this.Source = source; this.Data = data; } } }