aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/TextLayer.cs
blob: 3f4b8299be88d1135723c325c47e6dc8dbb723a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// 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;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

namespace Tango.Scripting.Editors.Rendering
{
	/// <summary>
	/// The control that contains the text.
	/// 
	/// This control is used to allow other UIElements to be placed inside the TextView but
	/// behind the text.
	/// The text rendering process (VisualLine creation) is controlled by the TextView, this
	/// class simply displays the created Visual Lines.
	/// </summary>
	/// <remarks>
	/// This class does not contain any input handling and is invisible to hit testing. Input
	/// is handled by the TextView.
	/// This allows UIElements that are displayed behind the text, but still can react to mouse input.
	/// </remarks>
	sealed class TextLayer : Layer
	{
		/// <summary>
		/// the index of the text layer in the layers collection
		/// </summary>
		internal int index;
		
		public TextLayer(TextView textView) : base(textView, KnownLayer.Text)
		{
		}
		
		List<VisualLineDrawingVisual> visuals = new List<VisualLineDrawingVisual>();
		
		internal void SetVisualLines(ICollection<VisualLine> visualLines)
		{
			foreach (VisualLineDrawingVisual v in visuals) {
				if (v.VisualLine.IsDisposed)
					RemoveVisualChild(v);
			}
			visuals.Clear();
			foreach (VisualLine newLine in visualLines) {
				VisualLineDrawingVisual v = newLine.Render();
				if (!v.IsAdded) {
					AddVisualChild(v);
					v.IsAdded = true;
				}
				visuals.Add(v);
			}
			InvalidateArrange();
		}
		
		protected override int VisualChildrenCount {
			get { return visuals.Count; }
		}
		
		protected override Visual GetVisualChild(int index)
		{
			return visuals[index];
		}
		
		protected override void ArrangeCore(Rect finalRect)
		{
			textView.ArrangeTextLayer(visuals);
		}
	}
}
.sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.Core;
using Tango.Core.Commands;
using Tango.Core.DI;
using Tango.MachineStudio.Common;
using Tango.MachineStudio.Common.Modules;
using Tango.MachineStudio.Common.Navigation;
using Tango.MachineStudio.Common.Threading;
using Tango.SharedUI.Controls;

namespace Tango.MachineStudio.UI.Navigation
{
    /// <summary>
    /// Represents the Machine Studio default <see cref="INavigationManager">Navigation Manager</see>.
    /// </summary>
    /// <seealso cref="Tango.MachineStudio.Common.Navigation.INavigationManager" />
    public class DefaultNavigationManager : ExtendedObject, INavigationManager
    {
        private event Action<Object, Object> NavigationCycleCompleted;

        private IDispatcherProvider _dispatcherProvider;
        private IStudioModuleLoader _moduleLoader;
        private Object _currentVM;
        private String _lastFullPath;
        private bool _preventHistory;
        private bool _navigating_back;

        private Stack<String> _navigationHistory;

        /// <summary>
        /// Gets the current view model.
        /// </summary>
        public StudioViewModel CurrentVM
        {
            get { return _currentVM as StudioViewModel; }
        }

        private IStudioModule _currentModule;
        /// <summary>
        /// Gets or sets the current module.
        /// </summary>
        public IStudioModule CurrentModule
        {
            get { return _currentModule; }
            private set { _currentModule = value; RaisePropertyChangedAuto(); }
        }

        /// <summary>
        /// Navigates to the previous view.
        /// </summary>
        public RelayCommand NavigateBackCommand { get; private set; }

        /// <summary>
        /// Navigates to the specified full path in command parameter.
        /// </summary>
        public RelayCommand<String> NavigateToCommand { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="DefaultNavigationManager"/> class.
        /// </summary>
        /// <param name="moduleLoader">The module loader.</param>
        public DefaultNavigationManager(IStudioModuleLoader moduleLoader, IDispatcherProvider dispatcherProvider)
        {
            _navigationHistory = new Stack<String>();
            _moduleLoader = moduleLoader;

            NavigateToCommand = new RelayCommand<string>(async (x) => await NavigateTo(x));
            NavigateBackCommand = new RelayCommand(async () => await NavigateBack());

            _dispatcherProvider = dispatcherProvider;
        }

        /// <summary>
        /// Navigates to the specified PPC view.
        /// </summary>
        /// <param name="view">The view.</param>
        public Task<bool> NavigateTo(NavigationView view, bool pushToHistory = true)
        {
            LogManager.Log($"Navigating to: {view.ToString()}...");

            _dispatcherProvider.Invoke(() =>
            {
                MainWindow.Instance.NavigationControl.NavigateTo(view.ToString());
            });

            return Task.FromResult(true);
        }

        /// <summary>
        /// Navigates to the specified PPC view with the specified receive object.
        /// </summary>
        /// <param name="view">The view.</param>
        /// <param name="obj"></param>
        /// <param name="pushToHistory"></param>
        /// <returns></returns>
        public Task<bool> NavigateWithObject<TPass>(NavigationView view, TPass obj, bool pushToHistory = true)
        {
            LogManager.Log($"Navigating to: {view.ToString()}, with object {typeof(TPass).Name}...");
            MainWindow.Instance.NavigationControl.NavigateTo(view.ToString());
            INavigationObjectReceiver<TPass> receiver = MainWindow.Instance.NavigationControl.Elements.FirstOrDefault(x => (x.GetType().Name == view.ToString() || NavigationControl.GetNavigationName(x) == view.ToString()) && x.DataContext is INavigationObjectReceiver<TPass>).DataContext as INavigationObjectReceiver<TPass>;

            if (receiver != null)
            {
                receiver.OnNavigatedToWithObject(obj);
            }

            return Task.FromResult(true);
        }

        /// <summary>
        /// Navigates to the specified module.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public Task<bool> NavigateTo<T>(bool pushToHistory = true) where T : IStudioModule
        {
            return NavigateTo(typeof(T));
        }

        /// <summary>
        /// Navigates to the specified module using the view path (e.g MainView.JobsView).
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="viewPath">The view path.</param>
        public Task<bool> NavigateTo<T>(string viewPath, bool pushToHistory = true) where T : IStudioModule
        {
            return NavigateTo<T>(pushToHistory, viewPath.Split('.'));
        }

        /// <summary>
        /// Navigates to the specified module using the view path (e.g MainView,JobsView).
        /// This method makes it easy to do stuff like NavigateTo(nameof(MainView),nameof(JobsView));
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="viewPath">The view path.</param>
        public Task<bool> NavigateTo<T>(bool pushToHistory = true, params String[] viewPath) where T : IStudioModule
        {
            return NavigateTo(typeof(T), pushToHistory, viewPath);
        }

        /// <summary>
        /// Navigates to the specified module and view by full path (e.g Jobs.JobsView).
        /// </summary>
        /// <param name="fullPath">The full path.</param>
        public async Task<bool> NavigateTo(String fullPath, bool pushToHistory = true)
        {
            String[] path = fullPath.Split('.');
            var module = _moduleLoader.UserModules.SingleOrDefault(x => x.GetType().Name == path[0] || x.Name == path[0]);

            if (path.Length == 1 && path[0] == CurrentModule.Name) return true;

            LogManager.Log($"Navigating to: {fullPath}...");

            var fromVM = _currentVM;

            if (_currentVM != null && _currentVM is INavigationBlocker)
            {
                if (_navigating_back)
                {
                    if (!await (_currentVM as INavigationBlocker).OnNavigateBackRequest())
                    {
                        return false;
                    }
                }
                else
                {
                    if (!await (_currentVM as INavigationBlocker).OnNavigateOutRequest())
                    {
                        return false;
                    }
                }
            }

            if (pushToHistory && _lastFullPath != null && !_preventHistory)
            {
                _navigationHistory.Push(_lastFullPath);
                RaisePropertyChanged(nameof(CanNavigateBack));
            }

            _lastFullPath = fullPath;

            MainWindow.Instance.NavigationControl.NavigateTo(NavigationView.MainView.ToString());
            var navigationControl = MachineStudio.UI.Views.MainView.Instance.NavigationControl;
            CurrentModule = module;
            var moduleView = navigationControl.NavigateTo(module.Name);

            _currentVM = moduleView.DataContext;

            if (path.Length > 1)
            {
                var moduleNavigation = moduleView.FindChildOffline<NavigationControl>();

                moduleNavigation.RegisterForLoadedOrNow(async (x, e) =>
                {
                    foreach (var view in path.Skip(1))
                    {
                        await Task.Delay(100);
                        var v = moduleNavigation.NavigateTo(view);

                        if (v != null)
                        {
                            _currentVM = v.DataContext;

                            if (view != path.Last())
                            {
                                moduleNavigation = v.FindChildOffline<NavigationControl>();
                            }
                        }
                        else
                        {
                            throw LogManager.Log(new ArgumentNullException("Could not navigate to " + fullPath));
                        }
                    }

                    NavigationCycleCompleted?.Invoke(fromVM, _currentVM);
                });
            }

            return true;
        }

        /// <summary>
        /// Navigates for result.
        /// </summary>
        /// <typeparam name="TModule">The type of the module.</typeparam>
        /// <typeparam name="TView">The type of the view.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <typeparam name="TObject">The type of the object.</typeparam>
        /// <param name="obj">The object.</param>
        /// <param name="pushToHistory">if set to <c>true</c> [push to history].</param>
        /// <returns></returns>
        public Task<TResult> NavigateForResult<TModule, TView, TResult, TObject>(TObject obj, bool pushToHistory = true)
               where TModule : IStudioModule
        {
            TaskCompletionSource<TResult> source = new TaskCompletionSource<TResult>();

            var fromVM = _currentVM;
            Object toVM = null;


            Action<Object, Object> handler = null;

            handler = (from, to) =>
            {
                if (toVM == null)
                {
                    toVM = to;
                    if (toVM is INavigationResultProvider<TResult, TObject>)
                    {
                        (toVM as INavigationResultProvider<TResult, TObject>).OnNavigationObjectReceived(obj);
                    }
                }
                else
                {
                    if (to == fromVM && from == toVM)
                    {
                        if (from is INavigationResultProvider<TResult, TObject>)
                        {
                            source.SetResult((from as INavigationResultProvider<TResult, TObject>).GetNavigationResult());
                        }
                    }

                    NavigationCycleCompleted -= handler;
                }
            };

            NavigationCycleCompleted += handler;

            NavigateTo<TModule>(typeof(TView).Name, pushToHistory);

            return source.Task;
        }

        /// <summary>
        /// Navigates to the specified module and view with the specified object.
        /// </summary>
        /// <typeparam name="TModule">The type of the module.</typeparam>
        /// <typeparam name="TView">The type of the view.</typeparam>
        /// <typeparam name="TPass">The type of the pass.</typeparam>
        /// <param name="obj">The object.</param>
        /// <param name="pushToHistory">if set to <c>true</c> [push to history].</param>
        /// <returns></returns>
        public Task<bool> NavigateWithObject<TModule, TView, TPass>(TPass obj, bool pushToHistory = true) where TModule : IStudioModule
        {
            TaskCompletionSource<bool> source = new TaskCompletionSource<bool>();

            Action<Object, Object> handler = null;

            handler = (from, to) =>
            {
                if (to is INavigationObjectReceiver<TPass>)
                {
                    (to as INavigationObjectReceiver<TPass>).OnNavigatedToWithObject(obj);
                }

                NavigationCycleCompleted -= handler;
            };

            NavigationCycleCompleted += handler;

            NavigateTo<TModule>(typeof(TView).Name, pushToHistory);

            return source.Task;
        }

        private Task<bool> NavigateTo(Type moduleType, bool pushToHistory = true, params String[] viewPath)
        {
            if (viewPath != null && viewPath.Length > 0)
            {
                return NavigateTo(moduleType.Name + "." + String.Join(".", viewPath), pushToHistory);
            }
            else
            {
                return NavigateTo(moduleType.Name, pushToHistory);
            }
        }

        /// <summary>
        /// Gets a value indicating whether the navigation system is able to navigate to the previous view.
        /// </summary>
        public bool CanNavigateBack
        {
            get { return _navigationHistory.Count > 0; }
        }

        /// <summary>
        /// Navigates to the previous view if <see cref="P:Tango.PPC.Common.Navigation.INavigationManager.CanNavigateBack" /> is true.
        /// </summary>
        public async Task<bool> NavigateBack()
        {
            LogManager.Log("Navigating back...");

            _navigating_back = true;

            String first = _navigationHistory.Pop();
            _preventHistory = true;


            if (await NavigateTo(first))
            {
                RaisePropertyChanged(nameof(CanNavigateBack));
                _preventHistory = false;
                _navigating_back = false;
                return true;
            }
            else
            {
                _navigationHistory.Push(first);
                _preventHistory = false;
                _navigating_back = false;
                RaisePropertyChanged(nameof(CanNavigateBack));
                return false;
            }
        }

        /// <summary>
        /// Clears the navigation back history.
        /// </summary>
        public void ClearHistory()
        {
            LogManager.Log("Navigation history cleared.");
            _navigationHistory.Clear();
            RaisePropertyChanged(nameof(CanNavigateBack));
        }

        /// <summary>
        /// Clears the navigation back history except the specified view type.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void ClearHistoryExcept<T>()
        {
            LogManager.Log($"Navigation history cleared except for {typeof(T).Name}.");

            var history_list = _navigationHistory.ToList();
            history_list = history_list.Where(x => x.Contains(typeof(T).Name)).Distinct().ToList();
            _navigationHistory.Clear();

            foreach (var item in history_list)
            {
                _navigationHistory.Push(item);
            }

            RaisePropertyChanged(nameof(CanNavigateBack));
        }

        public void NavigateToModule<T>() where T : IStudioModule
        {
            var loader = TangoIOC.Default.GetInstance<IStudioModuleLoader>();
            var module = loader.UserModules.SingleOrDefault(x => x.GetType() == typeof(T));

            if (module != null)
            {
                TangoIOC.Default.GetInstance<ViewModels.MainViewVM>().StartModule(module);
            }
        }
    }
}