485 lines
20 KiB
C#
485 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
|
|
namespace DevComponents.DotNetBar.Layout
|
|
{
|
|
/// <summary>
|
|
/// Represents layout item which hosts a Windows Forms Control.
|
|
/// </summary>
|
|
[Designer("DevComponents.DotNetBar.Layout.Design.LayoutControlItemDesigner, DevComponents.DotNetBar.Layout.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=7eb7c3a35b91de04")]
|
|
public class LayoutControlItem : LayoutItemBase
|
|
{
|
|
#region Constructor
|
|
protected override void OnDispose()
|
|
{
|
|
UnhookControlEventHandlers(_Control);
|
|
base.OnDispose();
|
|
}
|
|
#endregion
|
|
|
|
#region Implementation
|
|
protected override void OnUpdateLayout()
|
|
{
|
|
base.OnUpdateLayout();
|
|
|
|
if (_Control != null)
|
|
{
|
|
Rectangle bounds = Helpers.Deflate(this.Bounds, this.Padding);
|
|
Rectangle r = bounds;
|
|
if (this.TextVisible && !string.IsNullOrEmpty(this.Text))
|
|
{
|
|
Rectangle actualTextBounds = this.ActualTextBounds;
|
|
if (IsImageVisible)
|
|
actualTextBounds = Rectangle.Union(actualTextBounds, this.ActualImageBounds);
|
|
if (this.TextPosition == eLayoutPosition.Default || this.TextPosition == eLayoutPosition.Left)
|
|
{
|
|
r.X = actualTextBounds.Right + _TextControlSpacing;
|
|
r.Width = bounds.Right - r.X;
|
|
}
|
|
else if (this.TextPosition == eLayoutPosition.Top)
|
|
{
|
|
r.Y = actualTextBounds.Bottom + _TextControlSpacing;
|
|
r.Height = bounds.Bottom - r.Y;
|
|
}
|
|
else if (this.TextPosition == eLayoutPosition.Bottom)
|
|
{
|
|
r.Height = actualTextBounds.Y - bounds.Y - _TextControlSpacing;
|
|
}
|
|
else if (this.TextPosition == eLayoutPosition.Right)
|
|
{
|
|
r.Width = actualTextBounds.X - r.X - _TextControlSpacing;
|
|
}
|
|
}
|
|
if (_Control.Margin.Horizontal > 0 || _Control.Margin.Vertical > 0)
|
|
{
|
|
r.X += _Control.Margin.Left;
|
|
r.Width -= _Control.Margin.Horizontal;
|
|
r.Y += _Control.Margin.Top;
|
|
r.Height -= _Control.Margin.Vertical;
|
|
}
|
|
|
|
if (!_ControlSize.IsEmpty && _Control.Dock != DockStyle.Fill && (_ControlSize.Width > 0 && r.Width > _ControlSize.Width) || (_ControlSize.Height > 0 && r.Height > _ControlSize.Height))
|
|
{
|
|
Size controlSize = new Size(_ControlSize.Width > 0 ? Math.Min(r.Width, _ControlSize.Width) : r.Width,
|
|
_ControlSize.Height > 0 ? Math.Min(r.Height, _ControlSize.Height) : r.Height);
|
|
if (_Control.Dock != DockStyle.None)
|
|
{
|
|
if (_Control.Dock == DockStyle.Left)
|
|
r = new Rectangle(r.X, r.Y, controlSize.Width, r.Height);
|
|
else if (_Control.Dock == DockStyle.Right)
|
|
r = new Rectangle(r.Right - controlSize.Width, r.Y, controlSize.Width, r.Height);
|
|
else if (_Control.Dock == DockStyle.Top)
|
|
r = new Rectangle(r.X, r.Y, r.Width, controlSize.Height);
|
|
else if (_Control.Dock == DockStyle.Bottom)
|
|
r = new Rectangle(r.X, r.Bottom - controlSize.Height, r.Width, controlSize.Height);
|
|
}
|
|
else
|
|
{
|
|
if (_Control.Anchor == (AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom))
|
|
{
|
|
// Center into the bounding box
|
|
r.X += (r.Width - controlSize.Width) / 2;
|
|
r.Y += (r.Height - controlSize.Height) / 2;
|
|
r.Size = controlSize;
|
|
}
|
|
else if (_Control.Anchor == (AnchorStyles.Left | AnchorStyles.Top))
|
|
{
|
|
r.Size = controlSize;
|
|
}
|
|
else if (_Control.Anchor == (AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right))
|
|
{
|
|
r.X += (r.Width - controlSize.Width) / 2;
|
|
r.Size = controlSize;
|
|
}
|
|
else if (_Control.Anchor == (AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Bottom))
|
|
{
|
|
r.Y += (r.Height - controlSize.Height) / 2;
|
|
r.Size = controlSize;
|
|
}
|
|
else if (_Control.Anchor == (AnchorStyles.Left | AnchorStyles.Bottom))
|
|
{
|
|
r.Y = r.Bottom - controlSize.Height;
|
|
r.Size = controlSize;
|
|
}
|
|
else if (_Control.Anchor == (AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Right))
|
|
{
|
|
r.Y = r.Bottom - controlSize.Height;
|
|
r.X += (r.Width - controlSize.Width) / 2;
|
|
r.Size = controlSize;
|
|
}
|
|
else if (_Control.Anchor == (AnchorStyles.Right | AnchorStyles.Top))
|
|
{
|
|
r.X = r.Right - controlSize.Width;
|
|
r.Size = controlSize;
|
|
}
|
|
else if (_Control.Anchor == (AnchorStyles.Right | AnchorStyles.Bottom))
|
|
{
|
|
r.X = r.Right - controlSize.Width;
|
|
r.Y = r.Bottom - controlSize.Height;
|
|
r.Size = controlSize;
|
|
}
|
|
else if (_Control.Anchor == (AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Top))
|
|
{
|
|
r.X = r.Right - controlSize.Width;
|
|
r.Y += (r.Height - controlSize.Height) / 2;
|
|
r.Size = controlSize;
|
|
}
|
|
else
|
|
r.Size = controlSize;
|
|
}
|
|
}
|
|
|
|
_Control.Bounds = r;
|
|
}
|
|
}
|
|
|
|
protected override void OnPaintBackground(PaintContext context)
|
|
{
|
|
base.OnPaintBackground(context);
|
|
|
|
if (IsKeyboardFocusWithin && context.FocusStyle != null)
|
|
{
|
|
DrawingHelpers.PaintStyle(context.Graphics, context.FocusStyle, this.Bounds);
|
|
}
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public override void ScaleItem(SizeF factor)
|
|
{
|
|
base.ScaleItem(factor);
|
|
|
|
bool widthChanged = factor.Width != 1f;
|
|
bool heightChanged = factor.Height != 1f;
|
|
|
|
if (!_ControlSize.IsEmpty && (widthChanged || heightChanged))
|
|
{
|
|
Size newSize = new Size();
|
|
if (widthChanged)
|
|
newSize.Width = (int)(_ControlSize.Width * factor.Width);
|
|
else
|
|
newSize.Width = _ControlSize.Width;
|
|
if (heightChanged)
|
|
newSize.Height = (int)(_ControlSize.Height * factor.Height);
|
|
else
|
|
newSize.Height = _ControlSize.Height;
|
|
ControlSize = newSize;
|
|
}
|
|
}
|
|
|
|
internal override void UpdateScrollBounds(int xScroll, int yScroll, bool moveControls)
|
|
{
|
|
base.UpdateScrollBounds(xScroll, yScroll, moveControls);
|
|
if (moveControls && _Control != null)
|
|
_Control.Location = new Point(_Control.Location.X + xScroll, _Control.Location.Y + yScroll);
|
|
}
|
|
|
|
protected override Size OnMeasureText(LayoutContext c)
|
|
{
|
|
if (_Control is TextBoxBase && this.TextPosition == eLayoutPosition.Default)
|
|
{
|
|
TextBoxBase textBox = (TextBoxBase)_Control;
|
|
int textBaseLine = Helpers.GetTextBaseline(_Control, ContentAlignment.TopLeft);
|
|
if (textBox is DevComponents.DotNetBar.Controls.TextBoxX)
|
|
textBaseLine += 3;
|
|
else if (textBox.BorderStyle == BorderStyle.FixedSingle || textBox.BorderStyle == BorderStyle.None)
|
|
textBaseLine += 2;
|
|
else if (textBox.BorderStyle == BorderStyle.Fixed3D)
|
|
textBaseLine += 3;
|
|
_ControlTextBaseline = textBaseLine;
|
|
}
|
|
else
|
|
_ControlTextBaseline = 0;
|
|
|
|
return base.OnMeasureText(c);
|
|
}
|
|
|
|
internal override int TextBaseline
|
|
{
|
|
get
|
|
{
|
|
if (_ControlTextBaseline > 0 && _ControlTextBaseline > base.TextBaseline)
|
|
return _ControlTextBaseline;
|
|
return base.TextBaseline;
|
|
}
|
|
set
|
|
{
|
|
base.TextBaseline = value;
|
|
}
|
|
}
|
|
|
|
private int _ControlTextBaseline = 0;
|
|
|
|
private Control _Control = null;
|
|
/// <summary>
|
|
/// Gets or sets the control managed by layout item.
|
|
/// </summary>
|
|
[DefaultValue(null), Category("Data"), Description("Indicates control managed by layout item.")]
|
|
public Control Control
|
|
{
|
|
get { return _Control; }
|
|
set
|
|
{
|
|
if (value != _Control)
|
|
{
|
|
Control oldValue = _Control;
|
|
_Control = value;
|
|
OnControlChanged(oldValue, value);
|
|
}
|
|
}
|
|
}
|
|
private void UnhookControlEventHandlers(Control control)
|
|
{
|
|
if (control == null) return;
|
|
control.Enter -= ControlEnter;
|
|
control.Leave -= ControlLeave;
|
|
control.MouseHover -= ControlMouseHover;
|
|
control.MouseDown -= ControlMouseDown;
|
|
control.MouseMove -= ControlMouseMove;
|
|
control.MouseLeave -= ControlMouseLeave;
|
|
}
|
|
/// <summary>
|
|
/// Called when Control property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
protected virtual void OnControlChanged(Control oldValue, Control newValue)
|
|
{
|
|
if (oldValue != null)
|
|
{
|
|
UnhookControlEventHandlers(oldValue);
|
|
}
|
|
OnPropertyChanged(new PropertyChangedEventArgs("Control"));
|
|
if (_Control != null)
|
|
{
|
|
_Control.Enter += ControlEnter;
|
|
_Control.Leave += ControlLeave;
|
|
_Control.MouseHover += ControlMouseHover;
|
|
_Control.MouseDown += ControlMouseDown;
|
|
_Control.MouseMove += ControlMouseMove;
|
|
_Control.MouseLeave += ControlMouseLeave;
|
|
|
|
if (_Control.Visible != this.Visible)
|
|
_Control.Visible = this.Visible;
|
|
}
|
|
InvalidateLayout();
|
|
}
|
|
private Point _MouseTooltipLocation = Point.Empty;
|
|
void ControlMouseLeave(object sender, EventArgs e)
|
|
{
|
|
_MouseTooltipLocation = Point.Empty;
|
|
if (ToolTipVisible)
|
|
HideToolTip();
|
|
}
|
|
|
|
void ControlMouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
if (!_MouseTooltipLocation.IsEmpty && ToolTipVisible && (Math.Abs(_MouseTooltipLocation.X - e.X) > 1 || Math.Abs(_MouseTooltipLocation.Y - e.Y) > 1))
|
|
HideToolTip();
|
|
}
|
|
|
|
void ControlMouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
if (ToolTipVisible)
|
|
HideToolTip();
|
|
}
|
|
|
|
void ControlMouseHover(object sender, EventArgs e)
|
|
{
|
|
if (_EnableControlTooltip)
|
|
{
|
|
ShowToolTip();
|
|
_MouseTooltipLocation = _Control.PointToClient(Control.MousePosition);
|
|
}
|
|
}
|
|
|
|
private void ControlLeave(object sender, EventArgs e)
|
|
{
|
|
IsKeyboardFocusWithin = false;
|
|
}
|
|
|
|
private void ControlEnter(object sender, EventArgs e)
|
|
{
|
|
IsKeyboardFocusWithin = true;
|
|
}
|
|
|
|
private bool _EnableControlTooltip = true;
|
|
/// <summary>
|
|
/// Indicates whether Tooltip for the item is shown when mouse is over the control.
|
|
/// </summary>
|
|
[DefaultValue(true), Category("Behavior"), Description("Indicates whether Tooltip for the item is shown when mouse is over the control.")]
|
|
public bool EnableControlTooltip
|
|
{
|
|
get { return _EnableControlTooltip; }
|
|
set
|
|
{
|
|
if (value != _EnableControlTooltip)
|
|
{
|
|
bool oldValue = _EnableControlTooltip;
|
|
_EnableControlTooltip = value;
|
|
OnEnableControlTooltipChanged(oldValue, value);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when EnableControlTooltip property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
protected virtual void OnEnableControlTooltipChanged(bool oldValue, bool newValue)
|
|
{
|
|
OnPropertyChanged(new PropertyChangedEventArgs("EnableControlTooltip"));
|
|
}
|
|
|
|
private int _TextControlSpacing = 3;
|
|
/// <summary>
|
|
/// Indicates spacing between text and the control.
|
|
/// </summary>
|
|
[DefaultValue(3), Category("Appearance"), Description("Indicates spacing between text and the control."), RefreshProperties(RefreshProperties.All)]
|
|
public int TextControlSpacing
|
|
{
|
|
get { return _TextControlSpacing; }
|
|
set
|
|
{
|
|
if (value != _TextControlSpacing)
|
|
{
|
|
int oldValue = _TextControlSpacing;
|
|
_TextControlSpacing = value;
|
|
OnTextControlSpacingChanged(oldValue, value);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when TextControlSpacing property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
protected virtual void OnTextControlSpacingChanged(int oldValue, int newValue)
|
|
{
|
|
OnPropertyChanged(new PropertyChangedEventArgs("TextControlSpacing"));
|
|
InvalidateLayout();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processes accelerator key for the item.
|
|
/// </summary>
|
|
/// <param name="charCode"></param>
|
|
internal override bool ProcessMnemonic(char charCode)
|
|
{
|
|
if (MnemonicsEnabled && _Control != null && _Control.CanSelect)
|
|
{
|
|
_Control.Select();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private Size _ControlSize = Size.Empty;
|
|
/// <summary>
|
|
/// Indicates suggested control size which is used only if calculated layout size for the control exceeds the size specified here. Either width or height may be set or both.
|
|
/// ControlSize property can be used in conjuction with Dock and Anchor properties on the Control. When available space for the Control
|
|
/// exceeds ControlSize the Dock and Anchor properties will indicate the control position inside of the control box.
|
|
/// </summary>
|
|
[Category("Appearance"), Description("Indicates suggested control size which is used only if calculated layout size for the control exceeds the size specified here. Either width or height may be set or both.")]
|
|
public Size ControlSize
|
|
{
|
|
get { return _ControlSize; }
|
|
set
|
|
{
|
|
if (value != _ControlSize)
|
|
{
|
|
Size oldValue = _ControlSize;
|
|
_ControlSize = value;
|
|
OnControlSizeChanged(oldValue, value);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when ControlSize property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
protected virtual void OnControlSizeChanged(Size oldValue, Size newValue)
|
|
{
|
|
OnPropertyChanged(new PropertyChangedEventArgs("ControlSize"));
|
|
InvalidateLayout();
|
|
}
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeControlSize()
|
|
{
|
|
return !_ControlSize.IsEmpty;
|
|
}
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void ResetControlSize()
|
|
{
|
|
ControlSize = Size.Empty;
|
|
}
|
|
|
|
private bool _AutoSetTabIndex = true;
|
|
/// <summary>
|
|
/// Indicates whether Control TabIndex is automatically set based on the position of the item inside of the layout.
|
|
/// </summary>
|
|
[DefaultValue(true), Category("Behavior"), Description("Indicates whether Control TabIndex is automatically set based on the position of the item inside of the layout.")]
|
|
public bool AutoSetTabIndex
|
|
{
|
|
get { return _AutoSetTabIndex; }
|
|
set
|
|
{
|
|
if (value != _AutoSetTabIndex)
|
|
{
|
|
bool oldValue = _AutoSetTabIndex;
|
|
_AutoSetTabIndex = value;
|
|
OnAutoSetTabIndexChanged(oldValue, value);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when AutoSetTabIndex property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
protected virtual void OnAutoSetTabIndexChanged(bool oldValue, bool newValue)
|
|
{
|
|
OnPropertyChanged(new PropertyChangedEventArgs("AutoSetTabIndex"));
|
|
|
|
}
|
|
|
|
protected override void OnAbsoluteIndexChanged(int oldValue, int newValue)
|
|
{
|
|
if (_Control != null && _AutoSetTabIndex) _Control.TabIndex = newValue;
|
|
|
|
base.OnAbsoluteIndexChanged(oldValue, newValue);
|
|
}
|
|
|
|
private bool _FocusVisualStyleEnabled = true;
|
|
/// <summary>
|
|
/// Indicates whether LayoutControl.FocusStyle is used to paint background of item when control has input focus.
|
|
/// </summary>
|
|
[DefaultValue(true), Category("Behavior"), Description("Indicates whether LayoutControl.FocusStyle is used to paint background of item when control has input focus.")]
|
|
public bool FocusVisualStyleEnabled
|
|
{
|
|
get { return _FocusVisualStyleEnabled; }
|
|
set
|
|
{
|
|
if (_FocusVisualStyleEnabled == value)
|
|
return;
|
|
_FocusVisualStyleEnabled = value;
|
|
if (this.IsKeyboardFocusWithin)
|
|
this.Invalidate();
|
|
OnPropertyChanged(new PropertyChangedEventArgs("FocusVisualStyleEnabled"));
|
|
}
|
|
}
|
|
|
|
protected override void OnVisibleChanged(bool oldValue, bool newValue)
|
|
{
|
|
if (_Control != null)
|
|
_Control.Visible = newValue;
|
|
base.OnVisibleChanged(oldValue, newValue);
|
|
}
|
|
#endregion
|
|
}
|
|
}
|