using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.ComponentModel; using System.Drawing; using DevComponents.DotNetBar.ScrollBar; namespace DevComponents.DotNetBar.Controls { [ToolboxItem(true), Description("Page Slider Control with Touch Support")] [Designer("DevComponents.DotNetBar.Design.PageSliderDesigner, DevComponents.DotNetBar.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf")] [DefaultEvent("SelectedPageChanged"), DefaultProperty("SelectedPageIndex")] [ToolboxBitmap(typeof(StepIndicator), "Controls.PageSlider.ico")] public class PageSlider : Control { #region Constructor private StepIndicator _StepIndicator; private Touch.TouchHandler _TouchHandler = null; private HScrollBarAdv _HorizontalScrollBar = null; private VScrollBarAdv _VerticalScrollBar = null; /// /// Initializes a new instance of the PageSlider class. /// public PageSlider() { _StepIndicator = new StepIndicator(); _StepIndicator.Dock = DockStyle.Top; this.Controls.Add(_StepIndicator); if (BarFunctions.IsWindows7 && Touch.TouchHandler.IsTouchEnabled) { _TouchHandler = new DevComponents.DotNetBar.Touch.TouchHandler(this); _TouchHandler.PanBegin += new EventHandler(TouchHandlerPanBegin); _TouchHandler.Pan += new EventHandler(TouchHandlerPan); _TouchHandler.PanEnd += new EventHandler(TouchHandlerPanEnd); } _HorizontalScrollBar = new HScrollBarAdv(); _HorizontalScrollBar.Dock = DockStyle.Bottom; _HorizontalScrollBar.Height = 12; _HorizontalScrollBar.Scroll += new ScrollEventHandler(ScrollBarScroll); _HorizontalScrollBar.Visible = false; this.Controls.Add(_HorizontalScrollBar); _VerticalScrollBar = new VScrollBarAdv(); _VerticalScrollBar.Dock = DockStyle.Right; _VerticalScrollBar.Width = 12; _VerticalScrollBar.Scroll += new ScrollEventHandler(ScrollBarScroll); _VerticalScrollBar.Visible = false; this.Controls.Add(_VerticalScrollBar); } protected override void Dispose(bool disposing) { StopScrollBarTimer(); _HorizontalScrollBar.Scroll -= new ScrollEventHandler(ScrollBarScroll); _VerticalScrollBar.Scroll -= new ScrollEventHandler(ScrollBarScroll); _HorizontalScrollBar.Dispose(); _VerticalScrollBar.Dispose(); _VerticalScrollBar = null; _HorizontalScrollBar = null; if (_TouchHandler != null) { _TouchHandler.PanBegin -= new EventHandler(TouchHandlerPanBegin); _TouchHandler.Pan -= new EventHandler(TouchHandlerPan); _TouchHandler.PanEnd -= new EventHandler(TouchHandlerPanEnd); _TouchHandler.Release(); } base.Dispose(disposing); } #endregion #region Events /// /// Occurs when selected page has changed. /// [Description("Occurs when selected page has changed.")] public event EventHandler SelectedPageChanged; /// /// Raises SelectedPageChanged event. /// /// Provides event arguments. protected virtual void OnSelectedPageChanged(EventArgs e) { EventHandler handler = SelectedPageChanged; if (handler != null) handler(this, e); } #endregion #region Implementation protected override void ScaleControl(SizeF factor, BoundsSpecified specified) { if (Dpi.RecordScalePerControl) Dpi.SetScaling(factor); //_StepIndicator.Height = Dpi.Height(_StepIndicator.Height); base.ScaleControl(factor, specified); } protected override Size DefaultSize { get { return new Size(300, 200); } } protected override void OnHandleCreated(EventArgs e) { if (_UpdateScrollBarVisibilityDelayed) { _UpdateScrollBarVisibilityDelayed = false; UpdateScrollBarVisibility(); } UpdateBoundsForAllPages(false); base.OnHandleCreated(e); } protected override void OnHandleDestroyed(EventArgs e) { StopScrollBarTimer(); base.OnHandleDestroyed(e); } private bool _IndicatorVisible = true; /// /// Gets or sets whether current page indicator is visible. Default value is true. /// [DefaultValue(true), Category("Appearance"), Description("Indicates whether current page indicator is visible.")] public bool IndicatorVisible { get { return _IndicatorVisible; } set { if (value != _IndicatorVisible) { bool oldValue = _IndicatorVisible; _IndicatorVisible = value; OnIndicatorVisibleChanged(oldValue, value); } } } /// /// Called when IndicatorVisible property has changed. /// /// Old property value /// New property value protected virtual void OnIndicatorVisibleChanged(bool oldValue, bool newValue) { _StepIndicator.Visible = newValue; } protected override void OnControlAdded(ControlEventArgs e) { if (e.Control is PageSliderPage) { PageSliderPage page = (PageSliderPage)e.Control; UpdatePageTable(); page.Bounds = GetPageBounds(page); UpdateScrollBar(); } base.OnControlAdded(e); } protected override void OnControlRemoved(ControlEventArgs e) { if (e.Control is PageSliderPage) { PageSliderPage page = (PageSliderPage)e.Control; int pageIndex = _PageTable.IndexOf(page); _PageTable.Remove(page); UpdatePageTable(); if (_SelectedPage == page) { if (_PageTable.Count > 0) this.SelectedPage = _PageTable[pageIndex > 0 ? pageIndex-- : 0]; else this.SelectedPage = null; } UpdateScrollBar(); UpdateBoundsForAllPages(false, true); } base.OnControlRemoved(e); } protected override void OnLayout(LayoutEventArgs levent) { base.OnLayout(levent); if (levent.AffectedProperty == "ChildIndex") { UpdatePageTable(); UpdateBoundsForAllPages(true, true); } } private void UpdateBoundsForAllPages(bool updateControl) { UpdateBoundsForAllPages(updateControl, false); } private void UpdateBoundsForAllPages(bool updateControl, bool syncPageIndicator) { Rectangle selectedPageBounds = GetSelectedPageBounds(); int currentPage = -1; for (int i = 0; i < _PageTable.Count; i++) { PageSliderPage page = _PageTable[i]; page.Bounds = GetPageBounds(page); if (updateControl && page.Bounds.IntersectsWith(this.ClientRectangle)) this.Update(); if (syncPageIndicator && !_PageBoundsOffset.IsEmpty && page.Bounds.IntersectsWith(selectedPageBounds) && currentPage == -1) currentPage = i + 1; } if (syncPageIndicator && _PageBoundsOffset.IsEmpty) currentPage = this.SelectedPageIndex + 1; if (syncPageIndicator && currentPage > 0) _StepIndicator.CurrentStep = currentPage; UpdateScrollBar(); } private void UpdateScrollBar() { int selectedPageIndex = this.SelectedPageIndex; Rectangle selectedPageBounds = GetSelectedPageBounds(); Rectangle firstPageBounds = Rectangle.Empty, lastPageBounds = Rectangle.Empty; if (_PageTable.Count > 0) { firstPageBounds = _PageTable[0].Bounds; lastPageBounds = _PageTable[_PageTable.Count - 1].Bounds; } if (_Orientation == eOrientation.Horizontal) { _HorizontalScrollBar.Minimum = 0; _HorizontalScrollBar.Maximum = Math.Max(1, lastPageBounds.Right - firstPageBounds.X + (selectedPageIndex == -1 ? firstPageBounds.X : 0)); _HorizontalScrollBar.LargeChange = Math.Max(1, selectedPageBounds.Width); _HorizontalScrollBar.SmallChange = 32; if (!_IsScrolling && selectedPageIndex != -1) _HorizontalScrollBar.Value = Math.Min(Math.Max(_HorizontalScrollBar.Minimum, Math.Abs(firstPageBounds.X)), _HorizontalScrollBar.Maximum); } else { _VerticalScrollBar.Minimum = 0; _VerticalScrollBar.Maximum = Math.Max(1, lastPageBounds.Bottom - firstPageBounds.Y + (selectedPageIndex == -1 ? firstPageBounds.Y : 0)); _VerticalScrollBar.LargeChange = Math.Max(1, selectedPageBounds.Height); _VerticalScrollBar.SmallChange = 32; if (!_IsScrolling && selectedPageIndex != -1) _VerticalScrollBar.Value = Math.Min(Math.Max(_VerticalScrollBar.Minimum, Math.Abs(firstPageBounds.Y)), _VerticalScrollBar.Maximum); } } private bool _IsScrolling = false; private int _InitialScrollValue = 0; private void ScrollBarScroll(object sender, ScrollEventArgs e) { if (e.Type == ScrollEventType.EndScroll) { _IsScrolling = false; Rectangle selectedPageBounds = GetSelectedPageBounds(); PageSliderPage newSelection = this.SelectedPage; // Find right page to select since control can be scrolled a lot using scroll-bars if (e.NewValue > _InitialScrollValue) { for (int i = _PageTable.Count - 1; i >= 0; i--) { PageSliderPage page = _PageTable[i]; if (page.Bounds.IntersectsWith(selectedPageBounds) && selectedPageBounds.Right - page.Left >= TriggerPageChangeOffset) { newSelection = page; break; } } } else { for (int i = 0; i < _PageTable.Count; i++) { PageSliderPage page = _PageTable[i]; if (page.Bounds.IntersectsWith(selectedPageBounds) && page.Right - selectedPageBounds.X >= TriggerPageChangeOffset) { newSelection = page; break; } } } if (this.SelectedPage != newSelection) { this.SelectedPage = newSelection; if (_Orientation == eOrientation.Horizontal) _HorizontalScrollBar.Value = Math.Abs(_PageTable[0].Left); else _VerticalScrollBar.Value = Math.Abs(_PageTable[0].Top); } else PageBoundsOffset = Point.Empty; } else { if (!_IsScrolling) { if (_Orientation == eOrientation.Horizontal) _InitialScrollValue = _HorizontalScrollBar.Value; else _InitialScrollValue = _VerticalScrollBar.Value; _IsScrolling = true; } if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll) PageBoundsOffset = new Point(_InitialScrollValue - e.NewValue, 0); else PageBoundsOffset = new Point(0, _InitialScrollValue - e.NewValue); } } protected override void OnResize(EventArgs e) { UpdateBoundsForAllPages(false); base.OnResize(e); } private Rectangle GetSelectedPageBounds() { Rectangle selectedPageBounds = DeflateRectangle(this.ClientRectangle, _PagePadding); if (_Orientation == eOrientation.Horizontal) selectedPageBounds.Width -= _PageSpacing + _NextPageVisibleMargin; else selectedPageBounds.Height -= _PageSpacing + _NextPageVisibleMargin; if (_IndicatorVisible) { if (_StepIndicator.Dock == DockStyle.Top) { selectedPageBounds.Y += _StepIndicator.Height; selectedPageBounds.Height -= _StepIndicator.Height; } else if (_StepIndicator.Dock == DockStyle.Bottom) { selectedPageBounds.Height -= _StepIndicator.Height; } else if (_StepIndicator.Dock == DockStyle.Left) { selectedPageBounds.X += _StepIndicator.Width; selectedPageBounds.Width -= _StepIndicator.Width; } else if (_StepIndicator.Dock == DockStyle.Right) { selectedPageBounds.Width -= _StepIndicator.Width; } } if (_ScrollBarVisibility == eScrollBarVisibility.AlwaysVisible) { if (_Orientation == eOrientation.Horizontal) selectedPageBounds.Height -= _HorizontalScrollBar.Height; else selectedPageBounds.Width -= _HorizontalScrollBar.Width; } return selectedPageBounds; } private Point PageBoundsOffset { get { return _PageBoundsOffset; } set { if (_PageBoundsOffset != value) { _PageBoundsOffset = value; UpdateBoundsForAllPages(true, true); } } } private Point _PageBoundsOffset = Point.Empty; private System.Drawing.Rectangle GetPageBounds(PageSliderPage page) { int pageIndex = _PageTable.IndexOf(page); int selectedPageIndex = this.SelectedPageIndex; Rectangle bounds = Rectangle.Empty; Rectangle selectedPageBounds = GetSelectedPageBounds(); if (pageIndex == selectedPageIndex) { bounds = selectedPageBounds; } else if (pageIndex > selectedPageIndex) { bounds = selectedPageBounds; if (_Orientation == eOrientation.Horizontal) bounds.X += (_PageSpacing + bounds.Width) * (pageIndex - selectedPageIndex); else bounds.Y += (_PageSpacing + bounds.Height) * (pageIndex - selectedPageIndex); } else { bounds = selectedPageBounds; if (_Orientation == eOrientation.Horizontal) bounds.X -= (_PageSpacing + bounds.Width) * (selectedPageIndex - pageIndex); else bounds.Y -= (_PageSpacing + bounds.Height) * (selectedPageIndex - pageIndex); } bounds.Offset(_PageBoundsOffset); return bounds; } private Rectangle DeflateRectangle(Rectangle rect, Padding padding) { rect.X += padding.Left; rect.Y += padding.Top; rect.Width -= padding.Horizontal; rect.Height -= padding.Vertical; return rect; } private List _PageTable = new List(); private void UpdatePageTable() { _PageTable.Clear(); foreach (Control control in this.Controls) { PageSliderPage page = control as PageSliderPage; if (page == null) continue; bool appendPage = true; for (int i = 0; i < _PageTable.Count; i++) { if (_PageTable[i].PageNumber > page.PageNumber) { _PageTable.Insert(i, page); appendPage = false; break; } } if (appendPage) _PageTable.Add(page); } _StepIndicator.StepCount = _PageTable.Count; _StepIndicator.CurrentStep = this.SelectedPageIndex + 1; } /// /// Returns array of all pages in control. /// /// Array of pages. public PageSliderPage[] GetAllPages() { return _PageTable.ToArray(); } /// /// Removes and disposes all pages within the control. /// public void RemoveAllPages() { foreach (PageSliderPage page in _PageTable) { page.Visible = false; } while (_PageTable.Count > 0) { PageSliderPage page = _PageTable[0]; this.Controls.Remove(page); page.Dispose(); } } private PageSliderPage _SelectedPage; /// /// Indicates selected page. /// [DefaultValue(null), Category("Appearance"), Description("Indicates selected page.")] public PageSliderPage SelectedPage { get { return _SelectedPage; } set { if (value != _SelectedPage) { PageSliderPage oldValue = _SelectedPage; _SelectedPage = value; OnSelectedPageChanged(oldValue, value); } } } /// /// Called when SelectedPage property has changed. /// /// Old property value /// New property value protected virtual void OnSelectedPageChanged(PageSliderPage oldValue, PageSliderPage newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("SelectedPage")); if (_AnimationTime > 0) AnimatePageTransition(oldValue, newValue); else UpdateBoundsForAllPages(false); //if (newValue != null) //{ // newValue.Bounds = GetPageBounds(newValue); // newValue.BringToFront(); //} UpdateScrollBar(); _StepIndicator.CurrentStep = this.SelectedPageIndex + 1; OnSelectedPageChanged(EventArgs.Empty); } private void AnimatePageTransition(PageSliderPage oldValue, PageSliderPage newValue) { int oldIndex = -1; if (oldValue != null) oldIndex = _PageTable.IndexOf(oldValue); int newIndex = -1; if (newValue != null) newIndex = _PageTable.IndexOf(newValue); if (oldIndex == newIndex) { UpdateBoundsForAllPages(false); _PageBoundsOffset = Point.Empty; return; } int totalOffset = 0; Rectangle selectedPageBounds = GetSelectedPageBounds(); if (_Orientation == eOrientation.Horizontal) { totalOffset = ((oldIndex - newIndex) * (selectedPageBounds.Width + _PageSpacing)) - _PageBoundsOffset.X; } else { totalOffset = ((oldIndex - newIndex) * (selectedPageBounds.Height + _PageSpacing)) - _PageBoundsOffset.Y; } _PageBoundsOffset = Point.Empty; DateTime startingTime = DateTime.Now; int speedFactor = 1; int remainOffset = Math.Abs(totalOffset); int offsetSign = Math.Sign(totalOffset); int animationTimeDuration = _AnimationTime; if (_Orientation == eOrientation.Horizontal && remainOffset < selectedPageBounds.Width * .8 || _Orientation == eOrientation.Vertical && remainOffset < selectedPageBounds.Height * .8) { if (_Orientation == eOrientation.Horizontal) animationTimeDuration *= (remainOffset / selectedPageBounds.Width); else animationTimeDuration *= (remainOffset / selectedPageBounds.Height); animationTimeDuration = Math.Max(animationTimeDuration, 50); } TimeSpan animationTime = new TimeSpan(0, 0, 0, 0, animationTimeDuration); while (remainOffset > 0) { DateTime startPerMove = DateTime.Now; foreach (PageSliderPage page in _PageTable) { Rectangle bounds = page.Bounds; if (_Orientation == eOrientation.Horizontal) bounds.Offset(speedFactor * offsetSign, 0); else bounds.Offset(0, speedFactor * offsetSign); page.Bounds = bounds; if (bounds.IntersectsWith(this.ClientRectangle)) this.Update(); } remainOffset -= speedFactor; TimeSpan elapsedPerMove = DateTime.Now - startPerMove; TimeSpan elapsedTime = DateTime.Now - startingTime; if ((animationTime - elapsedTime).TotalMilliseconds <= 0) speedFactor = remainOffset; else { if ((int)(animationTime - elapsedTime).TotalMilliseconds == 0) speedFactor = 1; else speedFactor = remainOffset * (int)elapsedPerMove.TotalMilliseconds / Math.Max(1, (int)((animationTime - elapsedTime).TotalMilliseconds)); } if (speedFactor > remainOffset) speedFactor = remainOffset; } } private int _AnimationTime = 250; /// /// Indicates the animation time in milliseconds for operations that perform visual animation of transition. Set to zero to disable animation. /// [DefaultValue(250), Category("Behavior"), Description("Indicates the animation time in milliseconds for operations that perform visual animation of transition. Set to zero to disable animation.")] public int AnimationTime { get { return _AnimationTime; } set { if (value != _AnimationTime) { int oldValue = _AnimationTime; _AnimationTime = value; OnAnimationTimeChanged(oldValue, value); } } } /// /// Called when AnimationTime property has changed. /// /// Old property value /// New property value protected virtual void OnAnimationTimeChanged(int oldValue, int newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("AnimationTime")); } /// /// Gets or sets zero based selected page index. If there is no page selected returns -1. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int SelectedPageIndex { get { return _SelectedPage != null ? _PageTable.IndexOf(_SelectedPage) : -1; } set { if (value < 0 || value >= _PageTable.Count) throw new ArgumentOutOfRangeException("SelectedPageIndex must be greater or equal than 0 and less or equal than number of pages added to control."); this.SelectedPage = _PageTable[value]; } } private int _PageCount; /// /// Gets the total number of pages displayed by the control. /// [Browsable(false)] public int PageCount { get { return _PageTable.Count; } } private Padding _PagePadding = new Padding(4); /// /// Gets or sets the single page padding. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Padding PagePadding { get { return _PagePadding; } set { if (value != _PagePadding) { Padding oldValue = _PagePadding; _PagePadding = value; OnPagePaddingChanged(oldValue, value); } } } /// /// Called when SelectedPagePadding property has changed. /// /// Old property value /// New property value protected virtual void OnPagePaddingChanged(Padding oldValue, Padding newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("SelectedPagePadding")); UpdateBoundsForAllPages(false); } private const int DefaultPageSpacing = 48; private int _PageSpacing = DefaultPageSpacing; /// /// Gets or sets the spacing in pixels between pages. /// [DefaultValue(DefaultPageSpacing), Category("Appearance"), Description("Indicates spacing in pixels between pages.")] public int PageSpacing { get { return _PageSpacing; } set { if (value != _PageSpacing) { int oldValue = _PageSpacing; _PageSpacing = value; OnPageSpacingChanged(oldValue, value); } } } /// /// Called when PageSpacing property has changed. /// /// Old property value /// New property value protected virtual void OnPageSpacingChanged(int oldValue, int newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("PageSpacing")); UpdateBoundsForAllPages(false); } private const int DefaultNextPageVisibleMargin = 50; private int _NextPageVisibleMargin = DefaultNextPageVisibleMargin; [DefaultValue(DefaultNextPageVisibleMargin)] public int NextPageVisibleMargin { get { return _NextPageVisibleMargin; } set { if (value != _NextPageVisibleMargin) { int oldValue = _NextPageVisibleMargin; _NextPageVisibleMargin = value; OnNextPageVisibleMarginChanged(oldValue, value); } } } /// /// Called when NextPageVisibleMargin property has changed. /// /// Old property value /// New property value protected virtual void OnNextPageVisibleMarginChanged(int oldValue, int newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("NextPageVisibleMargin")); UpdateBoundsForAllPages(false); } private eOrientation _Orientation = eOrientation.Horizontal; /// /// Gets or sets the page layout orientation. Default is horizontal. /// [DefaultValue(eOrientation.Horizontal), Category("Appearance"), Description("Indicates page layout orientation.")] public eOrientation Orientation { get { return _Orientation; } set { if (value != _Orientation) { eOrientation oldValue = _Orientation; _Orientation = value; OnOrientationChanged(oldValue, value); } } } /// /// Called when Orientation property has changed. /// /// Old property value /// New property value protected virtual void OnOrientationChanged(eOrientation oldValue, eOrientation newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("Orientation")); UpdateBoundsForAllPages(false); } protected override void WndProc(ref Message m) { if (m.Msg == (int)WinApi.WindowsMessages.WM_APPCOMMAND) { int cmd = WinApi.GetAppCommandLParam(m.LParam); if (cmd == (int)WinApi.AppCommands.APPCOMMAND_BROWSER_BACKWARD) { if (this.SelectedPageIndex > 0) this.SelectedPageIndex--; m.Result = new IntPtr(1); } else if (cmd == (int)WinApi.AppCommands.APPCOMMAND_BROWSER_FORWARD) { if (this.SelectedPageIndex < _PageTable.Count - 1) this.SelectedPageIndex++; m.Result = new IntPtr(1); } } base.WndProc(ref m); } private bool _MouseDrag = false; protected override void OnMouseDown(MouseEventArgs e) { if (e.Button == MouseButtons.Left && _TouchHandler == null && _PageTable.Count > 0 && _MouseDragEnabled) { _MouseDrag = true; _TouchStartLocation = e.Location; } base.OnMouseDown(e); } private bool _PageMouseDragEnabled = true; /// /// Indicates whether page can be dragged using mouse to change currently selected page /// [DefaultValue(true), Category("Behavior"), Description("Indicates whether page can be dragged using mouse to change currently selected page")] public bool PageMouseDragEnabled { get { return _PageMouseDragEnabled; } set { _PageMouseDragEnabled = value; } } private bool _MouseDragEnabled = true; /// /// Indicates whether selected page can be changed by using mouse drag on PageSlider client area which is not covered by pages. /// [DefaultValue(true), Category("Behavior"), Description("Indicates whether selected page can be changed by using mouse drag on PageSlider client area which is not covered by pages.")] public bool MouseDragEnabled { get { return _MouseDragEnabled; } set { _MouseDragEnabled = value; } } internal void StartPageDrag() { if (_PageMouseDragEnabled && !_MouseDrag && Control.MouseButtons == MouseButtons.Left && _TouchHandler == null && _PageTable.Count > 0) { this.Capture = true; _MouseDrag = true; _TouchStartLocation = this.PointToClient(Control.MousePosition); } } private int MaximumReversePageOffset { get { return Math.Min(32, this.Width / 6); } } private int TriggerPageChangeOffset { get { return Math.Max(32, this.Width / 5); } } protected override void OnMouseMove(MouseEventArgs e) { if (_ScrollBarVisibility == eScrollBarVisibility.AutoVisible && !_HorizontalScrollBar.Visible && !_VerticalScrollBar.Visible) StartScrollBarTimer(); if (_MouseDrag) { Rectangle selectedPageBounds = GetSelectedPageBounds(); if (_Orientation == eOrientation.Horizontal) { int offset = e.Location.X - _TouchStartLocation.X; int offsetChange = offset - _PageBoundsOffset.X; Rectangle firstPageBounds = GetPageBounds(_PageTable[0]); if (_PageTable[0].Left + offsetChange > selectedPageBounds.X + MaximumReversePageOffset && SelectedPageIndex >= 0) { offset -= (_PageTable[0].Left + offsetChange) - (selectedPageBounds.X + MaximumReversePageOffset); } else if (_PageTable[_PageTable.Count - 1].Left + offsetChange < selectedPageBounds.X - MaximumReversePageOffset) { offset += (selectedPageBounds.X - MaximumReversePageOffset) - (_PageTable[_PageTable.Count - 1].Left + offsetChange); } PageBoundsOffset = new Point(offset, 0); } else { int offset = e.Location.Y - _TouchStartLocation.Y; int offsetChange = offset - _PageBoundsOffset.Y; Rectangle firstPageBounds = GetPageBounds(_PageTable[0]); if (_PageTable[0].Top + offsetChange > selectedPageBounds.Y + MaximumReversePageOffset && SelectedPageIndex >= 0) { offset -= (_PageTable[0].Top + offsetChange) - (selectedPageBounds.Y + MaximumReversePageOffset); } else if (_PageTable[_PageTable.Count - 1].Top + offsetChange < selectedPageBounds.Y - MaximumReversePageOffset) { offset += (selectedPageBounds.Y - MaximumReversePageOffset) - (_PageTable[_PageTable.Count - 1].Top + offsetChange); } PageBoundsOffset = new Point(0, offset); } } base.OnMouseMove(e); } protected override void OnMouseUp(MouseEventArgs e) { if (_MouseDrag) { _MouseDrag = false; int totalMoveOffset = _Orientation == eOrientation.Horizontal ? _PageBoundsOffset.X : _PageBoundsOffset.Y; if (Math.Abs(totalMoveOffset) >= TriggerPageChangeOffset) { Rectangle selectedPageBounds = GetSelectedPageBounds(); if (totalMoveOffset < 0) { if (this.SelectedPageIndex < _PageTable.Count - 1) { PageSliderPage newSelection = _PageTable[this.SelectedPageIndex + 1]; // Find right page to select since control can be scrolled a lot through inertia for (int i = _PageTable.Count - 1; i >= 0; i--) { PageSliderPage page = _PageTable[i]; if (page.Bounds.IntersectsWith(selectedPageBounds) && selectedPageBounds.Right - page.Left >= TriggerPageChangeOffset) { newSelection = page; break; } } if (this.SelectedPage != newSelection) this.SelectedPage = newSelection; else PageBoundsOffset = Point.Empty; } else PageBoundsOffset = Point.Empty; } else { if (this.SelectedPageIndex > 0) { PageSliderPage newSelection = _PageTable[this.SelectedPageIndex - 1]; // Find right page to select since control can be scrolled a lot through inertia for (int i = 0; i < _PageTable.Count; i++) { PageSliderPage page = _PageTable[i]; if (page.Bounds.IntersectsWith(selectedPageBounds) && page.Right - selectedPageBounds.X >= TriggerPageChangeOffset) { newSelection = page; break; } } if (this.SelectedPage != newSelection) this.SelectedPage = newSelection; else PageBoundsOffset = Point.Empty; } else PageBoundsOffset = Point.Empty; } } else PageBoundsOffset = Point.Empty; } base.OnMouseUp(e); } protected override void OnVisibleChanged(EventArgs e) { if (_ScrollBarVisibility == eScrollBarVisibility.AutoVisible && this.Visible) { StartScrollBarTimer(); } base.OnVisibleChanged(e); } private eScrollBarVisibility _ScrollBarVisibility = eScrollBarVisibility.AutoVisible; /// /// Indicates scrollbar visibility. /// [DefaultValue(eScrollBarVisibility.AutoVisible), Category("Behavior"), Description("Indicates scrollbar visibility.")] public eScrollBarVisibility ScrollBarVisibility { get { return _ScrollBarVisibility; } set { if (value != _ScrollBarVisibility) { eScrollBarVisibility oldValue = _ScrollBarVisibility; _ScrollBarVisibility = value; OnScrollBarVisibilityChanged(oldValue, value); } } } /// /// Called when ScrollBarVisibility property has changed. /// /// Old property value /// New property value protected virtual void OnScrollBarVisibilityChanged(eScrollBarVisibility oldValue, eScrollBarVisibility newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("ScrollBarVisibility")); if (this.IsHandleCreated) UpdateScrollBarVisibility(); else _UpdateScrollBarVisibilityDelayed = true; } private bool _UpdateScrollBarVisibilityDelayed = false; private void UpdateScrollBarVisibility() { if (_ScrollBarVisibility == eScrollBarVisibility.Hidden) { StopScrollBarTimer(); _HorizontalScrollBar.Visible = false; _VerticalScrollBar.Visible = false; UpdateBoundsForAllPages(false); } else if (_ScrollBarVisibility == eScrollBarVisibility.AlwaysVisible) { StopScrollBarTimer(); if (_Orientation == eOrientation.Horizontal) { if (!_HorizontalScrollBar.Visible) { _HorizontalScrollBar.Visible = true; if (!this.IsHandleCreated && _HorizontalScrollBar.Width == 0) _HorizontalScrollBar.Bounds = new Rectangle(this.ClientRectangle.X, this.ClientRectangle.Bottom - _HorizontalScrollBar.Height, this.ClientRectangle.Width, _HorizontalScrollBar.Height); UpdateBoundsForAllPages(false); } _VerticalScrollBar.Visible = false; } else { _HorizontalScrollBar.Visible = false; if (!_VerticalScrollBar.Visible) { _VerticalScrollBar.Visible = true; UpdateBoundsForAllPages(false); } } } else { Point p = this.PointToClient(Control.MousePosition); if (_ScrollBarTimer == null && this.ClientRectangle.Contains(p)) { StartScrollBarTimer(); } } } private int _AutoScrollBarVisibleTime = 3000; /// /// Gets or sets the time in milliseconds that scrollbar is kept visible when there is no activity in control and mouse is over the control. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int AutoScrollBarVisibleTime { get { return _AutoScrollBarVisibleTime; } set { _AutoScrollBarVisibleTime = value; } } internal void MouseEnterInternal() { if (_ScrollBarVisibility == eScrollBarVisibility.AutoVisible) StartScrollBarTimer(); } protected override void OnMouseEnter(EventArgs e) { MouseEnterInternal(); base.OnMouseEnter(e); } protected override void OnMouseLeave(EventArgs e) { MouseLeaveInternal(); base.OnMouseLeave(e); } internal void MouseLeaveInternal() { if (_ScrollBarVisibility == eScrollBarVisibility.AutoVisible) StartScrollBarTimer(); } private Timer _ScrollBarTimer = null; private void StartScrollBarTimer() { if (_Orientation == eOrientation.Horizontal) { _HorizontalScrollBar.Visible = true; _VerticalScrollBar.Visible = false; } else { _HorizontalScrollBar.Visible = false; _VerticalScrollBar.Visible = true; } if (_ScrollBarTimer == null) { _ScrollBarTimer = new Timer(); _ScrollBarTimer.Tick += new EventHandler(ScrollBarTimerTick); _ScrollBarTimer.Interval = _AutoScrollBarVisibleTime; } _ScrollBarTimer.Stop(); _ScrollBarTimer.Start(); } private Point _LastMousePosition = Point.Empty; void ScrollBarTimerTick(object sender, EventArgs e) { bool hideScrollBars = false; Point p = this.PointToClient(Control.MousePosition); if (this.ClientRectangle.Contains(p)) { if (!_LastMousePosition.IsEmpty && _LastMousePosition == p && (!_HorizontalScrollBar.Bounds.Contains(p) && _HorizontalScrollBar.Visible || !_VerticalScrollBar.Bounds.Contains(p) && _VerticalScrollBar.Visible)) hideScrollBars = true; } else { if (!_LastMousePosition.IsEmpty) hideScrollBars = true; } _LastMousePosition = p; if (hideScrollBars) { StopScrollBarTimer(); _HorizontalScrollBar.Visible = false; _VerticalScrollBar.Visible = false; _LastMousePosition = Point.Empty; } } private void StopScrollBarTimer() { Timer t = _ScrollBarTimer; _ScrollBarTimer = null; if (t != null) { t.Tick -= new EventHandler(ScrollBarTimerTick); t.Stop(); t.Dispose(); } } #endregion #region Touch Handling private bool ProcessTouch(DevComponents.DotNetBar.Touch.GestureEventArgs e) { if (_TouchEnabled == eTouchHandling.No) return false; if (_TouchEnabled == eTouchHandling.ClientContentOnly) { NativeFunctions.POINT p = new NativeFunctions.POINT(e.Location); IntPtr handle = NativeFunctions.ChildWindowFromPoint(this.Handle, p); if (handle == IntPtr.Zero) return false; Control c = Control.FromChildHandle(handle); if (c == null) return false; if (c is PageSliderPage) { handle = NativeFunctions.ChildWindowFromPoint(c.Handle, p); if (handle == IntPtr.Zero) return false; c = Control.FromChildHandle(handle); if (c == null || c is PageSliderPage || c is StepIndicator || c is Label || c is LabelX) return true; } if(c == this || c is StepIndicator) return true; return false; } return true; } private bool _TouchDrag = false; private Point _TouchStartLocation = Point.Empty; private void TouchHandlerPanBegin(object sender, DevComponents.DotNetBar.Touch.GestureEventArgs e) { if (!ProcessTouch(e)) return; _TouchDrag = true; _TouchStartLocation = e.Location; e.Handled = true; } private void TouchHandlerPanEnd(object sender, DevComponents.DotNetBar.Touch.GestureEventArgs e) { if (_TouchDrag) { EndTouchPan(); e.Handled = true; } } private void EndTouchPan() { _TouchDrag = false; int totalMoveOffset = _Orientation == eOrientation.Horizontal ? _PageBoundsOffset.X : _PageBoundsOffset.Y; if (Math.Abs(totalMoveOffset) >= TriggerPageChangeOffset) { Rectangle selectedPageBounds = GetSelectedPageBounds(); if (totalMoveOffset < 0) { if (this.SelectedPageIndex < _PageTable.Count - 1) { PageSliderPage newSelection = _PageTable[this.SelectedPageIndex + 1]; // Find right page to select since control can be scrolled a lot through inertia for (int i = _PageTable.Count - 1; i >= 0; i--) { PageSliderPage page = _PageTable[i]; if (page.Bounds.IntersectsWith(selectedPageBounds) && selectedPageBounds.Right - page.Left >= TriggerPageChangeOffset) { newSelection = page; break; } } if (this.SelectedPage != newSelection) this.SelectedPage = newSelection; else PageBoundsOffset = Point.Empty; } else PageBoundsOffset = Point.Empty; } else { if (this.SelectedPageIndex > 0) { PageSliderPage newSelection = _PageTable[this.SelectedPageIndex - 1]; // Find right page to select since control can be scrolled a lot through inertia for (int i = 0; i < _PageTable.Count; i++) { PageSliderPage page = _PageTable[i]; if (page.Bounds.IntersectsWith(selectedPageBounds) && page.Right - selectedPageBounds.X >= TriggerPageChangeOffset) { newSelection = page; break; } } if (this.SelectedPage != newSelection) this.SelectedPage = newSelection; else PageBoundsOffset = Point.Empty; } else PageBoundsOffset = Point.Empty; } } else PageBoundsOffset = Point.Empty; } private void TouchHandlerPan(object sender, DevComponents.DotNetBar.Touch.GestureEventArgs e) { if (_TouchDrag) { Rectangle selectedPageBounds = GetSelectedPageBounds(); if (_Orientation == eOrientation.Horizontal) { int offset = e.Location.X - _TouchStartLocation.X; int offsetChange = offset - _PageBoundsOffset.X; Rectangle firstPageBounds = GetPageBounds(_PageTable[0]); bool overflow = false; if (_PageTable[0].Left + offsetChange > selectedPageBounds.X + MaximumReversePageOffset && SelectedPageIndex >= 0) { offset -= (_PageTable[0].Left + offsetChange) - (selectedPageBounds.X + MaximumReversePageOffset); overflow = true; } else if (_PageTable[_PageTable.Count - 1].Left + offsetChange < selectedPageBounds.X - MaximumReversePageOffset) { offset += (selectedPageBounds.X - MaximumReversePageOffset) - (_PageTable[_PageTable.Count - 1].Left + offsetChange); overflow = true; } PageBoundsOffset = new Point(offset, 0); if (overflow && e.IsInertia) EndTouchPan(); } else { int offset = e.Location.Y - _TouchStartLocation.Y; int offsetChange = offset - _PageBoundsOffset.Y; Rectangle firstPageBounds = GetPageBounds(_PageTable[0]); bool overflow = false; if (_PageTable[0].Top + offsetChange > selectedPageBounds.Y + MaximumReversePageOffset && SelectedPageIndex >= 0) { offset -= (_PageTable[0].Top + offsetChange) - (selectedPageBounds.Y + MaximumReversePageOffset); overflow = true; } else if (_PageTable[_PageTable.Count - 1].Top + offsetChange < selectedPageBounds.Y - MaximumReversePageOffset) { offset += (selectedPageBounds.Y - MaximumReversePageOffset) - (_PageTable[_PageTable.Count - 1].Top + offsetChange); overflow = true; } PageBoundsOffset = new Point(0, offset); if (overflow && e.IsInertia) EndTouchPan(); } e.Handled = true; } } private eTouchHandling _TouchEnabled = eTouchHandling.Yes; /// /// Indicates whether native touch support in control is enabled if available on target system. /// [DefaultValue(eTouchHandling.Yes), Category("Behavior"), Description("Indicates whether native touch support in control is enabled if available on target system.")] public eTouchHandling TouchEnabled { get { return _TouchEnabled; } set { if (value != _TouchEnabled) { eTouchHandling oldValue = _TouchEnabled; _TouchEnabled = value; OnTouchEnabledChanged(oldValue, value); } } } /// /// Called when TouchEnabled property has changed. /// /// Old property value /// New property value protected virtual void OnTouchEnabledChanged(eTouchHandling oldValue, eTouchHandling newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("TouchEnabled")); } #endregion } /// /// Specifies scrollbar visibility. /// public enum eScrollBarVisibility { /// /// Scrollbars are not visible. /// Hidden, /// /// Scrollbars are visible only if mouse is inside of the control. /// AutoVisible, /// /// Scrollbars are always visible. /// AlwaysVisible } /// /// Specifies level of touch enabled on the control. /// public enum eTouchHandling { /// /// Touch is enabled control wide. /// Yes, /// /// Touch is disabled control wide. /// No, /// /// Touch is enabled but only for the direct control client content. If touch input occurs on any child control it is not processed. /// ClientContentOnly } }