aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/SideChains/ICSharpCode.AvalonEdit/Utils/Boxes.cs
blob: 4a50f11ceeb708db27ffe613755afeac22c6c405 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)

using System;

namespace ICSharpCode.AvalonEdit.Utils
{
	/// <summary>
	/// Reuse the same instances for boxed booleans.
	/// </summary>
	static class Boxes
	{
		public static readonly object True = true;
		public static readonly object False = false;
		
		public static object Box(bool value)
		{
			return value ? True : False;
		}
	}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using Tango.Core.Commands;
using Tango.Core.EventArguments;
using Tango.Core.ExtensionMethods;

namespace Tango.Touch.Controls
{
    public class TouchNotificationBar : ContentControl
    {
        private const double HEIGHT_RATIO = 0.75;
        private const double DRAGPATH_HEIGH = 20.0;

        private bool _isMouseDown;
        private Point _mouseDownLocation;
        private bool _isMoving;
        private Point _downLocation;
        private TouchDevice _touchDevice;
        private double _last_manipulation_delta;
        private DateTime _last_delta_measure_time;
        private double _last_mouse_y;



        private Border _border_notifications;
        private Border _border_drag;
        private Grid _grid_container;
        private Grid _grid_mask;
        private ItemsControl _items_control;
        private Grid _notification_counter_grid;
        private LightTouchScrollViewer _scrollViewer;



        #region Dep_Properties

        public bool HasNotifications
        {
            get { return (bool)GetValue(HasNotificationsProperty); }
            set { SetValue(HasNotificationsProperty, value); }
        }
        public static readonly DependencyProperty HasNotificationsProperty =
            DependencyProperty.Register("HasNotifications", typeof(bool), typeof(TouchNotificationBar), new PropertyMetadata(false, (d, e) => (d as TouchNotificationBar).OnHasNotificationsChanged()));

        public IList Notifications
        {
            get { return (IList)GetValue(NotificationsProperty); }
            set { SetValue(NotificationsProperty, value); }
        }
        public static readonly DependencyProperty NotificationsProperty =
            DependencyProperty.Register("Notifications", typeof(IList), typeof(TouchNotificationBar), new PropertyMetadata(null, (d, e) => (d as TouchNotificationBar).OnNotificationsChanged()));

        public DataTemplate NotificationTemplate
        {
            get { return (DataTemplate)GetValue(NotificationTemplateProperty); }
            set { SetValue(NotificationTemplateProperty, value); }
        }
        public static readonly DependencyProperty NotificationTemplateProperty =
            DependencyProperty.Register("NotificationTemplate", typeof(DataTemplate), typeof(TouchNotificationBar), new PropertyMetadata(null));

        public double CurrentMinHeight
        {
            get { return (double)GetValue(CurrentMinHeightProperty); }
            set { SetValue(CurrentMinHeightProperty, value); }
        }
        public static readonly DependencyProperty CurrentMinHeightProperty =
            DependencyProperty.Register("CurrentMinHeight", typeof(double), typeof(TouchNotificationBar), new PropertyMetadata(0.0));

        public bool IsExpanded
        {
            get { return (bool)GetValue(IsExpandedProperty); }
            set { SetValue(IsExpandedProperty, value); }
        }
        public static readonly DependencyProperty IsExpandedProperty =
            DependencyProperty.Register("IsExpanded", typeof(bool), typeof(TouchNotificationBar), new PropertyMetadata(false));

        public RelayCommand NotificationPressedCommand
        {
            get { return (RelayCommand)GetValue(NotificationPressedCommandProperty); }
            set { SetValue(NotificationPressedCommandProperty, value); }
        }
        public static readonly DependencyProperty NotificationPressedCommandProperty =
            DependencyProperty.Register("NotificationPressedCommand", typeof(RelayCommand), typeof(TouchNotificationBar), new PropertyMetadata(null));

        public Visibility NotificationBarVisibility
        {
            get { return (Visibility)GetValue(NotificationBarVisibilityProperty); }
            set { SetValue(NotificationBarVisibilityProperty, value); }
        }
        public static readonly DependencyProperty NotificationBarVisibilityProperty =
            DependencyProperty.Register("NotificationBarVisibility", typeof(Visibility), typeof(TouchNotificationBar), new PropertyMetadata(Visibility.Visible));

        #endregion

        #region constructors

        static TouchNotificationBar()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TouchNotificationBar), new FrameworkPropertyMetadata(typeof(TouchNotificationBar)));
        }
        public TouchNotificationBar()
        {
            IsExpanded = false;
            Loaded += TouchNotificationBar_Loaded;

            NotificationPressedCommand = new RelayCommand(() =>
            {
                if (IsExpanded && !_scrollViewer.IsAfterScrolling)
                {
                    CloseNotifications();
                }
            });
        }

        #endregion


        #region Override_Base

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _border_notifications = GetTemplateChild("PART_BorderNotifications") as Border;
            _border_drag = GetTemplateChild("PART_BorderDrag") as Border;
            _grid_container = GetTemplateChild("PART_Grid_Container") as Grid;
            _grid_mask = GetTemplateChild("PART_GridMask") as Grid;
            _items_control = GetTemplateChild("PART_ItemsControl") as ItemsControl;
            _notification_counter_grid = GetTemplateChild("PART_NotificationCounterGrid") as Grid;
            _scrollViewer = GetTemplateChild("PART_ScrollViewer") as LightTouchScrollViewer;
            
            _border_drag.RegisterForPreviewMouseOrTouchDown(GridNotificationMouseDown);
            _border_drag.RegisterForMouseOrTouchMove(GridNotificationMouseMove);
            _border_drag.RegisterForPreviewMouseOrTouchUp(GridNotificationMouseUp);
            _border_drag.SizeChanged += Drag_Border_SizeChanged;

        }

        #endregion


        private FrameworkElement GetLastNotification()
        {
            return _items_control.ItemContainerGenerator.ContainerFromIndex(0) as FrameworkElement;
        }

        private void TouchNotificationBar_Loaded(object sender, RoutedEventArgs e)
        {
            _border_drag.MaxHeight = ActualHeight;
        }
        private void Drag_Border_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            _grid_mask.Opacity = _border_drag.ActualHeight / ActualHeight;

            if (e.NewSize.Height > CurrentMinHeight && CurrentMinHeight > 0 )
            {
                _notification_counter_grid.Visibility = Visibility.Hidden;
            }
            else if(Notifications.Count > 1 && CurrentMinHeight > 0)
            {
                _notification_counter_grid.Visibility = Visibility.Visible;
            }
        }

        /// <summary>
        /// Called when has notifications items or all items removed
        /// </summary>
        private void OnHasNotificationsChanged()
        {
            if (HasNotifications)
            {
                UpdateMinHeightByDispalyedItem();
            }
            else
            {
                CurrentMinHeight = 0;
                if (IsExpanded)
                {
                    CloseNotifications();
                }
                _border_notifications.Height = CurrentMinHeight;
                _grid_container.MinHeight = 0;
                _grid_container.Height = 0;
            }
        }

        private void UpdateMinHeightByDispalyedItem()
        {
            var last = GetLastNotification();
            if(last != null)
            {
                last.RegisterForLoadedOrNow((x, y) =>
                {
                    CurrentMinHeight = last.ActualHeight;
                    _border_notifications.Height = last.ActualHeight;
                    _grid_container.MinHeight = last.ActualHeight;
                    _grid_container.Height = CurrentMinHeight;
                });
            }
        }
            /// <summary>
            /// Callback function on Notifications property
            /// </summary>
            private void OnNotificationsChanged()
        {
            if (Notifications is INotifyCollectionChanged)
            {
                (Notifications as INotifyCollectionChanged).CollectionChanged += (_, e) =>
                {
                    this.BeginInvoke(() =>
                    {
                        if(Notifications.Count > 0)
                        {
                            UpdateMinHeightByDispalyedItem();
                        }
                        if (IsExpanded == false && Notifications.Count > 1)
                        {
                            _notification_counter_grid.Visibility = Visibility.Visible;
                        }
                        else
                        {
                            _notification_counter_grid.Visibility = Visibility.Hidden;
                        }
                    });
                }; 
                
            }
        }
        
        #region Mouse handlers
        private void OpenNotifications()
        {
            _border_drag.StartDoubleAnimation(Border.HeightProperty, TimeSpan.FromSeconds(0.2), _border_drag.MaxHeight, null, null, 1, () =>
            {
                IsExpanded = true;
            });
            _border_notifications.StartDoubleAnimation(Border.HeightProperty, TimeSpan.FromSeconds(0.2), ActualHeight * HEIGHT_RATIO, null, null, 1);
        }

        private void CloseNotifications()
        {
            _border_notifications.StartDoubleAnimation(Border.HeightProperty, TimeSpan.FromSeconds(0.2), CurrentMinHeight, null, 1, null, () =>
              {
                  _border_notifications.BeginAnimation(Border.HeightProperty, null);
                  _border_notifications.Height = CurrentMinHeight;
              });

            _border_drag.StartDoubleAnimation(Border.HeightProperty, TimeSpan.FromSeconds(0.2), CurrentMinHeight, null, 1, null, () =>
            {
                _border_drag.BeginAnimation(Border.HeightProperty, null);
                _border_drag.Height = double.NaN;
            });

            ThicknessAnimation tAni = new ThicknessAnimation();
            tAni.Duration = TimeSpan.FromSeconds(0.3);
            tAni.To = new Thickness(0);
            _border_notifications.BeginAnimation(Border.BorderThicknessProperty, tAni);
            
            IsExpanded = false;

            Task.Delay(400).ContinueWith((x) =>
            {
                Dispatcher.BeginInvoke(new Action(() =>
                {
                    _scrollViewer.ScrollToTop();
                }));
            });
        }

        private void GridNotificationMouseUp(object sender, MouseOrTouchEventArgs e)
        {
            if (_isMouseDown)
            {
                _isMouseDown = false;

                if (_isMoving)
                {
                    if (_touchDevice != null)
                    {
                        _border_drag.ReleaseTouchCapture(_touchDevice);
                        _touchDevice = null;
                    }
                    else
                    {
                        _border_drag.ReleaseMouseCapture();
                    }

                    e.Handled = true;
                    _isMoving = false;

                    if ((e.GetPosition(this).Y > ActualHeight / 2 && _last_manipulation_delta > 0) || _last_manipulation_delta > 20)
                    {
                        OpenNotifications();
                    }
                    else if ((e.GetPosition(this).Y < ActualHeight / 2 && _last_manipulation_delta < 0) || _last_manipulation_delta < 20)
                    {
                        CloseNotifications();
                    }
                }

                _scrollViewer.DisableScrolling = false;
            }
        }

        private void GridNotificationMouseMove(object sender, MouseOrTouchEventArgs e)
        {
            if (_isMouseDown)
            {
                if (Math.Abs(e.Location.Y - _downLocation.Y) > 5)
                {
                    _isMoving = true;
                }

                if (_isMoving)
                {
                    DateTime curTime = DateTime.Now;

                    if (curTime > _last_delta_measure_time.AddMilliseconds(10))
                    {
                        _last_delta_measure_time = curTime;

                        double delta = e.Location.Y - _last_mouse_y;

                        if (delta != 0)
                        {
                            _last_manipulation_delta = delta;
                        }

                        _last_mouse_y = e.Location.Y;
                    }

                    if (e.TouchDevice != null)
                    {
                        _border_drag.CaptureTouch(e.TouchDevice);
                    }
                    else
                    {
                        Mouse.Capture(_border_drag);
                    }

                    _border_drag.Height = Math.Max(e.Location.Y + _mouseDownLocation.Y, CurrentMinHeight);
                    _border_notifications.Height = Math.Min(_border_drag.Height * HEIGHT_RATIO, ActualHeight * HEIGHT_RATIO);

                    _border_drag.BeginAnimation(Border.HeightProperty, null);
                    _border_notifications.BeginAnimation(Border.HeightProperty, null);

                    _border_notifications.BeginAnimation(Border.BorderThicknessProperty, null);

                    if (_border_notifications.ActualHeight > CurrentMinHeight)
                    {
                        _border_notifications.BorderThickness = new Thickness(0, 0, 0, DRAGPATH_HEIGH);
                    }
                    else
                    {
                        _border_notifications.BorderThickness = new Thickness(0);
                    }
                }
            }
        }

        private void GridNotificationMouseDown(object sender, MouseOrTouchEventArgs e)
        {
            if (!IsExpanded || e.OriginalSource == _border_drag || e.OriginalSource == _border_notifications)
            {
                _mouseDownLocation = new Point(e.Location.X, _border_drag.ActualHeight - e.Location.Y);
                _downLocation = e.Location;
                _last_mouse_y = _downLocation.Y;
                _last_delta_measure_time = DateTime.Now;
                _last_manipulation_delta = 0;
                _scrollViewer.DisableScrolling = true;
                _isMouseDown = true;
            }
        }

        #endregion
    }
}