using System; using System.Collections; using System.ComponentModel; using System.Drawing; using System.Data; using System.Windows.Forms; using System.Xml; using System.Drawing.Drawing2D; namespace DevComponents.DotNetBar { /// /// Represents Outlook 2003 like Navigation Bar. /// [ToolboxItem(true), System.Runtime.InteropServices.ComVisible(false), Designer("DevComponents.DotNetBar.Design.NavigationBarDesigner, DevComponents.DotNetBar.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf")] public class NavigationBar: BarBaseControl,ISupportInitialize { private NavigationBarContainer m_ItemContainer; private bool m_SplitterVisible=false; const int SPLITTER_SIZE=6; private Cursor m_SavedSplitterCursor=null; private bool m_SplitterMouseDown=false; /// /// Occurs after Options dialog which is used to customize control's content has closed by user using OK button. /// public event EventHandler OptionsDialogClosed; /// /// Default constructor. /// public NavigationBar():base() { m_ItemContainer=new NavigationBarContainer(); m_ItemContainer.GlobalItem=false; m_ItemContainer.ContainerControl=this; m_ItemContainer.Stretch=false; m_ItemContainer.Displayed=true; m_ItemContainer.Style=eDotNetBarStyle.Office2003; m_ItemContainer.SetOwner(this); this.SetBaseItemContainer(m_ItemContainer); SetDesignTimeDefaults(); } internal void InvokeOptionsDialogClosed() { OnOptionsDialogClosed(new EventArgs()); } protected virtual void OnOptionsDialogClosed(EventArgs e) { EventHandler handler = OptionsDialogClosed; if (handler != null) handler(this, e); } protected override void OnResize(EventArgs e) { base.OnResize(e); if (this.Width == 0 || this.Height == 0) return; this.RecalcSize(); } protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); this.RecalcSize(); } protected override void RecalcSize() { if(m_Initializing || !BarFunctions.IsHandleValid(this)) return; base.RecalcSize(); if(m_ItemContainer.IsRecalculatingSize) return; Rectangle r=this.GetItemContainerRectangle(); if(m_ItemContainer.HeightInternal>0) { this.Height = m_ItemContainer.HeightInternal + r.Top + Math.Max(0,this.ClientRectangle.Bottom - r.Bottom); } } /// /// Returns collection of items on a bar. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Browsable(false)] public SubItemsCollection Items { get { return m_ItemContainer.SubItems; } } /// /// Applies design-time defaults to control. /// public override void SetDesignTimeDefaults() { base.SetDesignTimeDefaults(); ApplyColorSchemeDefaults(); this.BackgroundStyle.BorderColor.ColorSchemePart=eColorSchemePart.PanelBorder; this.BackgroundStyle.Border=eBorderType.SingleLine; } private void ApplyColorSchemeDefaults() { // ColorScheme Defaults this.ColorScheme.ItemHotBorder = Color.Empty; this.ColorScheme.ItemBackground = this.ColorScheme.BarBackground; this.ColorScheme.ItemBackground2 = this.ColorScheme.BarBackground2; this.ColorScheme.ItemHotBorder = Color.Empty; this.ColorScheme.ItemPressedBorder = Color.Empty; this.ColorScheme.ItemCheckedBorder = Color.Empty; this.ColorScheme.ItemExpandedBackground = this.ColorScheme.ItemHotBackground; this.ColorScheme.ItemExpandedBackground2 = this.ColorScheme.ItemHotBackground2; this.ColorScheme.ItemExpandedShadow = Color.Empty; this.ColorScheme.ItemExpandedBorder = Color.Empty; this.ColorScheme.ResetChangedFlag(); this.BackgroundStyle.ApplyColorScheme(this.ColorScheme); } protected override void OnSystemColorsChanged(EventArgs e) { base.OnSystemColorsChanged(e); Application.DoEvents(); this.ColorScheme.Refresh(); ApplyColorSchemeDefaults(); } /// /// Gets or sets whether Configure Buttons button is visible. /// [Browsable(true),DevCoBrowsable(true),Category("Behavior"),Description("Indicates Configure Buttons button is visible."),System.ComponentModel.DefaultValue(true)] public bool ConfigureItemVisible { get {return m_ItemContainer.ConfigureItemVisible;} set { m_ItemContainer.ConfigureItemVisible=value; this.RecalcLayout(); } } /// /// Gets or sets whether Show More Buttons and Show Fewer Buttons menu items are visible on Configure buttons menu. /// [Browsable(true),DevCoBrowsable(true),Category("Behavior"),Description("Indicates whether Show More Buttons and Show Fewer Buttons menu items are visible on Configure buttons menu."),System.ComponentModel.DefaultValue(true)] public bool ConfigureShowHideVisible { get {return m_ItemContainer.ConfigureShowHideVisible;} set { m_ItemContainer.ConfigureShowHideVisible=value; this.RecalcLayout(); } } /// /// Gets or sets whether Navigation Pane Options menu item is visible on Configure buttons menu. /// [Browsable(true),DevCoBrowsable(true),Category("Behavior"),Description("Gets or sets whether Navigation Pane Options menu item is visible on Configure buttons menu."),System.ComponentModel.DefaultValue(true)] public bool ConfigureNavOptionsVisible { get {return m_ItemContainer.ConfigureNavOptionsVisible;} set { m_ItemContainer.ConfigureNavOptionsVisible=value; this.RecalcLayout(); } } /// /// Gets or sets whether Navigation Pane Add/Remove Buttons menu item is visible on Configure buttons menu. /// [Browsable(true),DevCoBrowsable(true),Category("Behavior"),Description("Indicates whether Navigation Pane Add/Remove Buttons menu item is visible on Configure buttons menu."),System.ComponentModel.DefaultValue(true)] public bool ConfigureAddRemoveVisible { get {return m_ItemContainer.ConfigureAddRemoveVisible;} set { m_ItemContainer.ConfigureAddRemoveVisible=value; this.RecalcLayout(); } } /// /// Gets or sets whether summary line is visible. /// [Browsable(true),DevCoBrowsable(true),Category("Behavior"),Description("Indicates whether summary line is visible."),System.ComponentModel.DefaultValue(true)] public bool SummaryLineVisible { get {return m_ItemContainer.SummaryLineVisible;} set { m_ItemContainer.SummaryLineVisible=value; this.RecalcLayout(); } } /// /// Gets or sets the padding in pixels at the top portion of the item. Height of each item will be increased by padding amount. /// [Browsable(true),DevCoBrowsable(true),Category("Layout"),Description("Indicates the padding in pixels at the top portion of the item."),DefaultValue(4)] public int ItemPaddingTop { get {return m_ItemContainer.ItemPaddingTop;} set { m_ItemContainer.ItemPaddingTop=value; if(this.DesignMode) this.RecalcLayout(); } } /// /// Gets or sets the padding in pixels for bottom portion of the item. Height of each item will be increased by padding amount. /// [Browsable(true),DevCoBrowsable(true),Category("Layout"),Description("Indicates the padding in pixels at the bottom of the item."),DefaultValue(4)] public int ItemPaddingBottom { get {return m_ItemContainer.ItemPaddingBottom;} set { m_ItemContainer.ItemPaddingBottom=value; if(this.DesignMode) this.RecalcLayout(); } } /// /// Increases the size of the navigation bar if possible by showing more buttons on the top. /// public void ShowMoreButtons() { m_ItemContainer.ShowMoreButtons(); } /// /// Reduces the size of the navigation bar if possible by showing fewer buttons on the top. /// public void ShowFewerButtons() { m_ItemContainer.ShowFewerButtons(); } protected override Rectangle GetItemContainerRectangle() { Rectangle r=base.GetItemContainerRectangle(); if(m_SplitterVisible) { r.Y+=SPLITTER_SIZE; r.Height-=SPLITTER_SIZE; } return r; } protected override void PaintContentOnTop(ItemPaintArgs pa) { base.PaintContentOnTop(pa); PaintSplitter(pa); } /// /// Returns items container. /// [Browsable(false)] public NavigationBarContainer ItemsContainer { get {return m_ItemContainer;} } /// /// Returns reference to currently checked button. /// [Browsable(false)] public ButtonItem CheckedButton { get { foreach(BaseItem item in m_ItemContainer.SubItems) { if(item is ButtonItem && ((ButtonItem)item).Checked) return item as ButtonItem; } return null; } } /// /// Gets or sets whether images are automatically resized to size specified in ImageSizeSummaryLine when button is on the bottom summary line of navigation bar. /// [Browsable(true),DevCoBrowsable(true),Category("Appearance"),Description("Indicates whether images are automatically resized to size specified in ImageSizeSummaryLine when button is on the bottom summary line of navigation bar."),DefaultValue(true)] public bool AutoSizeButtonImage { get {return m_ItemContainer.AutoSizeButtonImage;} set {m_ItemContainer.AutoSizeButtonImage=value;} } /// /// Gets or sets size of the image that will be use to resize images to when button button is on the bottom summary line of navigation bar and AutoSizeButtonImage=true. /// [Browsable(true),DevCoBrowsable(true),Category("Appearance"),Description("Indicates size of the image that will be use to resize images to when button button is on the bottom summary line of navigation bar and AutoSizeButtonImage=true.")] public Size ImageSizeSummaryLine { get {return m_ItemContainer.ImageSizeSummaryLine;} set {m_ItemContainer.ImageSizeSummaryLine=value;} } [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeImageSizeSummaryLine() { return (m_ItemContainer.ImageSizeSummaryLine.Width!=16 || m_ItemContainer.ImageSizeSummaryLine.Height!=16); } private bool m_Initializing=false; void ISupportInitialize.BeginInit() { m_Initializing=true; } void ISupportInitialize.EndInit() { m_Initializing=false; this.RecalcLayout(); } /// /// Saves current visual layout of navigation bar control to XML based file. /// /// File name to save layout to. public void SaveLayout(string fileName) { System.Xml.XmlDocument xmlDoc=new System.Xml.XmlDocument(); XmlElement parent=xmlDoc.CreateElement("navbarlayout"); xmlDoc.AppendChild(parent); this.SaveLayout(parent); xmlDoc.Save(fileName); } /// /// Saves current visual layout of navigation bar control to XmlElement. /// /// XmlElement object that will act as a parent for the layout definition. Exact same element should be passed into the LoadLayout method to load the layout. public void SaveLayout(XmlElement xmlParent) { if(this.Items.Count==0) return; XmlElement root=xmlParent.OwnerDocument.CreateElement("navigationbar"); xmlParent.AppendChild(root); root.SetAttribute("height",this.Height.ToString()); foreach(BaseItem item in this.Items) { if(item is ButtonItem && item.Name!="") { XmlElement xmlItem=xmlParent.OwnerDocument.CreateElement("item"); root.AppendChild(xmlItem); xmlItem.SetAttribute("index",this.Items.IndexOf(item).ToString()); xmlItem.SetAttribute("name",item.Name); xmlItem.SetAttribute("visible",XmlConvert.ToString(item.Visible)); xmlItem.SetAttribute("checked",XmlConvert.ToString(((ButtonItem)item).Checked)); } } } /// /// Gets or sets the navigation bar definition string. /// [Browsable(false),DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string LayoutDefinition { get { System.Xml.XmlDocument xmlDoc=new System.Xml.XmlDocument(); XmlElement parent=xmlDoc.CreateElement("navbarlayout"); xmlDoc.AppendChild(parent); this.SaveLayout(parent); return xmlDoc.OuterXml; } set { System.Xml.XmlDocument xmlDoc=new System.Xml.XmlDocument(); xmlDoc.LoadXml(value); LoadLayout(xmlDoc.FirstChild as XmlElement); } } /// /// Loads navigation bar layout that was saved using SaveLayout method. Note that this method must be called after all items are created and added to the control. /// /// File to load layout from. public void LoadLayout(string fileName) { System.Xml.XmlDocument xmlDoc=new System.Xml.XmlDocument(); xmlDoc.Load(fileName); this.LoadLayout(xmlDoc.FirstChild as XmlElement); } /// /// Loads navigation bar layout that was saved using SaveLayout method. Note that this method must be called after all items are created and added to the control. /// /// Parent XML element that is used to load layout from. Note that this must be the same element that was passed into the SaveLayout method. public void LoadLayout(XmlElement xmlParent) { if(this.Items.Count==0) return; XmlElement root=xmlParent.FirstChild as XmlElement; if(root==null || root.Name!="navigationbar") throw new InvalidOperationException("xmlParent parameter in LoadLayout does not contain expected XML child note with name navigationbar. Invalid XML layout file."); try { ((ISupportInitialize)this).BeginInit(); this.Height=XmlConvert.ToInt32(root.GetAttribute("height")); foreach(XmlElement xmlItem in root.ChildNodes) { if(!this.Items.Contains(xmlItem.GetAttribute("name"))) continue; BaseItem item=this.Items[xmlItem.GetAttribute("name")]; if(item is ButtonItem) { ButtonItem button=item as ButtonItem; button.Checked=XmlConvert.ToBoolean(xmlItem.GetAttribute("checked")); button.Visible=XmlConvert.ToBoolean(xmlItem.GetAttribute("visible")); int i=XmlConvert.ToInt32(xmlItem.GetAttribute("index")); if(this.Items.IndexOf(item)!=i) { this.Items.RemoveAt(this.Items.IndexOf(item)); this.Items.Insert(i,item); } } } } finally { ((ISupportInitialize)this).EndInit(); } } protected override bool ProcessMnemonic(char charCode) { string s="&"+charCode.ToString(); s=s.ToLower(); foreach(BaseItem item in this.Items) { string text=item.Text.ToLower(); if(text.IndexOf(s)>=0) { if(item is ButtonItem) { ((ButtonItem)item).Checked=true; return true; } } } return false; } /// /// Gets/Sets the visual style for items and color scheme. /// [Browsable(true), DevCoBrowsable(true), Category("Appearance"), Description("Specifies the visual style of the control."), DefaultValue(eDotNetBarStyle.Office2003)] public eDotNetBarStyle Style { get { return m_ItemContainer.Style; } set { this.ColorScheme.Style = value; m_ItemContainer.Style = value; ApplyColorSchemeDefaults(); this.RecalcLayout(); } } private static RoundRectangleShapeDescriptor _ButtonShape = new RoundRectangleShapeDescriptor(); internal IShapeDescriptor ButtonShape { get { return _ButtonShape; } } #region Splitter Support protected virtual void PaintSplitter(ItemPaintArgs pa) { if (m_SplitterVisible) { Rectangle r = this.GetSplitterRectangle(); eDotNetBarStyle effectiveStyle = m_ItemContainer.EffectiveStyle; if (effectiveStyle == eDotNetBarStyle.Office2010) { r.Height--; r.Inflate(0, 0); r.Width -= 2; } if (effectiveStyle != eDotNetBarStyle.Office2010) { using (System.Drawing.Drawing2D.LinearGradientBrush brush = BarFunctions.CreateLinearGradientBrush(r, pa.Colors.SplitterBackground, pa.Colors.SplitterBackground2, 90)) pa.Graphics.FillRectangle(brush, r); using (SolidBrush brush = new SolidBrush(Color.White)) { int x = r.X + (r.Width - 34) / 2; int y = r.Y + 2; for (int i = 0; i < 9; i++) { pa.Graphics.FillRectangle(brush, x, y, 2, 2); x += 4; } } using (SolidBrush brush = new SolidBrush(Color.FromArgb(128, ControlPaint.Dark(pa.Colors.SplitterBackground)))) { int x = r.X + (r.Width - 34) / 2 - 1; int y = r.Y + 1; for (int i = 0; i < 9; i++) { pa.Graphics.FillRectangle(brush, x, y, 2, 2); x += 4; } } DisplayHelp.DrawLine(pa.Graphics, r.X, r.Bottom - 1, r.Right, r.Bottom - 1, pa.Colors.SplitterBorder, 1); } else { Rectangle fillRect = r; fillRect.Height -= 1; SmoothingMode sm = pa.Graphics.SmoothingMode; pa.Graphics.SmoothingMode = SmoothingMode.None; using (System.Drawing.Drawing2D.LinearGradientBrush brush = new LinearGradientBrush(fillRect, pa.Colors.SplitterBackground, pa.Colors.SplitterBackground2, 90)) pa.Graphics.FillRectangle(brush, fillRect); pa.Graphics.SmoothingMode = sm; DisplayHelp.DrawRectangle(pa.Graphics, pa.Colors.SplitterBorder, r); } } } protected virtual Rectangle GetSplitterRectangle() { Rectangle r=new Rectangle(this.ClientRectangle.X,this.ClientRectangle.Y,this.Width,SPLITTER_SIZE); if(this.BackgroundStyle.Border==eBorderType.SingleLine) { if((this.BackgroundStyle.BorderSide & eBorderSide.Top)==eBorderSide.Top) r.Y++; if((this.BackgroundStyle.BorderSide & eBorderSide.Right)==eBorderSide.Right) r.Width--; if((this.BackgroundStyle.BorderSide & eBorderSide.Left)==eBorderSide.Left) { r.X++; r.Width--; } } else if(this.BackgroundStyle.Border!=eBorderType.None) { if((this.BackgroundStyle.BorderSide & eBorderSide.Top)==eBorderSide.Top) r.Y+=2; if((this.BackgroundStyle.BorderSide & eBorderSide.Right)==eBorderSide.Right) r.Width-=2; if((this.BackgroundStyle.BorderSide & eBorderSide.Left)==eBorderSide.Left) { r.X+=2; r.Width-=2; } } return r; } protected override void OnMouseMove(MouseEventArgs e) { SplitterMouseMove(e); if(!m_SplitterMouseDown) base.OnMouseMove(e); } [EditorBrowsable(EditorBrowsableState.Never)] public void SplitterMouseMove(MouseEventArgs e) { if(m_SplitterVisible && !m_SplitterMouseDown) { if(HitTestSplitter(e.X,e.Y)) { if(m_SavedSplitterCursor==null || this.GetDesignMode()) { if(m_SavedSplitterCursor==null) { if(this.GetDesignMode()) m_SavedSplitterCursor=Cursor.Current; else m_SavedSplitterCursor=this.Cursor; } if(this.GetDesignMode()) Cursor.Current=Cursors.SizeNS; else this.Cursor=Cursors.SizeNS; } } else if(m_SavedSplitterCursor!=null) { if(this.GetDesignMode()) Cursor.Current=m_SavedSplitterCursor; else this.Cursor=m_SavedSplitterCursor; m_SavedSplitterCursor=null; } } if(m_SplitterMouseDown) { bool reduceSize=false; BaseItem firstDisplayed=m_ItemContainer.GetFirstVisibleItem(); if(firstDisplayed==null) reduceSize=false; else if(e.Y>=firstDisplayed.DisplayRectangle.Bottom-SPLITTER_SIZE) reduceSize=true; // BaseItem referenceItem=m_ItemContainer.GetResizeReferenceItem(reduceSize); // if(referenceItem==null) // return; // int itemHeight=referenceItem.HeightInternal; // if(referenceItem is ButtonItem && m_ItemContainer.AutoSizeButtonImage && !m_ItemContainer.ImageSizeSummaryLine.IsEmpty && !((ButtonItem)referenceItem).ImageFixedSize.IsEmpty) // { // Size size=((ButtonItem)referenceItem).ImageFixedSize; // ((ButtonItem)referenceItem).ImageFixedSize=Size.Empty; // referenceItem.RecalcSize(); // itemHeight=referenceItem.HeightInternal; // itemHeight+=(m_ItemContainer.ItemPaddingBottom+m_ItemContainer.ItemPaddingTop); // ((ButtonItem)referenceItem).ImageFixedSize=size; // referenceItem.RecalcSize(); // } int itemHeight=m_ItemContainer.GetChangeSizeHeight(reduceSize); if(firstDisplayed!=null && e.Y>=firstDisplayed.DisplayRectangle.Bottom-SPLITTER_SIZE && this.GetItemContainerRectangle().Height>itemHeight+SPLITTER_SIZE) { //this.Height-=itemHeight; m_ItemContainer.ShowFewerButtons(); } else if(e.Y<0 && Math.Abs(e.Y)>=itemHeight+SPLITTER_SIZE) { // itemHeight+=SPLITTER_SIZE; // this.Height+=itemHeight+1; m_ItemContainer.ShowMoreButtons(); } else this.RecalcLayout(); } } protected override void OnMouseLeave(EventArgs e) { SplitterMouseLeave(); base.OnMouseLeave(e); } [EditorBrowsable(EditorBrowsableState.Never)] public void SplitterMouseLeave() { if(m_SavedSplitterCursor!=null) { if(this.GetDesignMode()) Cursor.Current=m_SavedSplitterCursor; else this.Cursor=m_SavedSplitterCursor; m_SavedSplitterCursor=null; } } protected override void OnMouseDown(MouseEventArgs e) { SplitterMouseDown(e); if(!m_SplitterMouseDown) base.OnMouseDown(e); } [EditorBrowsable(EditorBrowsableState.Never)] public void SplitterMouseDown(MouseEventArgs e) { if(this.Dock==DockStyle.Bottom && HitTestSplitter(e.X,e.Y)) { this.Capture=true; m_SplitterMouseDown=true; } } [EditorBrowsable(EditorBrowsableState.Never)] public bool HitTestSplitter(int x, int y) { if(m_SplitterVisible) { Rectangle r=this.GetSplitterRectangle(); if(r.Contains(x,y)) { return true; } } return false; } protected override void OnMouseUp(MouseEventArgs e) { SplitterMouseUp(e); base.OnMouseUp(e); } [EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsSplitterMouseDown { get {return m_SplitterMouseDown;} } [EditorBrowsable(EditorBrowsableState.Never)] public void SplitterMouseUp(MouseEventArgs e) { if(m_SplitterMouseDown) { m_SplitterMouseDown=false; this.Capture=false; if(m_SavedSplitterCursor!=null) { this.Cursor=m_SavedSplitterCursor; m_SavedSplitterCursor=null; } } } // Internal Splitter sizing logic assumes that control is docked to bottom and it will // change height ONLY. It is not capable of handling the generic splitter case!!!!! // OnMouseDown is hard-coded to check for Dock=Bottom to prevent any problems /// /// Indicates whether splitter on top of the navigation bar is visible. When activated splitter will let user change the height of the /// control to show fewer or more buttons. It is recommended to have navigation bar docked to bottom (Dock=Bottom) to maintain /// proper layout. /// [Browsable(true),DevCoBrowsable(true),Category("Layout"),Description("Indicates whether splitter on top of the navigation bar is visible."),DefaultValue(false)] public bool SplitterVisible { get{return m_SplitterVisible;} set { m_SplitterVisible=value; if(this.DesignMode) this.RecalcLayout(); } } #endregion } }