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
    {
        /// 
        /// Initializes a new instance of the LayoutControl class.
        /// 
        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(TouchHandlerPanBegin);
                _TouchHandler.Pan += new EventHandler(TouchHandlerPan);
                _TouchHandler.PanEnd += new EventHandler(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;
        }
        /// 
        /// 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.
        /// 
        /// New active style.
        [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);
        }
        /// 
        /// Brings specified item that belongs to this LayoutControl into view by scrolling control if necessary.
        /// 
        /// Item to bring into view.
        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();
        /// 
        /// Gets the LayoutGroup for the control. LayoutGroup should not be changed.
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Browsable(false)]
        public LayoutGroup RootGroup
        {
            get { return _RootGroup; }
            set
            {
                if (value != _RootGroup)
                {
                    LayoutGroup oldValue = _RootGroup;
                    _RootGroup = value;
                    OnRootGroupChanged(oldValue, value);
                }
            }
        }
        /// 
        /// Called when RootGroup property has changed.
        /// 
        /// Old property value
        /// New property value
        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;
        /// 
        /// Indicates font used for the item labels.
        /// 
        [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);
                }
            }
        }
        /// 
        /// Called when LabelFont property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnLabelFontChanged(Font oldValue, Font newValue)
        {
            //OnPropertyChanged(new PropertyChangedEventArgs("LabelFont"));
            this.PerformLayout();
            this.Invalidate();
        }
        private Color _LabelTextColor = Color.Empty;
        /// 
        /// Gets or sets the color of the label text.
        /// 
        [Category("Appearance"), Description("Indicates color of label text.")]
        public Color LabelTextColor
        {
            get { return _LabelTextColor; }
            set { _LabelTextColor = value; /*OnPropertyChanged("LabelTextColor");*/ this.Invalidate(); }
        }
        /// 
        /// Gets whether property should be serialized.
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeLabelTextColor()
        {
            return !_LabelTextColor.IsEmpty;
        }
        /// 
        /// Resets property to its default value.
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public void ResetLabelTextColor()
        {
            this.LabelTextColor = Color.Empty;
        }
        private eTextAlignment _LabelTextAlignment = eTextAlignment.Default;
        /// 
        /// Indicates the label text alignment within the text bounds.
        /// 
        [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);
                }
            }
        }
        /// 
        /// Called when LabelTextAlignment property has changed.
        /// 
        /// Old property value
        /// New property value
        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;
            }
        }
        /// 
        /// Sets default property values for LayoutControlItem given the control assigned to it.
        /// 
        /// Reference to LayoutControlItem
        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;
        /// 
        /// Indicates whether accelerator keys assigned to item Text property are processed by items which respond to them.
        /// 
        [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);
                }
            }
        }
        /// 
        /// Called when MnemonicsEnabled property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnMnemonicsEnabledChanged(bool oldValue, bool newValue)
        {
            //OnPropertyChanged(new PropertyChangedEventArgs("MnemonicsEnabled"));
        }
        private System.Drawing.Text.HotkeyPrefix _HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show;
        /// 
        /// Indicates visibility of the hot-key prefixes, accelerator keys, that are set using ampersand in item Text.
        /// 
        [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);
                }
            }
        }
        /// 
        /// Called when HotkeyPrefix property has changed.
        /// 
        /// Old property value
        /// New property value
        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);
            }
        }
        /// 
        /// Padding property is not supported by LayoutControl.
        /// 
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Never)]
        public new System.Windows.Forms.Padding Padding
        {
            get
            {
                return base.Padding;
            }
            set
            {
            }
        }
        private bool _AutoScaleLayout = true;
        /// 
        /// Indicates whether layout control automatically scales the items if the parent Form performs scaling due to AutoScale settings.
        /// 
        [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;
        /// 
        /// Indicates the focus style applied to the item which hosts an Control when that control contains input focus.
        /// 
        [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);
                }
            }
        }
        /// 
        /// Called when FocusStyle property has changed.
        /// 
        /// Old property value
        /// New property value
        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();
        }
        /// 
        /// Gets the vertical scrollbar used by control.
        /// 
        [Browsable(false)]
        public VScrollBarAdv VScrollBar
        {
            get
            {
                return _VScrollBar;
            }
        }
        /// 
        /// Gets the horizontal scrollbar used by the control.
        /// 
        [Browsable(false)]
        public DevComponents.DotNetBar.ScrollBar.HScrollBarAdv HScrollBar
        {
            get
            {
                return _HScrollBar;
            }
        }
        /// 
        /// 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.
        /// 
        /// 
        /// 
        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;
        }
        /// 
        /// Finds the layout items which have controls assigned but controls are not parented by the layout control or one of its child controls.
        /// 
        /// 
        public List FindOrphanedControlItems()
        {
            List list = new List();
            FindOrphanedControlItems(list, _RootGroup);
            return list;
        }
        private void FindOrphanedControlItems(List 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;
        }
        /// 
        /// Returns whether control is an system control used internally by LayoutControl.
        /// 
        /// 
        /// 
        public bool IsSystemControl(Control c)
        {
            return c == _VScrollBar || c == _HScrollBar || c == _InsertMarker || c == _Thumb;
        }
        private bool _DisposeControlsOnRootGroupClear = true;
        /// 
        /// Indicates whether controls associated with layout items are automatically disposed when RootGroup.Clear method is called. Default value is true.
        /// 
        [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;
        /// 
        /// Gets or sets whether tooltips are shown when mouse is over the item when Tooltip property is set.
        /// 
        [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;
            }
        }
        /// 
        /// Gets the layout item at specified location.
        /// 
        /// LayoutControl client coordinates to test.
        /// Layout item or null.
        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;
        }
        /// 
        /// Gets the HitTestInsertInfo structure that provides information on insertion point for an item based on the 
        /// specified client coordinates.
        /// 
        /// Client coordinates to determine insert location for.
        /// Instance of HitTestInsertInfo or null if item cannot be placed.
        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;
        }
        /// 
        /// Returns item which contains specified client point or null.
        /// 
        /// Client location to test.
        /// 
        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;
        /// 
        /// Indicates whether touch support for scrolling is enabled.
        /// 
        [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);
                }
            }
        }
        /// 
        /// Called when TouchEnabled property has changed.
        /// 
        /// Old property value
        /// New property value
        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
}