1379 lines
52 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Windows.Forms.Layout;
using System.ComponentModel;
namespace DevComponents.DotNetBar.Layout
{
[ToolboxItem(true)]
[Designer("DevComponents.DotNetBar.Layout.Design.LayoutControlDesigner, DevComponents.DotNetBar.Layout.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=7eb7c3a35b91de04")]
[ToolboxBitmap(typeof(LayoutControl), "LayoutControl.ico")]
public class LayoutControl : ContainerControl
{
/// <summary>
/// Initializes a new instance of the LayoutControl class.
/// </summary>
public LayoutControl()
{
this.SetStyle(ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer
| ControlStyles.SupportsTransparentBackColor | ControlStyles.Opaque, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
//this.SetStyle(ControlStyles.Opaque, true);
_RootGroup.IsRootGroup = true;
_HScrollBar = new DevComponents.DotNetBar.ScrollBar.HScrollBarAdv();
_HScrollBar.Height = SystemInformation.HorizontalScrollBarHeight;
_HScrollBar.Visible = false;
_HScrollBar.Scroll += new ScrollEventHandler(HScrollBarScroll);
this.Controls.Add(_HScrollBar);
_VScrollBar = new VScrollBarAdv();
_VScrollBar.Width = SystemInformation.VerticalScrollBarWidth;
_VScrollBar.Visible = false;
_VScrollBar.Scroll += VScrollBarScroll;
this.Controls.Add(_VScrollBar);
_Thumb = new Control();
_Thumb.Width = SystemInformation.VerticalScrollBarWidth;
_Thumb.Height = SystemInformation.HorizontalScrollBarHeight;
_Thumb.Visible = false;
this.Controls.Add(_Thumb);
_InsertMarker = new InsertMarker();
_InsertMarker.Visible = false;
this.Controls.Add(_InsertMarker);
_RootGroup.LayoutControl = this;
this.FocusStyle = new SimpleStyle();
if (BarFunctions.IsWindows7 && DevComponents.DotNetBar.Touch.TouchHandler.IsTouchEnabled)
{
_TouchHandler = new DevComponents.DotNetBar.Touch.TouchHandler(this, DevComponents.DotNetBar.Touch.eTouchHandlerType.Gesture);
_TouchHandler.PanBegin += new EventHandler<DevComponents.DotNetBar.Touch.GestureEventArgs>(TouchHandlerPanBegin);
_TouchHandler.Pan += new EventHandler<DevComponents.DotNetBar.Touch.GestureEventArgs>(TouchHandlerPan);
_TouchHandler.PanEnd += new EventHandler<DevComponents.DotNetBar.Touch.GestureEventArgs>(TouchHandlerPanEnd);
}
StyleManager.Register(this);
}
protected override void Dispose(bool disposing)
{
if (disposing) StyleManager.Unregister(this);
base.Dispose(disposing);
}
private Color _CurrentBackColor = Color.Empty;
private void UpdateBackColor()
{
DevComponents.DotNetBar.Rendering.Office2007ColorTable table = ((DevComponents.DotNetBar.Rendering.Office2007Renderer)DevComponents.DotNetBar.Rendering.GlobalManager.Renderer).ColorTable;
_CurrentBackColor = table.Form.BackColor;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="newStyle">New active style.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
public void StyleManagerStyleChanged(eDotNetBarStyle newStyle)
{
UpdateBackColor();
this.Invalidate(true);
}
void HScrollBarScroll(object sender, ScrollEventArgs e)
{
if (e.NewValue != e.OldValue)
ScrollControls(-e.NewValue, 0);
}
void VScrollBarScroll(object sender, ScrollEventArgs e)
{
if (e.NewValue != e.OldValue)
ScrollControls(0, -e.NewValue);
//Console.WriteLine("{0} {1} {2}", e.Type, e.NewValue, _RootGroup.ActualBounds.Height);
}
private Control _Thumb = null;
private DevComponents.DotNetBar.ScrollBar.HScrollBarAdv _HScrollBar = null;
private VScrollBarAdv _VScrollBar = null;
private InsertMarker _InsertMarker = null;
protected override void OnPaint(PaintEventArgs e)
{
#if TRIAL
if(WinApi.ColorExpAlt())
{
StringFormat format=new StringFormat(StringFormat.GenericDefault);
format.Alignment=StringAlignment.Center;
format.FormatFlags=format.FormatFlags & ~(format.FormatFlags & StringFormatFlags.NoWrap);
e.Graphics.DrawString("Thank you very much for trying DotNetBar. Unfortunately your trial period is over. To continue using DotNetBar you should purchase license at http://www.devcomponents.com",new Font(this.Font.FontFamily,12),SystemBrushes.Highlight,this.ClientRectangle,format);
format.Dispose();
return;
}
#endif
if ((this.BackColor.IsEmpty || this.BackColor == Color.Transparent))
{
base.OnPaintBackground(e);
}
else if(this.BackColor == SystemColors.Control && !_CurrentBackColor.IsEmpty)
{
using (SolidBrush brush = new SolidBrush(_CurrentBackColor))
e.Graphics.FillRectangle(brush, this.ClientRectangle);
}
else
{
using (SolidBrush brush = new SolidBrush(this.BackColor))
e.Graphics.FillRectangle(brush, this.ClientRectangle);
}
using (PaintContext context = new PaintContext(this, e.Graphics, _HotkeyPrefix))
{
_RootGroup.Paint(context);
}
//if (!string.IsNullOrEmpty(this.Text))
// e.Graphics.DrawString(this.Text, this.Font, Brushes.Black, new PointF(0, this.Height - 32));
base.OnPaint(e);
}
protected override void OnHandleCreated(EventArgs e)
{
UpdateBackColor();
_RootGroup.SetBounds(GetLayoutBounds());
//LayoutGroup();
base.OnHandleCreated(e);
}
private void LayoutGroup()
{
if (this.IsHandleCreated)
{
using (Graphics g = this.CreateGraphics())
{
LayoutContext context = new LayoutContext(this, g, _LabelFont ?? this.Font);
_RootGroup.Layout(context);
}
}
}
private Rectangle GetLayoutBounds()
{
Rectangle r = this.ClientRectangle;
return r;
}
protected override void OnLayout(LayoutEventArgs levent)
{
if (_VScrollBar == null || _HScrollBar == null || !this.IsHandleCreated) return;
Rectangle r = GetLayoutBounds();
if (r.Width <= 0 || r.Height <= 0) return;
WinApi.SendMessage(this.Handle, WinApi.WM_SETREDRAW, 0, 0);
r.Offset(_ScrollPosition);
_RootGroup.SetBounds(r);
LayoutGroup();
bool hScrollBarVisible = false, vScrollBarVisible = false;
if (_RootGroup.ActualBounds.Height > r.Height + 1)
{
vScrollBarVisible = true;
r.Width -= _VScrollBar.Width;
_RootGroup.SetBounds(r);
LayoutGroup();
if (_RootGroup.ActualBounds.Width > r.Width + 1)
{
hScrollBarVisible = true;
r.Height -= _HScrollBar.Height;
_RootGroup.SetBounds(r);
LayoutGroup();
}
}
else if (_RootGroup.ActualBounds.Width > r.Width + 1)
{
hScrollBarVisible = true;
r.Height -= _HScrollBar.Height;
_RootGroup.SetBounds(r);
LayoutGroup();
if (_RootGroup.ActualBounds.Height > r.Height + 1)
{
vScrollBarVisible = true;
r.Width -= _VScrollBar.Width;
_RootGroup.SetBounds(r);
LayoutGroup();
}
}
bool performLayout = false;
if (vScrollBarVisible && r.Height > 0)
{
_VScrollBar.Location = new Point(this.ClientRectangle.Right - _VScrollBar.Width, this.ClientRectangle.Y);
_VScrollBar.Height = this.ClientRectangle.Height - (hScrollBarVisible ? _HScrollBar.Height : 0);
if (_VScrollBar.Visible != vScrollBarVisible)
{
_VScrollBar.Value = 0;
_VScrollBar.Visible = true;
_VScrollBar.BringToFront();
}
_VScrollBar.Minimum = 0;
_VScrollBar.Maximum = _RootGroup.ActualBounds.Height - 1;
_VScrollBar.LargeChange = r.Height;
_VScrollBar.SmallChange = 16;
}
else if (_VScrollBar.Visible)
{
_VScrollBar.Visible = false;
if (_ScrollPosition.Y != 0)
{
_ScrollPosition.Y = 0;
performLayout = true;
}
}
if (hScrollBarVisible && r.Width > 0)
{
_HScrollBar.Location = new Point(this.ClientRectangle.X, this.ClientRectangle.Bottom - _HScrollBar.Height);
_HScrollBar.Width = this.ClientRectangle.Width - (vScrollBarVisible ? _VScrollBar.Width : 0);
if (_HScrollBar.Visible != hScrollBarVisible)
{
_HScrollBar.Value = 0;
_HScrollBar.Visible = true;
_HScrollBar.BringToFront();
}
_HScrollBar.Minimum = 0;
_HScrollBar.Maximum = _RootGroup.ActualBounds.Width - 1;
_HScrollBar.LargeChange = r.Width;
_HScrollBar.SmallChange = 16;
}
else if (_HScrollBar.Visible)
{
_HScrollBar.Visible = false;
if (_ScrollPosition.X != 0)
{
_ScrollPosition.X = 0;
performLayout = true;
}
}
if (vScrollBarVisible && hScrollBarVisible && r.Height > 0 && r.Width > 0)
{
_Thumb.Bounds = new Rectangle(this.ClientRectangle.Right - _VScrollBar.Width, this.ClientRectangle.Bottom - _HScrollBar.Height, _VScrollBar.Width, _HScrollBar.Height);
_Thumb.Visible = true;
_Thumb.BringToFront();
}
else if (_Thumb.Visible)
_Thumb.Visible = false;
if (performLayout)
{
r = GetLayoutBounds();
r.Offset(_ScrollPosition);
_RootGroup.SetBounds(r);
LayoutGroup();
}
WinApi.SendMessage(this.Handle, WinApi.WM_SETREDRAW, 1, 0);
this.Refresh();
base.OnLayout(levent);
}
protected override void OnMouseWheel(MouseEventArgs e)
{
if (_VScrollBar.Visible)
{
int y = -_VScrollBar.Value + Math.Sign(e.Delta) * _VScrollBar.SmallChange;
if (-y < 0) y = 0;
ScrollControls(0, y);
_VScrollBar.Value = Math.Min(_VScrollBar.Maximum - _VScrollBar.LargeChange, -y);
}
base.OnMouseWheel(e);
}
public new void ScrollControlIntoView(Control control)
{
LayoutItemBase item = FindControlItem(control);
if (item == null) return;
ScrollItemIntoView(item);
}
/// <summary>
/// Brings specified item that belongs to this LayoutControl into view by scrolling control if necessary.
/// </summary>
/// <param name="item">Item to bring into view.</param>
public void ScrollItemIntoView(LayoutItemBase item)
{
if (item.GetLayoutControl() != this)
throw new ArgumentException("item does not belong to this control");
if (!_HScrollBar.Visible && !_VScrollBar.Visible) return;
Rectangle clientRect = this.ClientRectangle;
Rectangle itemBounds = item.Bounds;
//itemBounds.Offset(-_ScrollPosition.X,-_ScrollPosition.Y);
if (clientRect.Contains(itemBounds)) return;
Point scroll = new Point();
if (item.Bounds.Y < clientRect.Y)
{
scroll.Y = clientRect.Y - itemBounds.Y;
}
else if (item.Bounds.Bottom > clientRect.Bottom)
{
scroll.Y = Math.Max(-(_VScrollBar.Maximum - _VScrollBar.LargeChange), clientRect.Bottom - itemBounds.Bottom);
}
if (item.Bounds.X < clientRect.X)
{
scroll.X = clientRect.X - itemBounds.X;
}
else if (item.Bounds.Right > clientRect.Right)
{
scroll.X = clientRect.Right - itemBounds.Right;
}
if (!scroll.IsEmpty)
{
ScrollControls(_ScrollPosition.X + scroll.X, _ScrollPosition.Y + scroll.Y);
_VScrollBar.Value = Math.Max(0, Math.Min(Math.Abs(_ScrollPosition.Y), _VScrollBar.Maximum));
}
}
private LayoutGroup _RootGroup = new LayoutGroup();
/// <summary>
/// Gets the LayoutGroup for the control. LayoutGroup should not be changed.
/// </summary>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Browsable(false)]
public LayoutGroup RootGroup
{
get { return _RootGroup; }
set
{
if (value != _RootGroup)
{
LayoutGroup oldValue = _RootGroup;
_RootGroup = value;
OnRootGroupChanged(oldValue, value);
}
}
}
/// <summary>
/// Called when RootGroup property has changed.
/// </summary>
/// <param name="oldValue">Old property value</param>
/// <param name="newValue">New property value</param>
protected virtual void OnRootGroupChanged(LayoutGroup oldValue, LayoutGroup newValue)
{
if (oldValue != null)
{
oldValue.LayoutControl = null;
oldValue.IsRootGroup = false;
}
if (newValue != null)
{
newValue.LayoutControl = this;
newValue.IsRootGroup = true;
}
//OnPropertyChanged(new PropertyChangedEventArgs("RootGroup"));
}
private Font _LabelFont = null;
/// <summary>
/// Indicates font used for the item labels.
/// </summary>
[DefaultValue(null), Category("Appearance"), Description("Indicates font used for the item labels.")]
public Font LabelFont
{
get { return _LabelFont; }
set
{
if (value != _LabelFont)
{
Font oldValue = _LabelFont;
_LabelFont = value;
OnLabelFontChanged(oldValue, value);
}
}
}
/// <summary>
/// Called when LabelFont property has changed.
/// </summary>
/// <param name="oldValue">Old property value</param>
/// <param name="newValue">New property value</param>
protected virtual void OnLabelFontChanged(Font oldValue, Font newValue)
{
//OnPropertyChanged(new PropertyChangedEventArgs("LabelFont"));
this.PerformLayout();
this.Invalidate();
}
private Color _LabelTextColor = Color.Empty;
/// <summary>
/// Gets or sets the color of the label text.
/// </summary>
[Category("Appearance"), Description("Indicates color of label text.")]
public Color LabelTextColor
{
get { return _LabelTextColor; }
set { _LabelTextColor = value; /*OnPropertyChanged("LabelTextColor");*/ this.Invalidate(); }
}
/// <summary>
/// Gets whether property should be serialized.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool ShouldSerializeLabelTextColor()
{
return !_LabelTextColor.IsEmpty;
}
/// <summary>
/// Resets property to its default value.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public void ResetLabelTextColor()
{
this.LabelTextColor = Color.Empty;
}
private eTextAlignment _LabelTextAlignment = eTextAlignment.Default;
/// <summary>
/// Indicates the label text alignment within the text bounds.
/// </summary>
[DefaultValue(eTextAlignment.Default), Category("Appearance"), Description("Indicates the label text alignment within the text bounds.")]
public eTextAlignment LabelTextAlignment
{
get { return _LabelTextAlignment; }
set
{
if (value != _LabelTextAlignment)
{
eTextAlignment oldValue = _LabelTextAlignment;
_LabelTextAlignment = value;
OnLabelTextAlignmentChanged(oldValue, value);
}
}
}
/// <summary>
/// Called when LabelTextAlignment property has changed.
/// </summary>
/// <param name="oldValue">Old property value</param>
/// <param name="newValue">New property value</param>
protected virtual void OnLabelTextAlignmentChanged(eTextAlignment oldValue, eTextAlignment newValue)
{
//OnPropertyChanged(new PropertyChangedEventArgs("LabelTextAlignment"));
this.Invalidate();
}
private EmptyLayoutManager _EmptyLayout = new EmptyLayoutManager();
public override LayoutEngine LayoutEngine
{
get
{
return _EmptyLayout;
}
}
/// <summary>
/// Sets default property values for LayoutControlItem given the control assigned to it.
/// </summary>
/// <param name="item">Reference to LayoutControlItem</param>
public void SetupControlItem(DevComponents.DotNetBar.Layout.LayoutControlItem item)
{
if (item == null || item.Control == null) return;
Control c = item.Control;
c.Margin = new System.Windows.Forms.Padding();
if (c is TextBoxBase)
{
item.Width = 100;
item.WidthType = eLayoutSizeType.Percent;
item.Height = c.Height + item.Padding.Vertical;
item.Text = "Label:";
item.MinSize = new Size(120, 0);
}
else if (c is ButtonBase || c is IButtonControl)
{
//item.ControlSize = c.Size;
item.Width = c.Width + item.Padding.Horizontal;
item.Height = c.Height + item.Padding.Vertical;
item.Text = "";
item.MinSize = new Size(32, 20);
}
else if(c is DevComponents.DotNetBar.Controls.RatingStar)
{
c.Text = "";
item.Width = c.Width + item.Padding.Horizontal;
item.Height = c.Height + item.Padding.Vertical;
item.Text = "Rating:";
item.MinSize = new Size(85, 23);
}
else
{
item.Width = c.Width + item.Padding.Horizontal;
item.Height = c.Height + item.Padding.Vertical;
item.Text = "Label:";
item.MinSize = new Size(64, 18);
}
}
private LayoutItemBase FindItemForMnemonic(LayoutGroup group, char charCode)
{
foreach (LayoutItemBase item in group.Items)
{
LayoutGroup childGroup = item as LayoutGroup;
if (childGroup != null)
{
LayoutItemBase item2 = FindItemForMnemonic(childGroup, charCode);
if (item2 != null) return item2;
}
else if (item.TextVisible && !string.IsNullOrEmpty(item.Text) && IsMnemonic(charCode, item.Text))
{
return item;
}
}
return null;
}
private bool IsMnemonicProcessed(char charCode)
{
LayoutItemBase item = FindItemForMnemonic(_RootGroup, charCode);
if (item != null)
return item.ProcessMnemonic(charCode);
return false;
}
protected override bool ProcessMnemonic(char charCode)
{
if (this.Visible && _MnemonicsEnabled && IsMnemonicProcessed(charCode))
return true;
return base.ProcessMnemonic(charCode);
}
private bool _MnemonicsEnabled = true;
/// <summary>
/// Indicates whether accelerator keys assigned to item Text property are processed by items which respond to them.
/// </summary>
[DefaultValue(true), Category("Behavior"), Description("Indicates whether accelerator keys assigned to item Text property are processed by items which respond to them.")]
public bool MnemonicsEnabled
{
get { return _MnemonicsEnabled; }
set
{
if (value != _MnemonicsEnabled)
{
bool oldValue = _MnemonicsEnabled;
_MnemonicsEnabled = value;
OnMnemonicsEnabledChanged(oldValue, value);
}
}
}
/// <summary>
/// Called when MnemonicsEnabled property has changed.
/// </summary>
/// <param name="oldValue">Old property value</param>
/// <param name="newValue">New property value</param>
protected virtual void OnMnemonicsEnabledChanged(bool oldValue, bool newValue)
{
//OnPropertyChanged(new PropertyChangedEventArgs("MnemonicsEnabled"));
}
private System.Drawing.Text.HotkeyPrefix _HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show;
/// <summary>
/// Indicates visibility of the hot-key prefixes, accelerator keys, that are set using ampersand in item Text.
/// </summary>
[DefaultValue(System.Drawing.Text.HotkeyPrefix.Show), Category("Behavior"), Description("Indicates visibility of the hot-key prefixes, accelerator keys, that are set using ampersand in item Text.")]
public System.Drawing.Text.HotkeyPrefix HotkeyPrefix
{
get { return _HotkeyPrefix; }
set
{
if (value != _HotkeyPrefix)
{
System.Drawing.Text.HotkeyPrefix oldValue = _HotkeyPrefix;
_HotkeyPrefix = value;
OnHotkeyPrefixChanged(oldValue, value);
}
}
}
/// <summary>
/// Called when HotkeyPrefix property has changed.
/// </summary>
/// <param name="oldValue">Old property value</param>
/// <param name="newValue">New property value</param>
protected virtual void OnHotkeyPrefixChanged(System.Drawing.Text.HotkeyPrefix oldValue, System.Drawing.Text.HotkeyPrefix newValue)
{
this.Invalidate();
//OnPropertyChanged(new PropertyChangedEventArgs("HotkeyPrefix"));
}
private Size GetAutoScrollMinSize()
{
Rectangle clientRectangle = GetLayoutBounds();
Rectangle displayRect = _RootGroup.ActualBounds;
return new Size(Math.Abs(Math.Min(clientRectangle.Width - displayRect.Width, 0)),
Math.Abs(Math.Min(clientRectangle.Height - displayRect.Height, 0)));
}
private Point _ScrollPosition = new Point();
private void ScrollControls(Point scrollPosition)
{
ScrollControls(scrollPosition.X, scrollPosition.Y);
}
private void ScrollControls(int x, int y)
{
int xScroll = 0;
int yScroll = 0;
Rectangle clientRectangle = GetLayoutBounds();
if (_VScrollBar.Visible)
clientRectangle.Width -= _VScrollBar.Width;
if (_HScrollBar.Visible)
clientRectangle.Height -= _HScrollBar.Height;
Rectangle displayRect = _RootGroup.ActualBounds;
int maxXScroll = Math.Min(clientRectangle.Width - displayRect.Width, 0);
int maxYScroll = Math.Min(clientRectangle.Height - displayRect.Height, 0);
if (x > 0)
x = 0;
if (y > 0)
y = 0;
if (x < maxXScroll)
x = maxXScroll;
if (y < maxYScroll)
y = maxYScroll;
if (_ScrollPosition.X != x)
xScroll = x - displayRect.X;
if (_ScrollPosition.Y != y)
yScroll = y - displayRect.Y;
_ScrollPosition.X = x;
_ScrollPosition.Y = y;
bool useScrollWindowEx = !(_VScrollBar.Visible && _HScrollBar.Visible);
if ((xScroll != 0) || ((yScroll != 0) && this.IsHandleCreated))
{
DateTime start = DateTime.Now;
if (useScrollWindowEx)
{
_RootGroup.UpdateScrollBounds(xScroll, yScroll, false); // Move Items but not controls
Rectangle clipBounds = clientRectangle;
WinApi.RECT rectClip = WinApi.RECT.FromXYWH(clipBounds.X, clipBounds.Y, clipBounds.Width, clipBounds.Height);
WinApi.RECT prcUpdate = WinApi.RECT.FromXYWH(clipBounds.X, clipBounds.Y, clipBounds.Width, clipBounds.Height);
WinApi.RECT rectScroll = WinApi.RECT.FromXYWH(displayRect.X, displayRect.Y, displayRect.Width, displayRect.Height);
WinApi.ScrollWindowEx(new System.Runtime.InteropServices.HandleRef(this, this.Handle),
xScroll,
yScroll,
ref rectScroll,
ref rectClip,
IntPtr.Zero,
ref prcUpdate,
7);
if (_HScrollBar.Visible)
{
_HScrollBar.Location = new Point(this.ClientRectangle.X, this.ClientRectangle.Bottom - _HScrollBar.Height);
_HScrollBar.BringToFront();
_HScrollBar.Refresh();
}
if (_VScrollBar.Visible)
{
_VScrollBar.Location = new Point(this.ClientRectangle.Right - _VScrollBar.Width, this.ClientRectangle.Y);
_VScrollBar.BringToFront();
_VScrollBar.Refresh();
}
Type t = typeof(Control);
System.Reflection.MethodInfo mi = t.GetMethod("UpdateBounds", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, System.Type.DefaultBinder, new Type[0], new System.Reflection.ParameterModifier[0]);
if (mi != null)
{
for (int i = 0; i < base.Controls.Count; i++)
{
Control control = base.Controls[i];
if ((control != null) && control.IsHandleCreated && control != _VScrollBar && control != _HScrollBar)
{
mi.Invoke(control, null); //control.UpdateBounds();
}
}
}
this.Refresh();
}
else
{
WinApi.SendMessage(this.Handle, WinApi.WM_SETREDRAW, 0, 0);
_RootGroup.UpdateScrollBounds(xScroll, yScroll, true);
WinApi.SendMessage(this.Handle, WinApi.WM_SETREDRAW, 1, 0);
this.Refresh();
}
DateTime end = DateTime.Now;
//Console.WriteLine("ScrollTime:{0}", end.Subtract(start).TotalMilliseconds);
}
}
/// <summary>
/// Padding property is not supported by LayoutControl.
/// </summary>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Never)]
public new System.Windows.Forms.Padding Padding
{
get
{
return base.Padding;
}
set
{
}
}
private bool _AutoScaleLayout = true;
/// <summary>
/// Indicates whether layout control automatically scales the items if the parent Form performs scaling due to AutoScale settings.
/// </summary>
[DefaultValue(true), Category("Behavior"), Description("Indicates whether layout control automatically scales the items if the parent Form performs scaling due to AutoScale settings.")]
public bool AutoScaleLayout
{
get { return _AutoScaleLayout; }
set
{
_AutoScaleLayout = value;
}
}
protected virtual void ScaleItems(LayoutGroup group, SizeF factor)
{
foreach (LayoutItemBase item in group.Items)
{
item.ScaleItem(factor);
if (item is LayoutGroup)
ScaleItems((LayoutGroup)item, factor);
}
}
protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
{
//Console.WriteLine("ScaleControl factor={0} boundsSpecified={1}", factor, specified);
if (_AutoScaleLayout && (factor.Width != 1f || factor.Height != 1f))
{
this.SuspendLayout();
try
{
ScaleItems(_RootGroup, factor);
}
finally
{
ResumeLayout();
}
}
base.ScaleControl(factor, specified);
}
protected override void ScaleCore(float dx, float dy)
{
//Console.WriteLine("ScaleCore dx={0} dy={1}", dx, dy);
base.ScaleCore(dx, dy);
}
private SimpleStyle _FocusStyle = null;
/// <summary>
/// Indicates the focus style applied to the item which hosts an Control when that control contains input focus.
/// </summary>
[Category("Appearance"), Description("Indicates the focus style applied to the item which hosts an Control when that control contains input focus."), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public SimpleStyle FocusStyle
{
get { return _FocusStyle; }
internal set
{
if (value != _FocusStyle)
{
SimpleStyle oldValue = _FocusStyle;
_FocusStyle = value;
OnFocusStyleChanged(oldValue, value);
}
}
}
/// <summary>
/// Called when FocusStyle property has changed.
/// </summary>
/// <param name="oldValue">Old property value</param>
/// <param name="newValue">New property value</param>
protected virtual void OnFocusStyleChanged(SimpleStyle oldValue, SimpleStyle newValue)
{
if (oldValue != null)
oldValue.PropertyChanged -= FocusStylePropertyChanged;
if (newValue != null)
newValue.PropertyChanged += FocusStylePropertyChanged;
//OnPropertyChanged(new PropertyChangedEventArgs("FocusStyle"));
}
private void FocusStylePropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.Invalidate();
}
/// <summary>
/// Gets the vertical scrollbar used by control.
/// </summary>
[Browsable(false)]
public VScrollBarAdv VScrollBar
{
get
{
return _VScrollBar;
}
}
/// <summary>
/// Gets the horizontal scrollbar used by the control.
/// </summary>
[Browsable(false)]
public DevComponents.DotNetBar.ScrollBar.HScrollBarAdv HScrollBar
{
get
{
return _HScrollBar;
}
}
/// <summary>
/// Finds the item which is responsible for the control or returns null if there is no item that represents the control or control is not
/// contained by the layout control.
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
public LayoutItemBase FindControlItem(Control c)
{
if (c == null || c.Parent != this) return null;
return FindControlItem(_RootGroup, c);
}
private LayoutItemBase FindControlItem(LayoutGroup group, Control c)
{
foreach (LayoutItemBase item in group.Items)
{
if (item is LayoutControlItem && ((LayoutControlItem)item).Control == c)
return item;
LayoutGroup childGroup = item as LayoutGroup;
if (childGroup != null)
{
LayoutItemBase childItem = FindControlItem(childGroup, c);
if (childItem != null) return childItem;
}
}
return null;
}
/// <summary>
/// Finds the layout items which have controls assigned but controls are not parented by the layout control or one of its child controls.
/// </summary>
/// <returns></returns>
public List<LayoutItemBase> FindOrphanedControlItems()
{
List<LayoutItemBase> list = new List<LayoutItemBase>();
FindOrphanedControlItems(list, _RootGroup);
return list;
}
private void FindOrphanedControlItems(List<LayoutItemBase> list, LayoutGroup group)
{
foreach (LayoutItemBase item in group.Items)
{
if (item is LayoutControlItem && !IsChildControl(((LayoutControlItem)item).Control))
list.Add(item);
else
{
LayoutGroup childGroup = item as LayoutGroup;
if (childGroup != null)
FindOrphanedControlItems(list, childGroup);
}
}
}
private bool IsChildControl(Control control)
{
if (control == null) return true;
do
{
if (control.Parent == this) return true;
control = control.Parent;
} while (control != null && control.Parent != null);
return false;
}
/// <summary>
/// Returns whether control is an system control used internally by LayoutControl.
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
public bool IsSystemControl(Control c)
{
return c == _VScrollBar || c == _HScrollBar || c == _InsertMarker || c == _Thumb;
}
private bool _DisposeControlsOnRootGroupClear = true;
/// <summary>
/// Indicates whether controls associated with layout items are automatically disposed when RootGroup.Clear method is called. Default value is true.
/// </summary>
[DefaultValue(true), Category("Behavior"), Description("Indicates whether controls are automatically disposed when RootGroup.Clear method is called.")]
public bool DisposeControlsOnRootGroupClear
{
get { return _DisposeControlsOnRootGroupClear; }
set
{
_DisposeControlsOnRootGroupClear = value;
}
}
private LayoutItemBase _MouseOverItem = null;
protected override void OnMouseMove(MouseEventArgs e)
{
if (_MouseOverItem != null && _MouseOverItem.Bounds.Contains(e.Location))
{
_MouseOverItem.OnMouseMove(this, e);
}
else
{
LayoutItemBase item = HitTest(e.Location);
if (item != _MouseOverItem)
{
if (_MouseOverItem != null)
_MouseOverItem.OnMouseLeave(this, e);
_MouseOverItem = item;
if (_MouseOverItem != null)
{
_MouseOverItem.OnMouseEnter(this, e);
_MouseOverItem.OnMouseMove(this, e);
}
}
}
base.OnMouseMove(e);
}
protected override void OnMouseLeave(EventArgs e)
{
if (_MouseOverItem != null)
{
_MouseOverItem.OnMouseLeave(this, e);
_MouseOverItem = null;
}
base.OnMouseLeave(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (_MouseOverItem != null)
_MouseOverItem.OnMouseDown(this, e);
base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (_MouseOverItem != null)
_MouseOverItem.OnMouseUp(this, e);
base.OnMouseUp(e);
}
protected override void OnClick(EventArgs e)
{
if (_MouseOverItem != null)
_MouseOverItem.OnClick(this, e);
base.OnClick(e);
}
protected override void OnMouseHover(EventArgs e)
{
if (_MouseOverItem != null)
_MouseOverItem.OnMouseHover(this, e);
base.OnMouseHover(e);
}
private bool _ShowToolTips = true;
/// <summary>
/// Gets or sets whether tooltips are shown when mouse is over the item when Tooltip property is set.
/// </summary>
[DefaultValue(true), Category("Behavior"), Description("Indicates whether tooltips are shown when mouse is over the item when Tooltip property is set.")]
public bool ShowToolTips
{
get { return _ShowToolTips; }
set
{
_ShowToolTips = value;
}
}
/// <summary>
/// Gets the layout item at specified location.
/// </summary>
/// <param name="clientLoc">LayoutControl client coordinates to test.</param>
/// <returns>Layout item or null.</returns>
public LayoutItemBase HitTest(Point clientLoc)
{
return HitTest(_RootGroup, clientLoc);
}
private LayoutItemBase HitTest(LayoutGroup group, Point clientLoc)
{
foreach (LayoutItemBase item in group.Items)
{
LayoutGroup childGroup = item as LayoutGroup;
if (childGroup != null)
{
LayoutItemBase childItem = HitTest(childGroup, clientLoc);
if (childItem != null) return childItem;
}
if (item.Bounds.Contains(clientLoc))
return item;
}
return null;
}
private bool IsContainedBy(LayoutItemBase item, LayoutItemBase parent)
{
if (parent == null || item == null) return false;
do
{
if (item.Parent == parent)
return true;
item = item.Parent;
} while (item != null);
return false;
}
/// <summary>
/// Gets the HitTestInsertInfo structure that provides information on insertion point for an item based on the
/// specified client coordinates.
/// </summary>
/// <param name="clientLoc">Client coordinates to determine insert location for.</param>
/// <returns>Instance of HitTestInsertInfo or null if item cannot be placed.</returns>
public HitTestInsertInfo GetHitTestInsertInfo(LayoutItemBase insertItem, Point clientLoc)
{
HitTestInsertInfo insertInfo = new HitTestInsertInfo();
insertInfo.Parent = _RootGroup;
LayoutItemBase item = HitTestInsert(_RootGroup, clientLoc);
if (item != null)
{
if (IsContainedBy(item, insertItem) || insertItem.IsChildItem(item))
return new HitTestInsertInfo();
else if (item is LayoutGroup && item != _RootGroup && item != insertItem)
{
insertInfo.Parent = (LayoutGroup)item;
if (insertInfo.Parent.Items.Count == 0)
{
insertInfo.InsertIndex = 0;
insertInfo.InsertMarkerBounds = new Rectangle(item.Bounds.X, item.Bounds.Y, 1, item.Bounds.Height);
}
else
{
LayoutItemBase lastItem = insertInfo.Parent.Items[insertInfo.Parent.Items.Count - 1];
insertInfo.InsertIndex = insertInfo.Parent.Items.Count;
insertInfo.InsertMarkerBounds = new Rectangle(lastItem.Bounds.Right, lastItem.Bounds.Y, 1, lastItem.Bounds.Height);
}
}
else
{
insertInfo.Parent = (LayoutGroup)item.Parent;
if (clientLoc.X < item.Bounds.X + item.Bounds.Width / 2)
{
insertInfo.InsertIndex = insertInfo.Parent.Items.IndexOf(item);
insertInfo.InsertMarkerBounds = new Rectangle(item.Bounds.X, item.Bounds.Y, 1, item.Bounds.Height);
}
else
{
insertInfo.InsertIndex = insertInfo.Parent.Items.IndexOf(item) + 1;
insertInfo.InsertMarkerBounds = new Rectangle(item.Bounds.Right, item.Bounds.Y, 1, item.Bounds.Height);
}
}
}
else
{
if (_RootGroup.Items.Count == 0)
insertInfo.InsertMarkerBounds = new Rectangle(_RootGroup.Bounds.X, _RootGroup.Bounds.Y, 1, insertItem.Bounds.Height);
else
{
insertInfo.InsertIndex = _RootGroup.Items.Count;
LayoutItemBase lastItem = _RootGroup.Items[_RootGroup.Items.Count - 1];
insertInfo.InsertMarkerBounds = new Rectangle(lastItem.Bounds.Right, lastItem.Bounds.Y, 1, lastItem.Bounds.Height);
}
}
return insertInfo;
}
/// <summary>
/// Returns item which contains specified client point or null.
/// </summary>
/// <param name="clientLoc">Client location to test.</param>
/// <returns></returns>
private LayoutItemBase HitTestInsert(LayoutGroup group, Point clientLoc)
{
LayoutItemBase relItem = null;
foreach (LayoutItemBase item in group.Items)
{
LayoutGroup childGroup = item as LayoutGroup;
if (childGroup != null)
{
relItem = HitTestInsert(childGroup, clientLoc);
if (relItem != null)
return relItem;
}
if (item.Bounds.Contains(clientLoc))
return item;
if (group.IsRootGroup && clientLoc.Y >= item.Bounds.Y && clientLoc.Y <= item.Bounds.Bottom)
{
if (item.Bounds.X < clientLoc.X || clientLoc.X > item.Bounds.Right)
relItem = item;
}
}
return relItem;
}
public void HideInsertMarker()
{
_InsertMarker.Visible = false;
}
public void ShowInsertMarker(Rectangle r)
{
if (r.Width < 6) r.Width = 6;
_InsertMarker.Bounds = r;
if (!_InsertMarker.Visible)
_InsertMarker.Visible = true;
_InsertMarker.BringToFront();
}
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new Size AutoScrollMargin
{
get
{
return base.AutoScrollMargin;
}
set
{
}
}
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new Size AutoScrollMinSize
{
get
{
return base.AutoScrollMinSize;
}
set { }
}
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override bool AutoScroll
{
get
{
return base.AutoScroll;
}
set
{
//base.AutoScroll = value;
}
}
[Browsable(false)]
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
}
}
protected override Size DefaultSize
{
get
{
return new Size(200, 200);
}
}
#region Touch Handling
private DevComponents.DotNetBar.Touch.TouchHandler _TouchHandler = null;
private bool _TouchEnabled = true;
/// <summary>
/// Indicates whether touch support for scrolling is enabled.
/// </summary>
[DefaultValue(true), Category("Behavior"), Description("Indicates whether touch support for scrolling is enabled.")]
public bool TouchEnabled
{
get { return _TouchEnabled; }
set
{
if (value != _TouchEnabled)
{
bool oldValue = _TouchEnabled;
_TouchEnabled = value;
OnTouchEnabledChanged(oldValue, value);
}
}
}
/// <summary>
/// Called when TouchEnabled property has changed.
/// </summary>
/// <param name="oldValue">Old property value</param>
/// <param name="newValue">New property value</param>
protected virtual void OnTouchEnabledChanged(bool oldValue, bool newValue)
{
//OnPropertyChanged(new PropertyChangedEventArgs("TouchEnabled"));
}
private int TriggerPageChangeOffset
{
get
{
return 32;
}
}
private int MaximumReversePageOffset
{
get
{
return 0; //Math.Min(32, this.Width / 6);
}
}
private bool _TouchDrag = false;
private Point _TouchStartLocation = Point.Empty;
private Point _TouchStartScrollPosition = Point.Empty;
private Rectangle _TouchInnerBounds = Rectangle.Empty;
private void TouchHandlerPanBegin(object sender, DevComponents.DotNetBar.Touch.GestureEventArgs e)
{
if (_TouchEnabled)
{
_TouchInnerBounds = GetLayoutBounds();
_TouchStartLocation = e.Location;
_TouchStartScrollPosition = _ScrollPosition;
_TouchDrag = true;
e.Handled = true;
}
}
private void TouchHandlerPanEnd(object sender, DevComponents.DotNetBar.Touch.GestureEventArgs e)
{
if (_TouchDrag)
{
EndTouchPan();
e.Handled = true;
}
}
private void EndTouchPan()
{
_TouchDrag = false;
Point autoScrollPosition = _ScrollPosition;
Size autoScrollMinSize = GetAutoScrollMinSize();
if (autoScrollMinSize.Width > 0)
{
if (autoScrollMinSize.Width < -autoScrollPosition.X)
autoScrollPosition = new Point(autoScrollMinSize.Width, autoScrollPosition.Y);
else if (-autoScrollPosition.X < 0)
autoScrollPosition = new Point(0, autoScrollPosition.Y);
}
if (autoScrollMinSize.Height > 0)
{
if (autoScrollMinSize.Height < -autoScrollPosition.Y)
autoScrollPosition = new Point(autoScrollPosition.X, autoScrollMinSize.Height);
else if (-autoScrollPosition.Y < 0)
autoScrollPosition = new Point(autoScrollPosition.X, 0);
}
ScrollControls(autoScrollPosition);
UpdateScrollbarsFromScrollPosition();
}
private void TouchHandlerPan(object sender, DevComponents.DotNetBar.Touch.GestureEventArgs e)
{
if (_TouchDrag)
{
Point autoScrollPosition = _ScrollPosition;
Size autoScrollMinSize = GetAutoScrollMinSize();
int offset = (e.Location.X - _TouchStartLocation.X);
int offsetChange = offset + _TouchStartScrollPosition.X;
bool overflowH = false;
if (autoScrollMinSize.Width > 0)
{
if (-offsetChange + MaximumReversePageOffset > autoScrollMinSize.Width)
{
autoScrollPosition.X = -(autoScrollMinSize.Width + MaximumReversePageOffset);
overflowH = true;
}
else if (offsetChange > MaximumReversePageOffset)
{
autoScrollPosition.X = MaximumReversePageOffset;
overflowH = true;
}
else
autoScrollPosition.X = offsetChange;
}
// Y Scroll
bool overflowV = false;
if (autoScrollMinSize.Height > 0)
{
offset = (e.Location.Y - _TouchStartLocation.Y);
offsetChange = offset + _TouchStartScrollPosition.Y;
if (-offsetChange + MaximumReversePageOffset > autoScrollMinSize.Height)
{
autoScrollPosition.Y = -(autoScrollMinSize.Height + MaximumReversePageOffset);
overflowV = true;
}
else if (offsetChange > MaximumReversePageOffset)
{
autoScrollPosition.Y = MaximumReversePageOffset;
overflowV = true;
}
else
autoScrollPosition.Y = offsetChange;
}
if (_ScrollPosition != autoScrollPosition)
{
ScrollControls(autoScrollPosition);
Update();
}
if (overflowH && overflowV && e.IsInertia) EndTouchPan();
UpdateScrollbarsFromScrollPosition();
e.Handled = true;
}
}
private void UpdateScrollbarsFromScrollPosition()
{
if (_VScrollBar != null && _VScrollBar.Visible && _VScrollBar.Value != -_ScrollPosition.Y)
_VScrollBar.Value = Math.Min(_VScrollBar.Maximum, Math.Max(0, -_ScrollPosition.Y));
if (_HScrollBar != null && _HScrollBar.Visible && _HScrollBar.Value != -_ScrollPosition.X)
_HScrollBar.Value = Math.Min(_HScrollBar.Maximum, Math.Max(0, -_ScrollPosition.X));
}
#endregion
}
#region HitTestInsertInfo
public class HitTestInsertInfo
{
public LayoutGroup Parent = null;
public int InsertIndex = -1;
public Rectangle InsertMarkerBounds = Rectangle.Empty;
}
#endregion
#region EmptyLayoutManager
internal class EmptyLayoutManager : LayoutEngine
{
public override void InitLayout(object child, BoundsSpecified specified)
{
}
public override bool Layout(object container, LayoutEventArgs layoutEventArgs)
{
return true;
}
}
#endregion
}