aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio
diff options
context:
space:
mode:
authorRoy Ben-Shabat <Roy@Twine-s.com>2018-06-12 12:47:24 +0300
committerRoy Ben-Shabat <Roy@Twine-s.com>2018-06-12 12:47:24 +0300
commitaf480467b881106ea03428e16def2b7600a5b75e (patch)
tree7dbee6bab9b0641265d2d1bac6973dbbe13462fd /Software/Visual_Studio
parent04379edd1bf2835b163c3db786c2273c1ef1bfdc (diff)
downloadTango-af480467b881106ea03428e16def2b7600a5b75e.tar.gz
Tango-af480467b881106ea03428e16def2b7600a5b75e.zip
Implemented LightTouch ScrollViewer !!
Diffstat (limited to 'Software/Visual_Studio')
-rw-r--r--Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.cs202
-rw-r--r--Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.xaml149
-rw-r--r--Software/Visual_Studio/Tango.Touch/Controls/LightTouchScrollViewer.cs198
-rw-r--r--Software/Visual_Studio/Tango.Touch/Controls/LightTouchScrollViewer.xaml67
-rw-r--r--Software/Visual_Studio/Tango.Touch/Converters/ScrollViewerScrollBarVisibilityConverter.cs26
-rw-r--r--Software/Visual_Studio/Tango.Touch/Converters/ScrollViewerThumbSizeConverter.cs27
-rw-r--r--Software/Visual_Studio/Tango.Touch/Tango.Touch.csproj2
-rw-r--r--Software/Visual_Studio/Utilities/Tango.UITests/MainWindow.xaml2
8 files changed, 374 insertions, 299 deletions
diff --git a/Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.cs b/Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.cs
index 1015dee80..eaaa76d79 100644
--- a/Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.cs
+++ b/Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.cs
@@ -26,13 +26,7 @@ namespace Tango.Touch.Controls
public class LightTouchDataGrid : Control
{
private ItemsControl _items_control_rows;
- private bool _mouse_down;
- private Point _mouse_down_location;
- private Grid _grid_rows;
- private List<double> _last_manipulation_deltas;
private Random _rnd = new Random();
- private const double touch_inertia_coefficiant = 10;
- private const double bounce_offset_max = 100;
private bool _isLoaded;
private List<LightTouchDataGridRow> _awaitingSelectionRows;
private LightTouchDataGridRow _firstMultiSelectionRow;
@@ -95,17 +89,6 @@ namespace Tango.Touch.Controls
DependencyProperty.Register("Columns", typeof(ObservableCollection<LightTouchDataGridColumn>), typeof(LightTouchDataGrid), new PropertyMetadata(new ObservableCollection<LightTouchDataGridColumn>()));
/// <summary>
- /// Gets or sets a value indicating whether the data grid is currently scrolling.
- /// </summary>
- public bool IsScrolling
- {
- get { return (bool)GetValue(IsScrollingProperty); }
- set { SetValue(IsScrollingProperty, value); }
- }
- public static readonly DependencyProperty IsScrollingProperty =
- DependencyProperty.Register("IsScrolling", typeof(bool), typeof(LightTouchDataGrid), new PropertyMetadata(false));
-
- /// <summary>
/// Gets or sets the selection mode.
/// </summary>
public LightTouchDataGridSelectionMode SelectionMode
@@ -138,6 +121,17 @@ namespace Tango.Touch.Controls
public static readonly DependencyProperty ItemSelectedCommandProperty =
DependencyProperty.Register("ItemSelectedCommand", typeof(RelayCommand<Object>), typeof(LightTouchDataGrid), new PropertyMetadata(null));
+ /// <summary>
+ /// Gets or sets the scroll viewer.
+ /// </summary>
+ public LightTouchScrollViewer ScrollViewer
+ {
+ get { return (LightTouchScrollViewer)GetValue(ScrollViewerProperty); }
+ set { SetValue(ScrollViewerProperty, value); }
+ }
+ public static readonly DependencyProperty ScrollViewerProperty =
+ DependencyProperty.Register("ScrollViewer", typeof(LightTouchScrollViewer), typeof(LightTouchDataGrid), new PropertyMetadata(null));
+
#endregion
@@ -184,7 +178,6 @@ namespace Tango.Touch.Controls
public LightTouchDataGrid()
{
_awaitingSelectionRows = new List<LightTouchDataGridRow>();
- _last_manipulation_deltas = new List<double>();
SortCommand = new RelayCommand<LightTouchDataGridColumn>(HandleSortCommand);
Loaded += LightTouchDataGrid_Loaded;
}
@@ -200,159 +193,17 @@ namespace Tango.Touch.Controls
{
base.OnApplyTemplate();
_items_control_rows = GetTemplateChild("PART_ItemsControl_Rows") as ItemsControl;
- _grid_rows = GetTemplateChild("PART_Grid_Rows") as Grid;
+ ScrollViewer = GetTemplateChild("PART_ScrollViewer") as LightTouchScrollViewer;
DraggingSurface = GetTemplateChild("PART_DraggingSurface") as DraggingSurface;
- _grid_rows.IsManipulationEnabled = true;
- _grid_rows.RegisterForMouseOrTouchDown(OnMouseTouchDown);
- _grid_rows.RegisterForMouseOrTouchMove(OnMouseTouchMove);
- _grid_rows.RegisterForPreviewMouseOrTouchUp(OnMouseTouchUp);
-
- _grid_rows.ManipulationDelta += _grid_rows_ManipulationDelta;
- _grid_rows.ManipulationCompleted += _grid_rows_ManipulationCompleted;
-
_items_control_rows.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
}
#endregion
- #region Touch Manipulation Handlers
-
- /// <summary>
- /// Handles the ManipulationCompleted event of the _grid_rows control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="ManipulationCompletedEventArgs"/> instance containing the event data.</param>
- private void _grid_rows_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
- {
- if (_last_manipulation_deltas.Count == 0) return;
-
- var last_manipulation_delta = _last_manipulation_deltas.Last();
-
- if (last_manipulation_delta == 0 && _last_manipulation_deltas.Count > 1)
- {
- last_manipulation_delta = _last_manipulation_deltas[_last_manipulation_deltas.Count - 2];
- }
-
- if (last_manipulation_delta != 0)
- {
- var to = (_items_control_rows.Margin.Top + (last_manipulation_delta * touch_inertia_coefficiant));
-
- if (to > 0)
- {
- to = Math.Min(to, bounce_offset_max);
- }
- else
- {
- to = Math.Max(to, bounce_offset_max + -(_items_control_rows.ActualHeight - _grid_rows.ActualHeight));
- }
-
- bool bounced = false;
-
- ThicknessAnimation ani = new ThicknessAnimation();
- ani.Duration = TimeSpan.FromSeconds(1);
- ani.To = new Thickness(0, to, 0, 0);
- ani.CurrentTimeInvalidated += (_, __) =>
- {
- if (!bounced)
- {
- if (_items_control_rows.Margin.Top > 0 || (_items_control_rows.Margin.Top - _grid_rows.ActualHeight < -_items_control_rows.ActualHeight))
- {
- bounced = true;
- SnapRowsToBounds();
- }
- }
- };
- ani.DecelerationRatio = 1.0;
- _items_control_rows.BeginAnimation(ItemsControl.MarginProperty, ani);
- _last_manipulation_deltas.Clear();
- }
-
- ReleaseAllTouchCaptures();
- }
-
- /// <summary>
- /// Handles the ManipulationDelta event of the _grid_rows control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="ManipulationDeltaEventArgs"/> instance containing the event data.</param>
- private void _grid_rows_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
- {
- _last_manipulation_deltas.Add(e.DeltaManipulation.Translation.Y);
- }
-
- #endregion
-
#region Touch / Mouse Handlers
/// <summary>
- /// Called when the mouse touch has been down
- /// </summary>
- /// <param name="sender">The sender.</param>
- /// <param name="e">The <see cref="MouseOrTouchEventArgs"/> instance containing the event data.</param>
- protected virtual void OnMouseTouchDown(object sender, MouseOrTouchEventArgs e)
- {
- if (e.OriginalSource.GetType() == typeof(DragThumb))
- {
- return;
- }
-
- _mouse_down_location = new Point(e.Location.X, e.Location.Y - _items_control_rows.Margin.Top);
- _mouse_down = true;
- }
-
- /// <summary>
- /// Called when the mouse touch has been move
- /// </summary>
- /// <param name="sender">The sender.</param>
- /// <param name="e">The <see cref="MouseOrTouchEventArgs"/> instance containing the event data.</param>
- protected virtual void OnMouseTouchMove(object sender, MouseOrTouchEventArgs e)
- {
- var a = _mouse_down_location.Y + _items_control_rows.Margin.Top;
-
- if (_mouse_down && Math.Abs((e.Location.Y - a)) > 5)
- {
- IsScrolling = true;
- Mouse.Capture(_grid_rows);
-
- if (e.TouchDevice != null)
- {
- e.TouchDevice.Capture(_grid_rows);
- }
-
- _items_control_rows.Margin = new Thickness(0, e.Location.Y - _mouse_down_location.Y, 0, 0);
- _items_control_rows.BeginAnimation(ItemsControl.MarginProperty, null);
- }
- }
-
- /// <summary>
- /// Called when the mouse touch has been up
- /// </summary>
- /// <param name="sender">The sender.</param>
- /// <param name="e">The <see cref="MouseOrTouchEventArgs"/> instance containing the event data.</param>
- protected virtual void OnMouseTouchUp(object sender, MouseOrTouchEventArgs e)
- {
- if (_mouse_down)
- {
- _mouse_down = false;
- Mouse.Capture(null);
-
- if (e.TouchDevice != null)
- {
- e.TouchDevice.Capture(null);
- }
-
- if (IsScrolling)
- {
- e.Handled = true;
- SnapRowsToBounds();
- }
-
- IsScrolling = false;
- }
- }
-
- /// <summary>
/// Called when the row mouse touch has been up
/// </summary>
/// <param name="sender">The sender.</param>
@@ -375,7 +226,7 @@ namespace Tango.Touch.Controls
}
else if (SelectionMode == LightTouchDataGridSelectionMode.Multiple && IsMultiSelecting)
{
- if (!IsScrolling)
+ if (!ScrollViewer.IsScrolling)
{
if (row != _firstMultiSelectionRow)
{
@@ -411,7 +262,7 @@ namespace Tango.Touch.Controls
{
_awaitingSelectionRows.Remove(row);
- if (_mouse_down && !IsScrolling)
+ if (ScrollViewer.IsMouseTouchDown && !ScrollViewer.IsScrolling)
{
_firstMultiSelectionRow = row;
otherRows.ForEach(x => x.IsSelected = false);
@@ -488,31 +339,6 @@ namespace Tango.Touch.Controls
#endregion
- #region Private Methods
-
- /// <summary>
- /// Snaps the items control if they are out of bounds.
- /// </summary>
- private void SnapRowsToBounds()
- {
- ThicknessAnimation ani = new ThicknessAnimation();
- ani.Duration = TimeSpan.FromSeconds(0.2);
- ani.AccelerationRatio = 1;
-
- if (_items_control_rows.Margin.Top > 0 || _items_control_rows.ActualHeight < _grid_rows.ActualHeight)
- {
- ani.To = new Thickness(0);
- _items_control_rows.BeginAnimation(ItemsControl.MarginProperty, ani);
- }
- else if (_items_control_rows.Margin.Top - _grid_rows.ActualHeight < -_items_control_rows.ActualHeight)
- {
- ani.To = new Thickness(0, -(_items_control_rows.ActualHeight - _grid_rows.ActualHeight), 0, 0);
- _items_control_rows.BeginAnimation(ItemsControl.MarginProperty, ani);
- }
- }
-
- #endregion
-
#region Public Methods
/// <summary>
diff --git a/Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.xaml b/Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.xaml
index faf1ba3de..ac1be1e62 100644
--- a/Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.xaml
+++ b/Software/Visual_Studio/Tango.Touch/Controls/LightTouchDataGrid.xaml
@@ -160,86 +160,87 @@
</local:LightTouchDataGridHeaderRow>
<!--Rows-->
- <Grid x:Name="PART_Grid_Rows" ClipToBounds="True" Background="Transparent">
- <ItemsControl ItemsSource="{TemplateBinding ItemsSource}" x:Name="PART_ItemsControl_Rows" ClipToBounds="True" VerticalAlignment="Top">
- <ItemsControl.ItemsPanel>
- <ItemsPanelTemplate>
- <Canvas ClipToBounds="True" IsItemsHost="True" VirtualizingPanel.IsVirtualizing="True">
- </Canvas>
- </ItemsPanelTemplate>
- </ItemsControl.ItemsPanel>
- <ItemsControl.ItemContainerStyle>
- <Style TargetType="FrameworkElement">
- <Setter Property="Width" Value="{Binding RelativeSource={RelativeSource AncestorType=local:LightTouchDataGrid},Path=ActualWidth}"></Setter>
- </Style>
- </ItemsControl.ItemContainerStyle>
- <ItemsControl.ItemTemplate>
- <DataTemplate>
- <local:LightTouchDataGridRow RenderTransformOrigin="0.5,0.5"
+ <Grid>
+ <local:LightTouchScrollViewer x:Name="PART_ScrollViewer">
+ <ItemsControl ItemsSource="{TemplateBinding ItemsSource}" x:Name="PART_ItemsControl_Rows" ClipToBounds="True" VerticalAlignment="Top">
+ <ItemsControl.ItemsPanel>
+ <ItemsPanelTemplate>
+ <Canvas ClipToBounds="True" IsItemsHost="True" VirtualizingPanel.IsVirtualizing="True">
+ </Canvas>
+ </ItemsPanelTemplate>
+ </ItemsControl.ItemsPanel>
+ <ItemsControl.ItemContainerStyle>
+ <Style TargetType="FrameworkElement">
+ <Setter Property="Width" Value="{Binding RelativeSource={RelativeSource AncestorType=local:LightTouchDataGrid},Path=ActualWidth}"></Setter>
+ </Style>
+ </ItemsControl.ItemContainerStyle>
+ <ItemsControl.ItemTemplate>
+ <DataTemplate>
+ <local:LightTouchDataGridRow RenderTransformOrigin="0.5,0.5"
dragAndDrop:DragAndDropService.Draggable="{Binding RelativeSource={RelativeSource AncestorType=local:LightTouchDataGrid},Path=EnableDragAndDrop}"
dragAndDrop:DragAndDropService.Droppable="{Binding RelativeSource={RelativeSource AncestorType=local:LightTouchDataGrid},Path=EnableDragAndDrop}"
dragAndDrop:DragAndDropService.DraggingSurface="{Binding RelativeSource={RelativeSource AncestorType=local:LightTouchDataGrid},Path=DraggingSurface}"
dragAndDrop:DragAndDropService.MinDragOffset="2"
Padding="0" Canvas.Top="{Binding RelativeSource={RelativeSource AncestorType=ContentPresenter},Path=(Canvas.Top),Mode=TwoWay}">
- <components:Ripple RippleFactor="20" RippleBrush="{StaticResource TangoRippleDarkBrush}" CornerRadius="{Binding RelativeSource={RelativeSource AncestorType=local:LightTouchDataGridRow},Path=CornerRadius}">
- <components:Ripple.Style>
- <Style TargetType="components:Ripple">
- <Setter Property="Disabled" Value="False"></Setter>
- <Style.Triggers>
- <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=local:LightTouchDataGrid},Path=IsScrolling}" Value="True">
- <Setter Property="Disabled" Value="True"></Setter>
- </DataTrigger>
- <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=local:LightTouchDataGrid},Path=IsMultiSelecting}" Value="True">
- <Setter Property="Disabled" Value="True"></Setter>
- </DataTrigger>
- </Style.Triggers>
- </Style>
- </components:Ripple.Style>
- <ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=local:LightTouchDataGrid},Path=Columns}">
- <ItemsControl.ItemsPanel>
- <ItemsPanelTemplate>
- <Grid>
- <Grid.Tag>
- <MultiBinding Converter="{StaticResource ColumnsToGridDefinitionsConverter}">
- <Binding RelativeSource="{RelativeSource Self}" Path="." />
- <Binding RelativeSource="{RelativeSource AncestorType=local:LightTouchDataGrid}" Path="Columns"/>
- </MultiBinding>
- </Grid.Tag>
- </Grid>
- </ItemsPanelTemplate>
- </ItemsControl.ItemsPanel>
- <ItemsControl.ItemContainerStyle>
- <Style TargetType="FrameworkElement">
- <Setter Property="Grid.Column">
- <Setter.Value>
- <MultiBinding Converter="{StaticResource ColumnToColumnIndexConverter}">
- <Binding RelativeSource="{RelativeSource AncestorType=local:LightTouchDataGrid}" Path="Columns" />
- <Binding Path="." />
- </MultiBinding>
- </Setter.Value>
- </Setter>
+ <components:Ripple RippleFactor="20" RippleBrush="{StaticResource TangoRippleDarkBrush}" CornerRadius="{Binding RelativeSource={RelativeSource AncestorType=local:LightTouchDataGridRow},Path=CornerRadius}">
+ <components:Ripple.Style>
+ <Style TargetType="components:Ripple">
+ <Setter Property="Disabled" Value="False"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=local:LightTouchDataGrid},Path=ScrollViewer.IsScrolling}" Value="True">
+ <Setter Property="Disabled" Value="True"></Setter>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=local:LightTouchDataGrid},Path=IsMultiSelecting}" Value="True">
+ <Setter Property="Disabled" Value="True"></Setter>
+ </DataTrigger>
+ </Style.Triggers>
</Style>
- </ItemsControl.ItemContainerStyle>
- <ItemsControl.ItemTemplate>
- <DataTemplate>
- <local:LightTouchDataGridCell>
- <local:LightTouchDataGridCell.Style>
- <Style TargetType="local:LightTouchDataGridCell" BasedOn="{StaticResource {x:Type local:LightTouchDataGridCell}}">
- <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment}"></Setter>
- <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment}"></Setter>
- </Style>
- </local:LightTouchDataGridCell.Style>
- <ContentControl Content="{Binding RelativeSource={RelativeSource AncestorType=ItemsPresenter},Path=DataContext}" ContentTemplate="{Binding CellTemplate}" VerticalContentAlignment="{Binding VerticalContentAlignment}" HorizontalContentAlignment="{Binding HorizontalContentAlignment}" />
- </local:LightTouchDataGridCell>
- </DataTemplate>
- </ItemsControl.ItemTemplate>
- </ItemsControl>
- </components:Ripple>
- </local:LightTouchDataGridRow>
- </DataTemplate>
- </ItemsControl.ItemTemplate>
- </ItemsControl>
-
+ </components:Ripple.Style>
+ <ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=local:LightTouchDataGrid},Path=Columns}">
+ <ItemsControl.ItemsPanel>
+ <ItemsPanelTemplate>
+ <Grid>
+ <Grid.Tag>
+ <MultiBinding Converter="{StaticResource ColumnsToGridDefinitionsConverter}">
+ <Binding RelativeSource="{RelativeSource Self}" Path="." />
+ <Binding RelativeSource="{RelativeSource AncestorType=local:LightTouchDataGrid}" Path="Columns"/>
+ </MultiBinding>
+ </Grid.Tag>
+ </Grid>
+ </ItemsPanelTemplate>
+ </ItemsControl.ItemsPanel>
+ <ItemsControl.ItemContainerStyle>
+ <Style TargetType="FrameworkElement">
+ <Setter Property="Grid.Column">
+ <Setter.Value>
+ <MultiBinding Converter="{StaticResource ColumnToColumnIndexConverter}">
+ <Binding RelativeSource="{RelativeSource AncestorType=local:LightTouchDataGrid}" Path="Columns" />
+ <Binding Path="." />
+ </MultiBinding>
+ </Setter.Value>
+ </Setter>
+ </Style>
+ </ItemsControl.ItemContainerStyle>
+ <ItemsControl.ItemTemplate>
+ <DataTemplate>
+ <local:LightTouchDataGridCell>
+ <local:LightTouchDataGridCell.Style>
+ <Style TargetType="local:LightTouchDataGridCell" BasedOn="{StaticResource {x:Type local:LightTouchDataGridCell}}">
+ <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment}"></Setter>
+ <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment}"></Setter>
+ </Style>
+ </local:LightTouchDataGridCell.Style>
+ <ContentControl Content="{Binding RelativeSource={RelativeSource AncestorType=ItemsPresenter},Path=DataContext}" ContentTemplate="{Binding CellTemplate}" VerticalContentAlignment="{Binding VerticalContentAlignment}" HorizontalContentAlignment="{Binding HorizontalContentAlignment}" />
+ </local:LightTouchDataGridCell>
+ </DataTemplate>
+ </ItemsControl.ItemTemplate>
+ </ItemsControl>
+ </components:Ripple>
+ </local:LightTouchDataGridRow>
+ </DataTemplate>
+ </ItemsControl.ItemTemplate>
+ </ItemsControl>
+ </local:LightTouchScrollViewer>
<dragAndDrop:DraggingSurface x:Name="PART_DraggingSurface" />
</Grid>
</DockPanel>
diff --git a/Software/Visual_Studio/Tango.Touch/Controls/LightTouchScrollViewer.cs b/Software/Visual_Studio/Tango.Touch/Controls/LightTouchScrollViewer.cs
index 8c9410586..eda8b759f 100644
--- a/Software/Visual_Studio/Tango.Touch/Controls/LightTouchScrollViewer.cs
+++ b/Software/Visual_Studio/Tango.Touch/Controls/LightTouchScrollViewer.cs
@@ -5,7 +5,9 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
using System.Windows.Input;
+using System.Windows.Media;
using System.Windows.Media.Animation;
using Tango.Core.EventArguments;
using Tango.DragAndDrop;
@@ -14,13 +16,14 @@ namespace Tango.Touch.Controls
{
public class LightTouchScrollViewer : ContentControl
{
- private Border _grid_rows;
- private Grid _items_control_rows;
- private bool _mouse_down;
+ private Border _border_viewport;
+ private Grid _grid_content;
private Point _mouse_down_location;
private List<double> _last_manipulation_deltas;
private const double touch_inertia_coefficiant = 10;
private const double bounce_offset_max = 100;
+ private Thumb _thumb;
+ private Border _border_thumb;
#region Properties
@@ -35,6 +38,67 @@ namespace Tango.Touch.Controls
public static readonly DependencyProperty IsScrollingProperty =
DependencyProperty.Register("IsScrolling", typeof(bool), typeof(LightTouchScrollViewer), new PropertyMetadata(false));
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this instance is mouse touch down.
+ /// </summary>
+ public bool IsMouseTouchDown
+ {
+ get { return (bool)GetValue(IsMouseTouchDownProperty); }
+ set { SetValue(IsMouseTouchDownProperty, value); }
+ }
+ public static readonly DependencyProperty IsMouseTouchDownProperty =
+ DependencyProperty.Register("IsMouseTouchDown", typeof(bool), typeof(LightTouchScrollViewer), new PropertyMetadata(false));
+
+ /// <summary>
+ /// Gets or sets the width of the scroll bar.
+ /// </summary>
+ /// <value>
+ /// The width of the scroll bar.
+ /// </value>
+ public double ScrollBarWidth
+ {
+ get { return (double)GetValue(ScrollBarWidthProperty); }
+ set { SetValue(ScrollBarWidthProperty, value); }
+ }
+ public static readonly DependencyProperty ScrollBarWidthProperty =
+ DependencyProperty.Register("ScrollBarWidth", typeof(double), typeof(LightTouchScrollViewer), new PropertyMetadata(5.0));
+
+ /// <summary>
+ /// Gets or sets the scroll bar background.
+ /// </summary>
+ public Brush ScrollBarBackground
+ {
+ get { return (Brush)GetValue(ScrollBarBackgroundProperty); }
+ set { SetValue(ScrollBarBackgroundProperty, value); }
+ }
+ public static readonly DependencyProperty ScrollBarBackgroundProperty =
+ DependencyProperty.Register("ScrollBarBackground", typeof(Brush), typeof(LightTouchScrollViewer), new PropertyMetadata(null));
+
+ /// <summary>
+ /// Gets or sets the scroll bar foreground.
+ /// </summary>
+ public Brush ScrollBarForeground
+ {
+ get { return (Brush)GetValue(ScrollBarForegroundProperty); }
+ set { SetValue(ScrollBarForegroundProperty, value); }
+ }
+ public static readonly DependencyProperty ScrollBarForegroundProperty =
+ DependencyProperty.Register("ScrollBarForeground", typeof(Brush), typeof(LightTouchScrollViewer), new PropertyMetadata(null));
+
+ /// <summary>
+ /// Gets or sets the scroll bar corner radius.
+ /// </summary>
+ public CornerRadius ScrollBarCornerRadius
+ {
+ get { return (CornerRadius)GetValue(ScrollBarCornerRadiusProperty); }
+ set { SetValue(ScrollBarCornerRadiusProperty, value); }
+ }
+ public static readonly DependencyProperty ScrollBarCornerRadiusProperty =
+ DependencyProperty.Register("ScrollBarCornerRadius", typeof(CornerRadius), typeof(LightTouchScrollViewer), new PropertyMetadata(default(CornerRadius)));
+
+
+
#endregion
#region Constructors
@@ -57,16 +121,60 @@ namespace Tango.Touch.Controls
{
base.OnApplyTemplate();
- _grid_rows = GetTemplateChild("PART_Border") as Border;
- _items_control_rows = GetTemplateChild("PART_Grid_Content") as Grid;
+ _border_viewport = GetTemplateChild("PART_Border") as Border;
+ _grid_content = GetTemplateChild("PART_Grid_Content") as Grid;
+ _thumb = GetTemplateChild("PART_Thumb") as Thumb;
+ _border_thumb = GetTemplateChild("PART_Thumb_Border") as Border;
+
+ ContentPresenter presenter = GetTemplateChild("PART_Content_Presenter") as ContentPresenter;
+ FrameworkElement firstChild = presenter.Content as FrameworkElement;
+
+ _grid_content.Bind(Grid.HeightProperty, firstChild, FrameworkElement.HeightProperty);
+
+ _border_viewport.IsManipulationEnabled = true;
+ _border_viewport.RegisterForMouseOrTouchDown(OnMouseTouchDown);
+ _border_viewport.RegisterForMouseOrTouchMove(OnMouseTouchMove);
+ _border_viewport.RegisterForPreviewMouseOrTouchUp(OnMouseTouchUp);
- _grid_rows.IsManipulationEnabled = true;
- _grid_rows.RegisterForMouseOrTouchDown(OnMouseTouchDown);
- _grid_rows.RegisterForMouseOrTouchMove(OnMouseTouchMove);
- _grid_rows.RegisterForPreviewMouseOrTouchUp(OnMouseTouchUp);
+ _border_viewport.ManipulationDelta += _grid_rows_ManipulationDelta;
+ _border_viewport.ManipulationCompleted += _grid_rows_ManipulationCompleted;
- _grid_rows.ManipulationDelta += _grid_rows_ManipulationDelta;
- _grid_rows.ManipulationCompleted += _grid_rows_ManipulationCompleted;
+ _thumb.DragDelta += _thumb_DragDelta;
+ _thumb.DragStarted += _thumb_DragStarted;
+ _thumb.DragCompleted += _thumb_DragCompleted;
+ }
+
+ private void _thumb_DragCompleted(object sender, DragCompletedEventArgs e)
+ {
+ IsScrolling = false;
+ }
+
+ private void _thumb_DragStarted(object sender, DragStartedEventArgs e)
+ {
+ IsScrolling = true;
+ }
+
+ private void _thumb_DragDelta(object sender, DragDeltaEventArgs e)
+ {
+ var step = CalculateScrollbarThumbStep();
+
+ double content_margin = _grid_content.Margin.Top + -(step * e.VerticalChange);
+
+ _grid_content.BeginAnimation(Grid.MarginProperty, null);
+
+ Canvas.SetTop(_border_thumb, Canvas.GetTop(_border_thumb) + e.VerticalChange);
+ _grid_content.Margin = new Thickness(0, content_margin, 0, 0);
+
+ if (content_margin > 0)
+ {
+ Canvas.SetTop(_border_thumb, 0);
+ _grid_content.Margin = new Thickness(0, 0, 0, 0);
+ }
+ else if (content_margin - _border_viewport.ActualHeight < -_grid_content.ActualHeight)
+ {
+ Canvas.SetTop(_border_thumb, _border_viewport.ActualHeight - _border_thumb.ActualHeight);
+ _grid_content.Margin = new Thickness(0, -(_grid_content.ActualHeight - _border_viewport.ActualHeight), 0, 0);
+ }
}
#endregion
@@ -91,7 +199,7 @@ namespace Tango.Touch.Controls
if (last_manipulation_delta != 0)
{
- var to = (_items_control_rows.Margin.Top + (last_manipulation_delta * touch_inertia_coefficiant));
+ var to = (_grid_content.Margin.Top + (last_manipulation_delta * touch_inertia_coefficiant));
if (to > 0)
{
@@ -99,7 +207,7 @@ namespace Tango.Touch.Controls
}
else
{
- to = Math.Max(to, bounce_offset_max + -(_items_control_rows.ActualHeight - _grid_rows.ActualHeight));
+ to = Math.Max(to, bounce_offset_max + -(_grid_content.ActualHeight - _border_viewport.ActualHeight));
}
bool bounced = false;
@@ -111,15 +219,17 @@ namespace Tango.Touch.Controls
{
if (!bounced)
{
- if (_items_control_rows.Margin.Top > 0 || (_items_control_rows.Margin.Top - _grid_rows.ActualHeight < -_items_control_rows.ActualHeight))
+ if (_grid_content.Margin.Top > 0 || (_grid_content.Margin.Top - _border_viewport.ActualHeight < -_grid_content.ActualHeight))
{
bounced = true;
SnapRowsToBounds();
}
}
+
+ SetThumbPosition();
};
ani.DecelerationRatio = 1.0;
- _items_control_rows.BeginAnimation(ItemsControl.MarginProperty, ani);
+ _grid_content.BeginAnimation(Grid.MarginProperty, ani);
_last_manipulation_deltas.Clear();
}
@@ -152,8 +262,8 @@ namespace Tango.Touch.Controls
return;
}
- _mouse_down_location = new Point(e.Location.X, e.Location.Y - _items_control_rows.Margin.Top);
- _mouse_down = true;
+ _mouse_down_location = new Point(e.Location.X, e.Location.Y - _grid_content.Margin.Top);
+ IsMouseTouchDown = true;
}
/// <summary>
@@ -163,20 +273,22 @@ namespace Tango.Touch.Controls
/// <param name="e">The <see cref="MouseOrTouchEventArgs"/> instance containing the event data.</param>
protected virtual void OnMouseTouchMove(object sender, MouseOrTouchEventArgs e)
{
- var a = _mouse_down_location.Y + _items_control_rows.Margin.Top;
+ var a = _mouse_down_location.Y + _grid_content.Margin.Top;
- if (_mouse_down && Math.Abs((e.Location.Y - a)) > 5)
+ if (IsMouseTouchDown && Math.Abs((e.Location.Y - a)) > 5)
{
IsScrolling = true;
- Mouse.Capture(_grid_rows);
+ Mouse.Capture(_border_viewport);
if (e.TouchDevice != null)
{
- e.TouchDevice.Capture(_grid_rows);
+ e.TouchDevice.Capture(_border_viewport);
}
- _items_control_rows.Margin = new Thickness(0, e.Location.Y - _mouse_down_location.Y, 0, 0);
- _items_control_rows.BeginAnimation(ItemsControl.MarginProperty, null);
+ _grid_content.Margin = new Thickness(0, e.Location.Y - _mouse_down_location.Y, 0, 0);
+ _grid_content.BeginAnimation(Grid.MarginProperty, null);
+
+ SetThumbPosition();
}
}
@@ -187,9 +299,9 @@ namespace Tango.Touch.Controls
/// <param name="e">The <see cref="MouseOrTouchEventArgs"/> instance containing the event data.</param>
protected virtual void OnMouseTouchUp(object sender, MouseOrTouchEventArgs e)
{
- if (_mouse_down)
+ if (IsMouseTouchDown)
{
- _mouse_down = false;
+ IsMouseTouchDown = false;
Mouse.Capture(null);
if (e.TouchDevice != null)
@@ -220,15 +332,41 @@ namespace Tango.Touch.Controls
ani.Duration = TimeSpan.FromSeconds(0.2);
ani.AccelerationRatio = 1;
- if (_items_control_rows.Margin.Top > 0 || _items_control_rows.ActualHeight < _grid_rows.ActualHeight)
+ if (_grid_content.Margin.Top > 0 || _grid_content.ActualHeight < _border_viewport.ActualHeight)
{
ani.To = new Thickness(0);
- _items_control_rows.BeginAnimation(ItemsControl.MarginProperty, ani);
+ _grid_content.BeginAnimation(Grid.MarginProperty, ani);
+ }
+ else if (_grid_content.Margin.Top - _border_viewport.ActualHeight < -_grid_content.ActualHeight)
+ {
+ ani.To = new Thickness(0, -(_grid_content.ActualHeight - _border_viewport.ActualHeight), 0, 0);
+ _grid_content.BeginAnimation(Grid.MarginProperty, ani);
+ }
+ }
+
+ private double CalculateScrollbarThumbStep()
+ {
+ var scrollTrackSpace = _grid_content.ActualHeight - _border_viewport.ActualHeight;
+ var scrollThumbSpace = _border_viewport.ActualHeight - _thumb.ActualHeight;
+ var scrollJump = scrollTrackSpace / scrollThumbSpace;
+ return scrollJump;
+ }
+
+ private void SetThumbPosition()
+ {
+ double step = CalculateScrollbarThumbStep();
+ double content_margin = _grid_content.Margin.Top;
+ double thumb_top = -(content_margin / step);
+
+ Canvas.SetTop(_border_thumb, thumb_top);
+
+ if (thumb_top < 0)
+ {
+ Canvas.SetTop(_border_thumb, 0);
}
- else if (_items_control_rows.Margin.Top - _grid_rows.ActualHeight < -_items_control_rows.ActualHeight)
+ else if (thumb_top + _border_thumb.ActualHeight > _border_viewport.ActualHeight)
{
- ani.To = new Thickness(0, -(_items_control_rows.ActualHeight - _grid_rows.ActualHeight), 0, 0);
- _items_control_rows.BeginAnimation(ItemsControl.MarginProperty, ani);
+ Canvas.SetTop(_border_thumb, _border_viewport.ActualHeight - _border_thumb.ActualHeight);
}
}
diff --git a/Software/Visual_Studio/Tango.Touch/Controls/LightTouchScrollViewer.xaml b/Software/Visual_Studio/Tango.Touch/Controls/LightTouchScrollViewer.xaml
index df0e7a434..a1873acca 100644
--- a/Software/Visual_Studio/Tango.Touch/Controls/LightTouchScrollViewer.xaml
+++ b/Software/Visual_Studio/Tango.Touch/Controls/LightTouchScrollViewer.xaml
@@ -1,20 +1,75 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:converters="clr-namespace:Tango.Touch.Converters"
+ xmlns:dragAndDrop="clr-namespace:Tango.DragAndDrop;assembly=Tango.DragAndDrop"
xmlns:local="clr-namespace:Tango.Touch.Controls">
+ <ResourceDictionary.MergedDictionaries>
+ <ResourceDictionary>
+ <converters:ScrollViewerThumbSizeConverter x:Key="ScrollViewerThumbSizeConverter" />
+ <converters:ScrollViewerScrollBarVisibilityConverter x:Key="ScrollViewerScrollBarVisibilityConverter" />
+ </ResourceDictionary>
+ </ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type local:LightTouchScrollViewer}">
+ <Setter Property="ScrollBarBackground" Value="#33000000"></Setter>
+ <Setter Property="ScrollBarForeground" Value="#90000000"></Setter>
+ <Setter Property="ScrollBarWidth" Value="5"></Setter>
+ <Setter Property="ScrollBarCornerRadius" Value="3"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:LightTouchScrollViewer}">
- <Border x:Name="PART_Border" ClipToBounds="True" Background="Transparent">
- <Grid x:Name="PART_Grid_Content" ClipToBounds="True" Background="Transparent">
- <ContentPresenter Content="{TemplateBinding Content}" />
- </Grid>
- </Border>
+ <Grid>
+ <Border x:Name="PART_Border" ClipToBounds="True" Background="Transparent">
+ <Grid x:Name="PART_Grid_Content" Background="Transparent" VerticalAlignment="Top">
+ <ContentPresenter x:Name="PART_Content_Presenter" Content="{TemplateBinding Content}" VerticalAlignment="Top" Height="Auto" />
+ </Grid>
+ </Border>
+
+ <Canvas Margin="0 0 5 0" x:Name="PART_canvas" HorizontalAlignment="Right" VerticalAlignment="Stretch" Width="{TemplateBinding ScrollBarWidth}" Background="{TemplateBinding ScrollBarBackground}">
+ <Canvas.Visibility>
+ <MultiBinding Converter="{StaticResource ScrollViewerScrollBarVisibilityConverter}">
+ <Binding ElementName="PART_Border" Path="ActualHeight" />
+ <Binding ElementName="PART_Grid_Content" Path="ActualHeight" />
+ </MultiBinding>
+ </Canvas.Visibility>
+ <Canvas.Style>
+ <Style TargetType="Canvas">
+ <Setter Property="Opacity" Value="0"></Setter>
+ <Style.Triggers>
+ <DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent},Path=IsScrolling}" Value="True">
+ <DataTrigger.EnterActions>
+ <BeginStoryboard>
+ <Storyboard>
+ <DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="00:00:0.2"/>
+ </Storyboard>
+ </BeginStoryboard>
+ </DataTrigger.EnterActions>
+ <DataTrigger.ExitActions>
+ <BeginStoryboard>
+ <Storyboard>
+ <DoubleAnimation Storyboard.TargetProperty="Opacity" To="0" BeginTime="00:00:01" Duration="00:00:01"/>
+ </Storyboard>
+ </BeginStoryboard>
+ </DataTrigger.ExitActions>
+ </DataTrigger>
+ </Style.Triggers>
+ </Style>
+ </Canvas.Style>
+ <Border x:Name="PART_Thumb_Border" CornerRadius="{TemplateBinding ScrollBarCornerRadius}" Canvas.Top="0" Width="{Binding ElementName=PART_canvas,Path=ActualWidth}" Background="{TemplateBinding ScrollBarForeground}">
+ <Border.Height>
+ <MultiBinding Converter="{StaticResource ScrollViewerThumbSizeConverter}">
+ <Binding ElementName="PART_Border" Path="ActualHeight" />
+ <Binding ElementName="PART_Grid_Content" Path="ActualHeight" />
+ </MultiBinding>
+ </Border.Height>
+ <Thumb x:Name="PART_Thumb" Opacity="0" Background="Transparent" />
+ </Border>
+ </Canvas>
+ </Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
-
+
</ResourceDictionary> \ No newline at end of file
diff --git a/Software/Visual_Studio/Tango.Touch/Converters/ScrollViewerScrollBarVisibilityConverter.cs b/Software/Visual_Studio/Tango.Touch/Converters/ScrollViewerScrollBarVisibilityConverter.cs
new file mode 100644
index 000000000..d477feeb3
--- /dev/null
+++ b/Software/Visual_Studio/Tango.Touch/Converters/ScrollViewerScrollBarVisibilityConverter.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Data;
+
+namespace Tango.Touch.Converters
+{
+ public class ScrollViewerScrollBarVisibilityConverter : IMultiValueConverter
+ {
+ public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ double scroll_viewer_height = (double)values[0];
+ double content_height = (double)values[1];
+ return content_height > scroll_viewer_height ? Visibility.Visible : Visibility.Collapsed;
+ }
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.Touch/Converters/ScrollViewerThumbSizeConverter.cs b/Software/Visual_Studio/Tango.Touch/Converters/ScrollViewerThumbSizeConverter.cs
new file mode 100644
index 000000000..5307f6509
--- /dev/null
+++ b/Software/Visual_Studio/Tango.Touch/Converters/ScrollViewerThumbSizeConverter.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Data;
+
+namespace Tango.Touch.Converters
+{
+ public class ScrollViewerThumbSizeConverter : IMultiValueConverter
+ {
+ public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ double scroll_viewer_height = (double)values[0];
+ double content_height = (double)values[1];
+
+ var viewableRatio = scroll_viewer_height / content_height;
+ return scroll_viewer_height * viewableRatio;
+ }
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.Touch/Tango.Touch.csproj b/Software/Visual_Studio/Tango.Touch/Tango.Touch.csproj
index d86cedc83..00f8b65fb 100644
--- a/Software/Visual_Studio/Tango.Touch/Tango.Touch.csproj
+++ b/Software/Visual_Studio/Tango.Touch/Tango.Touch.csproj
@@ -174,6 +174,8 @@
<Compile Include="Converters\NotZeroConverter.cs" />
<Compile Include="Converters\RotateTransformCentreConverter.cs" />
<Compile Include="Converters\RotateTransformConverter.cs" />
+ <Compile Include="Converters\ScrollViewerScrollBarVisibilityConverter.cs" />
+ <Compile Include="Converters\ScrollViewerThumbSizeConverter.cs" />
<Compile Include="Converters\SizeToRectConverter.cs" />
<Compile Include="Converters\StartPointConverter.cs" />
<Compile Include="Converters\WidthHeightToRectConverter.cs" />
diff --git a/Software/Visual_Studio/Utilities/Tango.UITests/MainWindow.xaml b/Software/Visual_Studio/Utilities/Tango.UITests/MainWindow.xaml
index cfea9140c..df8073e23 100644
--- a/Software/Visual_Studio/Utilities/Tango.UITests/MainWindow.xaml
+++ b/Software/Visual_Studio/Utilities/Tango.UITests/MainWindow.xaml
@@ -10,7 +10,7 @@
xmlns:keyboard="clr-namespace:Tango.Touch.Keyboard;assembly=Tango.Touch"
xmlns:touch="clr-namespace:Tango.Touch.Controls;assembly=Tango.Touch"
mc:Ignorable="d"
- Title="MainWindow" Height="800" Width="800" DataContext="{Binding RelativeSource={RelativeSource Self}}" Background="{StaticResource TangoMidBackgroundBrush}">
+ Title="MainWindow" Height="1000" Width="800" DataContext="{Binding RelativeSource={RelativeSource Self}}" Background="{StaticResource TangoMidBackgroundBrush}">
<Grid>