From 26cee052a5b20d7a5bdb597776c55dcd3da2da62 Mon Sep 17 00:00:00 2001 From: Roy Ben-Shabat Date: Thu, 23 May 2019 16:44:30 +0300 Subject: Implemented new Twine color catalog ! --- .../Controls/TwineCatalogControl.xaml | 39 ++- .../Controls/TwineCatalogControl.xaml.cs | 97 +++--- .../Controls/TwineCatalogRenderer.cs | 342 +++++++++++++++++++++ .../PPC/Tango.PPC.Common/Tango.PPC.Common.csproj | 3 +- 4 files changed, 418 insertions(+), 63 deletions(-) create mode 100644 Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/TwineCatalogRenderer.cs (limited to 'Software/Visual_Studio/PPC/Tango.PPC.Common') diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/TwineCatalogControl.xaml b/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/TwineCatalogControl.xaml index 93af8965a..65db9818c 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/TwineCatalogControl.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/TwineCatalogControl.xaml @@ -14,20 +14,21 @@ - + - - - - - - - + + + + + + + + + + --> + + + --> + + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/TwineCatalogControl.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/TwineCatalogControl.xaml.cs index e23c629c5..af5888f3f 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/TwineCatalogControl.xaml.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/TwineCatalogControl.xaml.cs @@ -47,20 +47,22 @@ namespace Tango.PPC.Common.Controls { InitializeComponent(); - list.ApplyTemplate(); - list.Loaded += TwineCatalogControl_Loaded; + //list.ApplyTemplate(); + //list.Loaded += TwineCatalogControl_Loaded; DataContextChanged += (x, y) => { _catalog = DataContext as Catalog; - //if (list.ScrollViewer != null && _catalog != null) - //{ - // list.ScrollViewer.ScrollToTop(); - // _preventChange = true; - // slider.Value = _catalog.Groups.Count; - // _preventChange = false; - //} + if (scrollViewer != null && _catalog != null) + { + scrollViewer.ScrollToTop(); + _preventChange = true; + slider.Value = _catalog.Groups.Count; + _preventChange = false; + } }; + + scrollViewer.Scrolling += ScrollViewer_Scrolling; } /// @@ -70,22 +72,22 @@ namespace Tango.PPC.Common.Controls /// The instance containing the event data. private void ScrollViewer_Scrolling(object sender, Touch.Controls.DoubleValueChangedEventArgs e) { - //if (!_preventChange) - //{ - // if (e.Value > _lastScrollPosition + 60 || e.Value < _lastScrollPosition - 60) - // { - // var group = list.ScrollViewer.GetMostVisibleElementDataContext(); - - // if (group != null) - // { - // _preventChange = true; - // slider.Value = slider.Maximum - _catalog.Groups.IndexOf(group); - // _preventChange = false; - // } - - // _lastScrollPosition = e.Value; - // } - //} + if (!_preventChange) + { + if (e.Value > _lastScrollPosition + 60 || e.Value < _lastScrollPosition - 60) + { + var group = renderer.GetVisibleGroup(); + + if (group != null) + { + _preventChange = true; + slider.Value = slider.Maximum - _catalog.Groups.IndexOf(group); + _preventChange = false; + } + + _lastScrollPosition = e.Value; + } + } } /// @@ -113,22 +115,23 @@ namespace Tango.PPC.Common.Controls /// The instance containing the event data. private void TouchSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { - //if (_catalog == null || _catalog.Groups.Count == 0) return; + if (_catalog == null || _catalog.Groups.Count == 0) return; - //if (!_preventChange) - //{ - // if (_catalog != null) - // { - // _preventChange = true; - // list.ScrollToItem(_catalog.Groups.ElementAt(_catalog.Groups.Count - 1 - (int)e.NewValue)); - // _preventChange = false; - // } - //} + if (!_preventChange) + { + if (_catalog != null) + { + _preventChange = true; + var group = _catalog.Groups.ElementAt(_catalog.Groups.Count - 1 - (int)e.NewValue); + scrollViewer.ScrollToPosition(renderer.GetGroupPosition(group)); + _preventChange = false; + } + } - //if (_catalog != null && _catalog.Groups.Count > _catalog.Groups.Count - 1 - (int)e.NewValue && _catalog.Groups.Count - 1 - (int)e.NewValue > -1) - //{ - // slider.Foreground = new SolidColorBrush(_catalog.Groups.ElementAt(_catalog.Groups.Count - 1 - (int)e.NewValue).Color); - //} + if (_catalog != null && _catalog.Groups.Count > _catalog.Groups.Count - 1 - (int)e.NewValue && _catalog.Groups.Count - 1 - (int)e.NewValue > -1) + { + slider.Foreground = new SolidColorBrush(_catalog.Groups.ElementAt(_catalog.Groups.Count - 1 - (int)e.NewValue).Color); + } } /// @@ -136,14 +139,14 @@ namespace Tango.PPC.Common.Controls /// private void OnSelectedItemChanged() { - if (!_preventChange) - { - _preventChange = true; - var item = SelectedItem; - SelectedItem = null; - SelectedItem = item; - _preventChange = false; - } + //if (!_preventChange) + //{ + // _preventChange = true; + // var item = SelectedItem; + // SelectedItem = null; + // SelectedItem = item; + // _preventChange = false; + //} } /// diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/TwineCatalogRenderer.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/TwineCatalogRenderer.cs new file mode 100644 index 000000000..7a8ddbb46 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Controls/TwineCatalogRenderer.cs @@ -0,0 +1,342 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using Tango.BL.Catalogs; +using Tango.Touch.Controls; + +namespace Tango.PPC.Common.Controls +{ + public class TwineCatalogRenderer : FrameworkElement + { + private class ItemContainer + { + public DrawingVisual Visual { get; set; } + public CatalogItem Item { get; set; } + public double PositionY { get; set; } + } + + private class GroupContainer + { + public DrawingVisual Visual { get; set; } + public CatalogGroup Group { get; set; } + public double PositionY { get; set; } + + public List Items { get; set; } + + public GroupContainer() + { + Items = new List(); + } + } + + private readonly VisualCollection _children; + private List _catalogItems; + private List _groupItems; + private double ellipseWidth = 60; + private double ellipseHeight = 60; + private double textHeight = 30; + private double ellipseMargin = 20; + private double textMargin = 5; + private double groupMargin = 60; + private bool selectedFromClick; + private LightTouchScrollViewer _scrollViewer; + + public List Groups + { + get { return (List)GetValue(GroupsProperty); } + set { SetValue(GroupsProperty, value); } + } + public static readonly DependencyProperty GroupsProperty = + DependencyProperty.Register("Groups", typeof(List), typeof(TwineCatalogRenderer), new PropertyMetadata(null, (d, e) => { (d as TwineCatalogRenderer).OnCatalogChanged(); })); + + public CatalogItem SelectedItem + { + get { return (CatalogItem)GetValue(SelectedItemProperty); } + set { SetValue(SelectedItemProperty, value); } + } + public static readonly DependencyProperty SelectedItemProperty = + DependencyProperty.Register("SelectedItem", typeof(CatalogItem), typeof(TwineCatalogRenderer), new PropertyMetadata(null, (d, e) => (d as TwineCatalogRenderer).OnSelectedItemChanged(e.OldValue, e.NewValue))); + + public Brush Foreground + { + get { return (Brush)this.GetValue(ForegroundProperty); } + set { this.SetValue(ForegroundProperty, value); } + } + public static readonly DependencyProperty ForegroundProperty = + TextBlock.ForegroundProperty.AddOwner(typeof(TwineCatalogRenderer)); + + public Brush Background + { + get { return (Brush)GetValue(BackgroundProperty); } + set { SetValue(BackgroundProperty, value); } + } + public static readonly DependencyProperty BackgroundProperty = + DependencyProperty.Register("Background", typeof(Brush), typeof(TwineCatalogRenderer), new PropertyMetadata(null)); + + + public TwineCatalogRenderer() + { + Background = new SolidColorBrush(Colors.White); + + _children = new VisualCollection(this); + _catalogItems = new List(); + _groupItems = new List(); + + this.PreviewMouseUp += TwineCatalogRenderer_MouseLeftButtonUp; + this.Loaded += TwineCatalogRenderer_Loaded; + } + + private void TwineCatalogRenderer_Loaded(object sender, RoutedEventArgs e) + { + _scrollViewer = this.FindAncestor(); + } + + public CatalogGroup GetVisibleGroup() + { + double currentPosition = _scrollViewer.GetScrollPosition(); + + var viewportRect = _scrollViewer.GetViewPortRect(); + + foreach (var group in _groupItems.Where(x => x.Items.Count > 0).Reverse().ToList()) + { + var groupRect = GetGroupRect(group); + + if (groupRect.IntersectsWith(viewportRect)) + { + return group.Group; + } + } + + return null; + } + + public double GetGroupPosition(CatalogGroup group) + { + return _groupItems.Single(x => x.Group == group).PositionY; + } + + private Rect GetGroupRect(GroupContainer group) + { + var height = group.Items.Last().PositionY - group.PositionY; + return new Rect(0, group.PositionY + (height / 4), ActualWidth, height); + } + + private void TwineCatalogRenderer_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + + if (!_scrollViewer.IsAfterScrolling) + { + // Retreive the coordinates of the mouse button event. + Point pt = e.GetPosition((UIElement)this); + + // Initiate the hit test by setting up a hit test result callback method. + VisualTreeHelper.HitTest(this, null, HitTestCallback, new PointHitTestParameters(pt)); + } + } + + // If a child visual object is hit, toggle its opacity to visually indicate a hit. + public HitTestResultBehavior HitTestCallback(HitTestResult result) + { + if (result.VisualHit.GetType() == typeof(System.Windows.Media.DrawingVisual)) + { + var visual = result.VisualHit as DrawingVisual; + + if (visual != null) + { + var container = _catalogItems.SingleOrDefault(x => x.Visual == visual); + + if (container != null && container.Item is CatalogItem) + { + selectedFromClick = true; + SelectedItem = container.Item; + selectedFromClick = false; + } + } + } + + // Stop the hit test enumeration of objects in the visual tree. + return HitTestResultBehavior.Stop; + } + + private void OnSelectedItemChanged(object oldValue, object newValue) + { + var newItem = _catalogItems.SingleOrDefault(x => x.Item == newValue); + var oldItem = _catalogItems.SingleOrDefault(x => x.Item == oldValue); + + if (newItem != null) + { + (newItem.Visual.Transform as ScaleTransform).ScaleX = 1.3; + (newItem.Visual.Transform as ScaleTransform).ScaleY = 1.3; + + if (!selectedFromClick) + { + _scrollViewer.ScrollToPosition(newItem.PositionY - _scrollViewer.ActualHeight / 2); + } + } + + if (oldItem != null) + { + (oldItem.Visual.Transform as ScaleTransform).ScaleX = 1; + (oldItem.Visual.Transform as ScaleTransform).ScaleY = 1; + } + } + + private ItemContainer AddCatalogItem(DrawingVisual visual, CatalogItem item, double y) + { + _children.Add(visual); + + var container = new ItemContainer() + { + Visual = visual, + Item = item, + PositionY = y, + }; + + _catalogItems.Add(container); + + return container; + } + + private GroupContainer AddGroupItem(DrawingVisual visual, CatalogGroup group, double y) + { + _children.Add(visual); + + var container = new GroupContainer() + { + Visual = visual, + Group = group, + PositionY = y, + }; + + _groupItems.Add(container); + + return container; + } + + private void OnCatalogChanged() + { + _children.Clear(); + _catalogItems.Clear(); + _groupItems.Clear(); + + double position_y = 0; + double position_x = 0; + + if (Groups != null) + { + foreach (var group in Groups) + { + position_x = 0; + + var groupContainer = AddGroupItem(CreateGroup(group.Name, position_y), group, position_y); + + position_y += ellipseMargin; + + foreach (var item in group.Items) + { + double x = position_x + ellipseMargin; + + if (x + ellipseWidth > ActualWidth) + { + position_x = 0; + position_y += (ellipseHeight + ellipseMargin + textMargin + textHeight); + } + + var itemContainer = AddCatalogItem(CreateItem(item, position_x + ellipseMargin, position_y + ellipseMargin), item, position_y + ellipseMargin); + groupContainer.Items.Add(itemContainer); + + position_x += ellipseWidth + ellipseMargin; + } + + position_y += (ellipseHeight + ellipseMargin + textMargin + textHeight + groupMargin); + } + + Height = position_y; + } + + //InvalidateVisual(); + } + + private DrawingVisual CreateItem(CatalogItem item, double x, double y) + { + DrawingVisual drawingVisual = new DrawingVisual(); + DrawingContext drawingContext = drawingVisual.RenderOpen(); + + drawingContext.DrawEllipse(item.Brush, null, new Point(x + ellipseWidth / 2, y + ellipseHeight / 2), ellipseWidth / 2, ellipseHeight / 2); + + var formattedText = new FormattedText(item.Name, + CultureInfo.GetCultureInfo("en-us"), + FlowDirection.LeftToRight, + new Typeface("Flexo"), + 16, + Foreground); + + formattedText.MaxTextWidth = ellipseWidth + ellipseMargin; + + drawingContext.DrawText(formattedText, new Point((x + (ellipseWidth / 2)) - (formattedText.Width / 2), y + ellipseHeight + textMargin)); + + var center = new Point(x + ellipseWidth / 2, (y + ellipseHeight / 2) + textHeight + textMargin); + + drawingVisual.Transform = new ScaleTransform(1, 1, center.X, center.Y); + + drawingContext.Close(); + + return drawingVisual; + } + + private void Clear() + { + DrawingVisual drawingVisual = new DrawingVisual(); + DrawingContext drawingContext = drawingVisual.RenderOpen(); + + drawingContext.DrawRectangle(Background, null, new Rect(0, 0, ActualWidth, ActualHeight)); + + drawingContext.Close(); + + _children.Add(drawingVisual); + } + + private DrawingVisual CreateGroup(String name, double y) + { + DrawingVisual drawingVisual = new DrawingVisual(); + DrawingContext drawingContext = drawingVisual.RenderOpen(); + + var formattedText = new FormattedText(name, + CultureInfo.GetCultureInfo("en-us"), + FlowDirection.LeftToRight, + new Typeface("Flexo"), + 25, + Foreground); + + //formattedText.SetFontWeight(FontWeights.SemiBold); + + drawingContext.DrawText(formattedText, new Point((ActualWidth / 2) - (formattedText.Width / 2), y)); + + drawingContext.Close(); + + return drawingVisual; + } + + // Provide a required override for the VisualChildrenCount property. + protected override int VisualChildrenCount => _children != null ? _children.Count : 0; + + // Provide a required override for the GetVisualChild method. + protected override Visual GetVisualChild(int index) + { + if (index < 0 || index >= _children.Count) + { + throw new ArgumentOutOfRangeException(); + } + + return _children[index]; + } + } +} diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj b/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj index 62874d9cb..c5faaa28b 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj @@ -131,6 +131,7 @@ TwineCatalogControl.xaml + @@ -372,7 +373,7 @@ - + \ No newline at end of file -- cgit v1.3.1