You're breathtaking!
This commit is contained in:
199
Source/Editor/Surface/VisjectSurface.Context.cs
Normal file
199
Source/Editor/Surface/VisjectSurface.Context.cs
Normal file
@@ -0,0 +1,199 @@
|
||||
// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FlaxEditor.Surface
|
||||
{
|
||||
public partial class VisjectSurface
|
||||
{
|
||||
private VisjectSurfaceContext _root;
|
||||
private VisjectSurfaceContext _context;
|
||||
private readonly Dictionary<ISurfaceContext, VisjectSurfaceContext> _contextCache = new Dictionary<ISurfaceContext, VisjectSurfaceContext>();
|
||||
|
||||
/// <summary>
|
||||
/// The surface context stack.
|
||||
/// </summary>
|
||||
public readonly Stack<VisjectSurfaceContext> ContextStack = new Stack<VisjectSurfaceContext>(8);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the root surface context.
|
||||
/// </summary>
|
||||
public VisjectSurfaceContext RootContext => _root;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the active surface context.
|
||||
/// </summary>
|
||||
public VisjectSurfaceContext Context => _context;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when context gets changed.
|
||||
/// </summary>
|
||||
public event Action<VisjectSurfaceContext> ContextChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the Visject surface context for the given surface data source context.
|
||||
/// </summary>
|
||||
/// <param name="parent">The parent context.</param>
|
||||
/// <param name="context">The context.</param>
|
||||
/// <returns></returns>
|
||||
protected virtual VisjectSurfaceContext CreateContext(VisjectSurfaceContext parent, ISurfaceContext context)
|
||||
{
|
||||
return new VisjectSurfaceContext(this, parent, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the child context of the current context.
|
||||
/// </summary>
|
||||
/// <param name="context">The context.</param>
|
||||
public void OpenContext(ISurfaceContext context)
|
||||
{
|
||||
if (context == null)
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
if (_context != null && _context.Context == context)
|
||||
return;
|
||||
|
||||
// Get or create context
|
||||
VisjectSurfaceContext surfaceContext;
|
||||
if (!_contextCache.TryGetValue(context, out surfaceContext))
|
||||
{
|
||||
surfaceContext = CreateContext(_context, context);
|
||||
_context?.Children.Add(surfaceContext);
|
||||
_contextCache.Add(context, surfaceContext);
|
||||
|
||||
context.OnContextCreated(surfaceContext);
|
||||
|
||||
// Load context
|
||||
if (_root != null)
|
||||
{
|
||||
if (surfaceContext.Load())
|
||||
throw new Exception("Failed to load graph.");
|
||||
}
|
||||
}
|
||||
if (_root == null)
|
||||
_root = surfaceContext;
|
||||
else if (ContextStack.Contains(surfaceContext))
|
||||
throw new ArgumentException("Context has been already added to the stack.");
|
||||
|
||||
// Change stack
|
||||
ContextStack.Push(surfaceContext);
|
||||
|
||||
// Update
|
||||
OnContextChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the last opened context (the current one).
|
||||
/// </summary>
|
||||
public void CloseContext()
|
||||
{
|
||||
if (ContextStack.Count == 0)
|
||||
throw new ArgumentException("No context to close.");
|
||||
|
||||
// Change stack
|
||||
ContextStack.Pop();
|
||||
|
||||
// Update
|
||||
OnContextChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the context from the surface and any related cached data.
|
||||
/// </summary>
|
||||
/// <param name="context">The context.</param>
|
||||
public void RemoveContext(ISurfaceContext context)
|
||||
{
|
||||
// Skip if surface is already disposing
|
||||
if (IsDisposing || _isReleasing)
|
||||
return;
|
||||
|
||||
// Validate input
|
||||
if (context == null)
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
|
||||
// Removing root requires to close every context
|
||||
if (RootContext != null && context == RootContext.Context)
|
||||
{
|
||||
while (ContextStack.Count > 0)
|
||||
CloseContext();
|
||||
}
|
||||
|
||||
// Check if has context in cache
|
||||
VisjectSurfaceContext surfaceContext;
|
||||
if (_contextCache.TryGetValue(context, out surfaceContext))
|
||||
{
|
||||
// Remove from navigation path
|
||||
while (ContextStack.Contains(surfaceContext))
|
||||
CloseContext();
|
||||
|
||||
// Dispose
|
||||
surfaceContext.Clear();
|
||||
_contextCache.Remove(context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the current opened context to the given one. Used as a navigation method.
|
||||
/// </summary>
|
||||
/// <param name="context">The target context.</param>
|
||||
public void ChangeContext(ISurfaceContext context)
|
||||
{
|
||||
if (context == null)
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
if (_context == null)
|
||||
{
|
||||
OpenContext(context);
|
||||
return;
|
||||
}
|
||||
if (_context.Context == context)
|
||||
return;
|
||||
|
||||
// Check if already in a path
|
||||
VisjectSurfaceContext surfaceContext;
|
||||
if (_contextCache.TryGetValue(context, out surfaceContext) && ContextStack.Contains(surfaceContext))
|
||||
{
|
||||
// Change stack
|
||||
do
|
||||
{
|
||||
ContextStack.Pop();
|
||||
} while (ContextStack.Peek() != surfaceContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: implement this case (need to find first parent of the context that is in path)
|
||||
throw new NotSupportedException("TODO: support changing context to one not in the active path");
|
||||
}
|
||||
|
||||
// Update
|
||||
OnContextChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when context gets changed. Updates current context and UI. Updates the current context based on the first element in teh stack.
|
||||
/// </summary>
|
||||
protected virtual void OnContextChanged()
|
||||
{
|
||||
var context = ContextStack.Count > 0 ? ContextStack.Peek() : null;
|
||||
_context = context;
|
||||
if (ContextStack.Count == 0)
|
||||
_root = null;
|
||||
|
||||
// Update root control linkage
|
||||
if (_rootControl != null)
|
||||
{
|
||||
_rootControl.Parent = null;
|
||||
}
|
||||
if (context != null)
|
||||
{
|
||||
_rootControl = _context.RootControl;
|
||||
_rootControl.Parent = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
_rootControl = null;
|
||||
}
|
||||
|
||||
ContextChanged?.Invoke(_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user