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
}
}