1342 lines
54 KiB
C#
1342 lines
54 KiB
C#
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;
|
|
/// <summary>
|
|
/// Initializes a new instance of the PageSlider class.
|
|
/// </summary>
|
|
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<DevComponents.DotNetBar.Touch.GestureEventArgs>(TouchHandlerPanBegin);
|
|
_TouchHandler.Pan += new EventHandler<DevComponents.DotNetBar.Touch.GestureEventArgs>(TouchHandlerPan);
|
|
_TouchHandler.PanEnd += new EventHandler<DevComponents.DotNetBar.Touch.GestureEventArgs>(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<DevComponents.DotNetBar.Touch.GestureEventArgs>(TouchHandlerPanBegin);
|
|
_TouchHandler.Pan -= new EventHandler<DevComponents.DotNetBar.Touch.GestureEventArgs>(TouchHandlerPan);
|
|
_TouchHandler.PanEnd -= new EventHandler<DevComponents.DotNetBar.Touch.GestureEventArgs>(TouchHandlerPanEnd);
|
|
_TouchHandler.Release();
|
|
}
|
|
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Events
|
|
/// <summary>
|
|
/// Occurs when selected page has changed.
|
|
/// </summary>
|
|
[Description("Occurs when selected page has changed.")]
|
|
public event EventHandler SelectedPageChanged;
|
|
/// <summary>
|
|
/// Raises SelectedPageChanged event.
|
|
/// </summary>
|
|
/// <param name="e">Provides event arguments.</param>
|
|
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;
|
|
/// <summary>
|
|
/// Gets or sets whether current page indicator is visible. Default value is true.
|
|
/// </summary>
|
|
[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);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when IndicatorVisible property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
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<PageSliderPage> _PageTable = new List<PageSliderPage>();
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns array of all pages in control.
|
|
/// </summary>
|
|
/// <returns>Array of pages.</returns>
|
|
public PageSliderPage[] GetAllPages()
|
|
{
|
|
return _PageTable.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes and disposes all pages within the control.
|
|
/// </summary>
|
|
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;
|
|
/// <summary>
|
|
/// Indicates selected page.
|
|
/// </summary>
|
|
[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);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when SelectedPage property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
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;
|
|
/// <summary>
|
|
/// Indicates the animation time in milliseconds for operations that perform visual animation of transition. Set to zero to disable animation.
|
|
/// </summary>
|
|
[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);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when AnimationTime property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
protected virtual void OnAnimationTimeChanged(int oldValue, int newValue)
|
|
{
|
|
//OnPropertyChanged(new PropertyChangedEventArgs("AnimationTime"));
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets zero based selected page index. If there is no page selected returns -1.
|
|
/// </summary>
|
|
[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;
|
|
/// <summary>
|
|
/// Gets the total number of pages displayed by the control.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
public int PageCount
|
|
{
|
|
get
|
|
{
|
|
return _PageTable.Count;
|
|
}
|
|
}
|
|
|
|
private Padding _PagePadding = new Padding(4);
|
|
/// <summary>
|
|
/// Gets or sets the single page padding.
|
|
/// </summary>
|
|
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public Padding PagePadding
|
|
{
|
|
get { return _PagePadding; }
|
|
set
|
|
{
|
|
if (value != _PagePadding)
|
|
{
|
|
Padding oldValue = _PagePadding;
|
|
_PagePadding = value;
|
|
OnPagePaddingChanged(oldValue, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when SelectedPagePadding property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
protected virtual void OnPagePaddingChanged(Padding oldValue, Padding newValue)
|
|
{
|
|
//OnPropertyChanged(new PropertyChangedEventArgs("SelectedPagePadding"));
|
|
UpdateBoundsForAllPages(false);
|
|
}
|
|
|
|
private const int DefaultPageSpacing = 48;
|
|
private int _PageSpacing = DefaultPageSpacing;
|
|
/// <summary>
|
|
/// Gets or sets the spacing in pixels between pages.
|
|
/// </summary>
|
|
[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);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when PageSpacing property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when NextPageVisibleMargin property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
protected virtual void OnNextPageVisibleMarginChanged(int oldValue, int newValue)
|
|
{
|
|
//OnPropertyChanged(new PropertyChangedEventArgs("NextPageVisibleMargin"));
|
|
UpdateBoundsForAllPages(false);
|
|
}
|
|
|
|
private eOrientation _Orientation = eOrientation.Horizontal;
|
|
/// <summary>
|
|
/// Gets or sets the page layout orientation. Default is horizontal.
|
|
/// </summary>
|
|
[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);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when Orientation property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
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;
|
|
/// <summary>
|
|
/// Indicates whether page can be dragged using mouse to change currently selected page
|
|
/// </summary>
|
|
[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;
|
|
/// <summary>
|
|
/// Indicates whether selected page can be changed by using mouse drag on PageSlider client area which is not covered by pages.
|
|
/// </summary>
|
|
[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;
|
|
/// <summary>
|
|
/// Indicates scrollbar visibility.
|
|
/// </summary>
|
|
[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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when ScrollBarVisibility property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
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;
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
[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;
|
|
/// <summary>
|
|
/// Indicates whether native touch support in control is enabled if available on target system.
|
|
/// </summary>
|
|
[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);
|
|
}
|
|
}
|
|
}
|
|
/// <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(eTouchHandling oldValue, eTouchHandling newValue)
|
|
{
|
|
//OnPropertyChanged(new PropertyChangedEventArgs("TouchEnabled"));
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specifies scrollbar visibility.
|
|
/// </summary>
|
|
public enum eScrollBarVisibility
|
|
{
|
|
/// <summary>
|
|
/// Scrollbars are not visible.
|
|
/// </summary>
|
|
Hidden,
|
|
/// <summary>
|
|
/// Scrollbars are visible only if mouse is inside of the control.
|
|
/// </summary>
|
|
AutoVisible,
|
|
/// <summary>
|
|
/// Scrollbars are always visible.
|
|
/// </summary>
|
|
AlwaysVisible
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specifies level of touch enabled on the control.
|
|
/// </summary>
|
|
public enum eTouchHandling
|
|
{
|
|
/// <summary>
|
|
/// Touch is enabled control wide.
|
|
/// </summary>
|
|
Yes,
|
|
/// <summary>
|
|
/// Touch is disabled control wide.
|
|
/// </summary>
|
|
No,
|
|
/// <summary>
|
|
/// Touch is enabled but only for the direct control client content. If touch input occurs on any child control it is not processed.
|
|
/// </summary>
|
|
ClientContentOnly
|
|
}
|
|
}
|