using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Text; using System.Windows.Forms; namespace DevComponents.DotNetBar { /// /// Represents simple item container which orders items horizontally and support all ItemAlignment settings. /// [ToolboxItem(false)] public class SimpleItemContainer : ImageItem, IDesignTimeProvider { #region Constructor /// /// Initializes a new instance of the SimpleItemContainer class. /// public SimpleItemContainer() { // We contain other controls m_IsContainer = true; this.AccessibleRole = System.Windows.Forms.AccessibleRole.Grouping; } #endregion #region Implementation public override void RecalcSize() { if (_LayoutOrientation == eOrientation.Vertical) { RecalcSizeVertical(); } else { List leftItems = new List(); List centerItems = new List(); List rightItems = new List(); int centerWidth = 0; Size minSize = SplitItems(leftItems, centerItems, rightItems, out centerWidth); Point loc = this.Bounds.Location; int bottom = this.Bounds.Bottom; loc.X += _PaddingLeft; if (this.WidthInternal == 0 || this.WidthInternal <= minSize.Width) { BaseItem[] items = new BaseItem[leftItems.Count + centerItems.Count + rightItems.Count]; leftItems.CopyTo(items); centerItems.CopyTo(items, leftItems.Count); rightItems.CopyTo(items, leftItems.Count + centerItems.Count); BaseItem previousItem = null; // Just line items up foreach (BaseItem item in items) { if (!item.Visible) continue; item.Displayed = true; loc.X -= GetOverlapSpacing(previousItem, item); item.LeftInternal = loc.X; if (IsVerticallyCentered(item)) item.TopInternal = loc.Y + (minSize.Height - item.HeightInternal)/2; else item.TopInternal = loc.Y + (minSize.Height - item.HeightInternal); loc.X += item.WidthInternal + _ItemSpacing; previousItem = item; } m_Rect.Size = minSize; } else { int leftItemsRight = 0; BaseItem previousItem = null; foreach (BaseItem item in leftItems) { item.Displayed = true; if (item.BeginGroup) loc.X += _BeginGroupSpacing; loc.X -= GetOverlapSpacing(previousItem, item); item.LeftInternal = loc.X; if (IsVerticallyCentered(item)) item.TopInternal = loc.Y + (minSize.Height - item.HeightInternal)/2; else item.TopInternal = loc.Y + (minSize.Height - item.HeightInternal); loc.X += item.WidthInternal + _ItemSpacing; previousItem = item; } leftItemsRight = loc.X; int rightItemsLeft = 0; loc = new Point(this.Bounds.Right - _PaddingRight, this.Bounds.Y); previousItem = null; for (int i = rightItems.Count - 1; i >= 0; i--) { BaseItem item = rightItems[i]; loc.X -= item.WidthInternal; item.Displayed = true; loc.X += GetOverlapSpacing(previousItem, item); item.LeftInternal = loc.X; loc.X -= _ItemSpacing + (item.BeginGroup ? _BeginGroupSpacing : 0); if (IsVerticallyCentered(item)) item.TopInternal = loc.Y + (minSize.Height - item.HeightInternal)/2; else item.TopInternal = loc.Y + (minSize.Height - item.HeightInternal); previousItem = item; } rightItemsLeft = loc.X; loc = new Point((this.WidthInternal - centerWidth)/2, this.Bounds.Y); if (loc.X < leftItemsRight || loc.X + centerWidth > rightItemsLeft) { loc.X = leftItemsRight + ((rightItemsLeft - leftItemsRight) - centerWidth)/2; } previousItem = null; foreach (BaseItem item in centerItems) { item.Displayed = true; if (item.BeginGroup) loc.X += _BeginGroupSpacing; loc.X -= GetOverlapSpacing(previousItem, item); item.LeftInternal = loc.X; if (IsVerticallyCentered(item)) item.TopInternal = loc.Y + (minSize.Height - item.HeightInternal)/2; else item.TopInternal = loc.Y + (minSize.Height - item.HeightInternal); loc.X += item.WidthInternal + _ItemSpacing; previousItem = item; } m_Rect.Height = minSize.Height; } if (m_Rect.Width < _MinimumSize.Width) m_Rect.Width = _MinimumSize.Width; if (m_Rect.Height < _MinimumSize.Height) m_Rect.Height = _MinimumSize.Height; } base.RecalcSize(); } protected virtual bool IsVerticallyCentered(BaseItem item) { return !(item is DevComponents.DotNetBar.Metro.MetroTabItem); } private Size SplitItems(List leftItems, List centerItems, List rightItems, out int centerWidth) { Size minSize = new Size(); centerWidth = 0; BaseItem previousItem = null; foreach (BaseItem item in this.SubItems) { if (!item.Visible) { item.Displayed = false; continue; } item.RecalcSize(); minSize.Width += item.WidthInternal + _ItemSpacing + (item.BeginGroup ? _BeginGroupSpacing : 0) - GetOverlapSpacing(previousItem, item); minSize.Height = Math.Max(item.HeightInternal, minSize.Height); if (item.ItemAlignment == eItemAlignment.Near) leftItems.Add(item); else if (item.ItemAlignment == eItemAlignment.Center) { centerItems.Add(item); centerWidth += item.WidthInternal + _ItemSpacing; } else if (item.ItemAlignment == eItemAlignment.Far) rightItems.Add(item); previousItem = item; } if (minSize.Width > 0) minSize.Width -= _ItemSpacing; if (centerWidth > 0) centerWidth -= _ItemSpacing; return minSize; } private int GetOverlapSpacing(BaseItem previousItem, BaseItem item) { if (previousItem == null || _OverlapSpacing <= 0 || _OverlapType == null || !(_OverlapType.IsInstanceOfType(previousItem) && _OverlapType.IsInstanceOfType(item))) return 0; return _OverlapSpacing; } private bool IsHorizontallyCentered(BaseItem item) { return !(item is DevComponents.DotNetBar.Metro.MetroTabItem); } private Size SplitItemsVertical(List topItems, List centerItems, List bottomItems, out int centerHeight) { Size minSize = new Size(); centerHeight = 0; BaseItem previousItem = null; foreach (BaseItem item in this.SubItems) { if (!item.Visible) { item.Displayed = false; continue; } item.RecalcSize(); minSize.Height += item.HeightInternal + _ItemSpacing + (item.BeginGroup ? _BeginGroupSpacing : 0) - GetOverlapSpacing(previousItem, item); minSize.Width = Math.Max(item.WidthInternal, minSize.Width); if (item.ItemAlignment == eItemAlignment.Near) topItems.Add(item); else if (item.ItemAlignment == eItemAlignment.Center) { centerItems.Add(item); centerHeight += item.HeightInternal + _ItemSpacing; } else if (item.ItemAlignment == eItemAlignment.Far) bottomItems.Add(item); previousItem = item; } if (minSize.Height > 0) minSize.Height -= _ItemSpacing; if (centerHeight > 0) centerHeight -= _ItemSpacing; return minSize; } private void RecalcSizeVertical() { List leftItems = new List(); List centerItems = new List(); List rightItems = new List(); int centerHeight = 0; Size minSize = SplitItemsVertical(leftItems, centerItems, rightItems, out centerHeight); Point loc = this.Bounds.Location; int bottom = this.Bounds.Bottom; if (this.HeightInternal == 0 || this.HeightInternal <= minSize.Height) { BaseItem[] items = new BaseItem[leftItems.Count + centerItems.Count + rightItems.Count]; leftItems.CopyTo(items); centerItems.CopyTo(items, leftItems.Count); rightItems.CopyTo(items, leftItems.Count + centerItems.Count); // Just line items up foreach (BaseItem item in items) { if (!item.Visible) continue; item.Displayed = true; item.TopInternal = loc.Y; item.LeftInternal = loc.X; //if (IsHorizontallyCentered(item)) // item.LeftInternal = loc.X + (minSize.Width - item.WidthInternal) / 2; //else // item.LeftInternal = loc.X + (minSize.Width - item.WidthInternal); item.WidthInternal = minSize.Width; loc.Y += item.HeightInternal + _ItemSpacing; } m_Rect.Size = minSize; } else { int leftItemsRight = 0; foreach (BaseItem item in leftItems) { item.Displayed = true; if (item.BeginGroup) loc.Y += _BeginGroupSpacing; item.TopInternal = loc.Y; item.WidthInternal = minSize.Width; if (IsHorizontallyCentered(item)) item.LeftInternal = loc.X + (minSize.Width - item.WidthInternal) / 2; else item.LeftInternal = loc.X + (minSize.Width - item.WidthInternal); loc.Y += item.HeightInternal + _ItemSpacing; } leftItemsRight = loc.Y; int rightItemsLeft = 0; loc = new Point(this.Bounds.X, this.Bounds.Bottom); for (int i = rightItems.Count - 1; i >= 0; i--) { BaseItem item = rightItems[i]; loc.Y -= item.HeightInternal; item.Displayed = true; item.TopInternal = loc.Y; item.WidthInternal = minSize.Width; loc.Y -= _ItemSpacing + (item.BeginGroup ? _BeginGroupSpacing : 0); if (IsHorizontallyCentered(item)) item.LeftInternal = loc.X + (minSize.Width - item.WidthInternal) / 2; else item.LeftInternal = loc.X + (minSize.Width - item.WidthInternal); } rightItemsLeft = loc.Y; loc = new Point(this.Bounds.X, (this.HeightInternal - centerHeight) / 2); if (loc.Y < leftItemsRight || loc.Y + centerHeight > rightItemsLeft) { loc.Y = leftItemsRight + ((rightItemsLeft - leftItemsRight) - centerHeight) / 2; } foreach (BaseItem item in centerItems) { item.Displayed = true; if (item.BeginGroup) loc.Y += _BeginGroupSpacing; item.TopInternal = loc.Y; item.WidthInternal = minSize.Width; if (IsHorizontallyCentered(item)) item.LeftInternal = loc.X + (minSize.Width - item.WidthInternal) / 2; else item.LeftInternal = loc.X + (minSize.Width - item.WidthInternal); loc.Y += item.HeightInternal + _ItemSpacing; } m_Rect.Width = minSize.Width; } if (m_Rect.Width < _MinimumSize.Width) m_Rect.Width = _MinimumSize.Width; if (m_Rect.Height < _MinimumSize.Height) m_Rect.Height = _MinimumSize.Height; } public override void Paint(ItemPaintArgs p) { foreach (BaseItem item in this.SubItems) { if (!item.Displayed) continue; if (item.BeginGroup) { DisplayHelp.DrawLine(p.Graphics, item.LeftInternal -3, this.TopInternal + 4, item.LeftInternal - 3, this.Bounds.Bottom - 8, p.Colors.ItemSeparator, 1); } item.Paint(p); } } /// /// Returns copy of the item. /// public override BaseItem Copy() { SimpleItemContainer objCopy = new SimpleItemContainer(); this.CopyToItem(objCopy); return objCopy; } /// /// Copies the item specific properties to new instance of the item. /// /// New instance. internal void InternalCopyToItem(SimpleItemContainer copy) { CopyToItem(copy); } /// /// Copies the item specific properties to new instance of the item. /// /// New instance. protected override void CopyToItem(BaseItem copy) { SimpleItemContainer c = copy as SimpleItemContainer; base.CopyToItem(c); } internal void SetSystemFocus() { if (m_HotSubItem != null || this.SubItems.Count == 0) return; BaseItem exp = this.ExpandedItem(); if (exp != null) { m_HotSubItem = exp; m_HotSubItem.InternalMouseEnter(); m_HotSubItem.InternalMouseMove(new MouseEventArgs(MouseButtons.None, 0, m_HotSubItem.LeftInternal + 2, m_HotSubItem.TopInternal + 2, 0)); return; } foreach (BaseItem objItem in this.SubItems) { if (!objItem.SystemItem && objItem.Displayed && objItem.Visible) { m_HotSubItem = objItem; m_HotSubItem.InternalMouseEnter(); m_HotSubItem.InternalMouseMove(new MouseEventArgs(MouseButtons.None, 0, m_HotSubItem.LeftInternal + 2, m_HotSubItem.TopInternal + 2, 0)); break; } } } internal void ReleaseSystemFocus() { CollapseSubItems(this); if (m_HotSubItem != null) { Control c = this.ContainerControl as Control; if (c != null) { Point p = c.PointToClient(Control.MousePosition); if (m_HotSubItem.DisplayRectangle.Contains(p)) return; } m_HotSubItem.InternalMouseLeave(); m_HotSubItem = null; } } private int _ItemSpacing; private Size _MinimumSize = Size.Empty; /// /// Gets or sets the minimum size of the container. Either Width or Height can be set or both. Default value is 0,0 which means /// that size is automatically calculated. /// [Browsable(false)] public Size MinimumSize { get { return _MinimumSize; } set { _MinimumSize = value; this.NeedRecalcSize = true; this.OnAppearanceChanged(); } } //private bool ShouldSerializeMinimumSize() //{ // return !_MinimumSize.IsEmpty; //} private bool _SystemContainer = false; /// /// Returns whether instance of the item container is used as system container internally by DotNetBar. /// [Browsable(false)] public bool SystemContainer { get { return _SystemContainer; } } /// /// Sets whether container is used as system container internally by DotNetBar. /// /// true or false to indicate whether container is system container or not. internal void SetSystemContainer(bool b) { _SystemContainer = b; } /// /// Indicates the spacing between items. /// public int ItemSpacing { get { return _ItemSpacing; } set { if (value != _ItemSpacing) { int oldValue = _ItemSpacing; _ItemSpacing = value; OnItemSpacingChanged(oldValue, value); } } } /// /// Called when ItemSpacing property has changed. /// /// Old property value /// New property value protected virtual void OnItemSpacingChanged(int oldValue, int newValue) { this.NeedRecalcSize = true; this.OnAppearanceChanged(); //OnPropertyChanged(new PropertyChangedEventArgs("ItemSpacing")); } private int _BeginGroupSpacing = 6; /// /// Indicates additional spacing between item when its BeginGroup property is set. /// [DefaultValue(6), Category("Appearance"), Description("Indicates additional spacing between item when its BeginGroup property is set.")] public int BeginGroupSpacing { get { return _BeginGroupSpacing; } set { _BeginGroupSpacing = value; } } private eOrientation _LayoutOrientation = eOrientation.Horizontal; /// /// Specifies the layout orientation /// [DefaultValue(eOrientation.Horizontal), Category("Layout"), Description("Specifies the layout orientation")] public eOrientation LayoutOrientation { get { return _LayoutOrientation; } set { if (_LayoutOrientation != value) { _LayoutOrientation = value; NeedRecalcSize = true; } } } private bool _EqualizeButtonSize = false; /// /// Indicates whether all items are resized to be of the size equal to largest item in the container /// [DefaultValue(false), Category("Layout"), Description("Indicates whether all items are resized to be of the size equal to largest item in the container")] public bool EqualizeButtonSize { get { return _EqualizeButtonSize; } set { if (_EqualizeButtonSize != value) { _EqualizeButtonSize = value; NeedRecalcSize = true; } } } private int _PaddingLeft = 0; /// /// Indicates left side padding within container. /// public int PaddingLeft { get { return _PaddingLeft; } set { _PaddingLeft = value; } } private int _PaddingRight; /// /// Indicates right side padding within container. /// public int PaddingRight { get { return _PaddingRight; } set { _PaddingRight = value; } } private int _OverlapSpacing = 0; /// /// Gets overlap spacing for specific item types specified by OverlapType in the container. /// public int OverlapSpacing { get { return _OverlapSpacing; } set { _OverlapSpacing = value; } } private Type _OverlapType = null; /// /// Gets the type of the item that will overlap. /// public Type OverlapType { get { return _OverlapType; } set { _OverlapType = value; } } #endregion #region IDesignTimeProvider public InsertPosition GetInsertPosition(Point pScreen, BaseItem DragItem) { return DesignTimeProviderContainer.GetInsertPosition(this, pScreen, DragItem); } public void DrawReversibleMarker(int iPos, bool Before) { DesignTimeProviderContainer.DrawReversibleMarker(this, iPos, Before); return; } public void InsertItemAt(BaseItem objItem, int iPos, bool Before) { DesignTimeProviderContainer.InsertItemAt(this, objItem, iPos, Before); return; } #endregion } }