313 lines
11 KiB
C#
313 lines
11 KiB
C#
#nullable enable
|
|
using ImGuiNET;
|
|
using T3.Core.Animation;
|
|
using T3.Editor.Gui.Hub;
|
|
using T3.Editor.Gui.Interaction;
|
|
using T3.Editor.Gui.Interaction.TransformGizmos;
|
|
using T3.Editor.Gui.MagGraph.Interaction;
|
|
using T3.Editor.Gui.Styling;
|
|
using T3.Editor.Gui.UiHelpers;
|
|
using T3.Editor.Gui.Windows;
|
|
using T3.Editor.Gui.Windows.Layouts;
|
|
using T3.Editor.Gui.Windows.TimeLine;
|
|
using T3.Editor.UiModel;
|
|
using T3.Editor.UiModel.ProjectHandling;
|
|
using T3.Editor.UiModel.Selection;
|
|
using MagGraphView = T3.Editor.Gui.MagGraph.Ui.MagGraphView;
|
|
using Vector2 = System.Numerics.Vector2;
|
|
|
|
namespace T3.Editor.Gui.Window;
|
|
|
|
[HelpUiID("Graph")]
|
|
internal sealed class GraphWindow : Windows.Window
|
|
{
|
|
#region Window implementation --------------------
|
|
public GraphWindow()
|
|
{
|
|
Config.Title = LayoutHandling.GraphPrefix + _instanceNumber;
|
|
Config.Visible = true;
|
|
|
|
AllowMultipleInstances = true;
|
|
MayNotCloseLastInstance = true;
|
|
Config.Visible = true;
|
|
WindowFlags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse;
|
|
|
|
_instanceNumber++;
|
|
GraphWindowInstances.Add(this);
|
|
}
|
|
|
|
// The graph editor canvas (and the Hub it hosts) get their own themeable backdrop, separate from
|
|
// regular panels' Panel Background.
|
|
protected override T3.Core.DataTypes.Vector.Color? InnerBackgroundColor => UiColors.EditorBackground;
|
|
|
|
private readonly int _instanceNumber;
|
|
|
|
internal override IReadOnlyList<Gui.Windows.Window> GetInstances() => GraphWindowInstances;
|
|
internal static readonly List<GraphWindow> GraphWindowInstances = [];
|
|
|
|
public void SetWindowToNormal()
|
|
{
|
|
WindowFlags &= ~(ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoBringToFrontOnFocus | ImGuiWindowFlags.NoMove |
|
|
ImGuiWindowFlags.NoResize);
|
|
}
|
|
|
|
protected override void AddAnotherInstance()
|
|
{
|
|
// ReSharper disable once ObjectCreationAsStatement
|
|
new GraphWindow();
|
|
}
|
|
#endregion
|
|
|
|
#region Handling project view ----------------------
|
|
public ProjectView? ProjectView { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Initialize <see cref="ProjectView"/> for loading a project
|
|
/// </summary>
|
|
internal bool TrySetToProject(OpenedProject project, bool tryRestoreViewArea = true)
|
|
{
|
|
if (!project.Package.HasHome)
|
|
{
|
|
Log.Error("Project has no home.");
|
|
return false;
|
|
}
|
|
|
|
ProjectView = UserSettings.Config.GraphStyle == UserSettings.GraphStyles.Magnetic
|
|
? MagGraphView.CreateWithComponents(project)
|
|
: Legacy.GraphView.CreateWithComponents(project);
|
|
|
|
ProjectView.SetAsFocused();
|
|
// ProjectView = MagGraphCanvas.CreateWithComponents(project);
|
|
// ProjectView = Legacy.GraphCanvas.CreateWithComponents(project);
|
|
ProjectView.OnCompositionChanged += CompositionChangedHandler;
|
|
|
|
var rootInstance = ProjectView.RootInstance;
|
|
var rootSymbolChildId = rootInstance.SymbolChildId;
|
|
var rootPath = rootInstance.InstancePath;
|
|
var startPath = rootPath;
|
|
if (project.Package.OverrideHomeGuid == Guid.Empty)
|
|
{
|
|
var opId = UserSettings.GetLastOpenOpForWindow(Config.Title);
|
|
if (opId != Guid.Empty && opId != rootSymbolChildId)
|
|
{
|
|
if (rootInstance.SymbolChild.SearchForChild(opId, out _, out var path))
|
|
{
|
|
startPath = path;
|
|
}
|
|
}
|
|
}
|
|
|
|
const ScalableCanvas.Transition transition = ScalableCanvas.Transition.JumpIn;
|
|
if (!ProjectView.TrySetCompositionOp(startPath, transition, tryRestoreViewArea: tryRestoreViewArea)
|
|
&& !ProjectView.TrySetCompositionOp(rootPath, transition, tryRestoreViewArea: tryRestoreViewArea))
|
|
{
|
|
Log.Warning("Can't set composition op");
|
|
return false;
|
|
}
|
|
|
|
_focusOnNextFrame = true;
|
|
return true;
|
|
}
|
|
|
|
/** Called when view is closed (e.g. when jumping to hub) or changed */
|
|
public void CloseView()
|
|
{
|
|
if (ProjectView != null)
|
|
ProjectView.OnCompositionChanged -= CompositionChangedHandler;
|
|
|
|
_reinitHubView = true;
|
|
ProjectView = null;
|
|
}
|
|
|
|
/** Called when windows is closed */
|
|
protected override void Close()
|
|
{
|
|
if (ProjectView == null)
|
|
return;
|
|
|
|
ProjectView.OnCompositionChanged -= CompositionChangedHandler;
|
|
|
|
ProjectView.Close();
|
|
GraphWindowInstances.Remove(this);
|
|
}
|
|
|
|
private bool _reinitHubView = true;
|
|
private bool _focusOnNextFrame;
|
|
|
|
// private void FocusRequested()
|
|
// {
|
|
// TakeFocus();
|
|
// _focusOnNextFrame = true;
|
|
// }
|
|
|
|
private void CompositionChangedHandler(ProjectView _, Guid instanceId)
|
|
{
|
|
UserSettings.SaveLastViewedOpForWindow(Config.Title, instanceId);
|
|
}
|
|
#endregion
|
|
|
|
#region Drawing ---------------------------------------
|
|
protected override void DrawContent()
|
|
{
|
|
if (ProjectView == null)
|
|
{
|
|
ProjectHub.Draw(this, _reinitHubView);
|
|
_reinitHubView = false;
|
|
return;
|
|
}
|
|
|
|
if (FitViewToSelectionHandling.FitViewToSelectionRequested)
|
|
GraphCanvas?.FocusViewToSelection();
|
|
|
|
if (ProjectView.InstView == null)
|
|
return;
|
|
|
|
var windowContentHeight = (int)ImGui.GetWindowHeight();
|
|
|
|
if (UserSettings.Config.ShowTimeline)
|
|
{
|
|
ProjectView.TimeLineCanvas.FoldingHeight.DrawSplit(out windowContentHeight);
|
|
}
|
|
|
|
//ImageBackgroundFading.HandleImageBackgroundFading(ProjectView.GraphImageBackground, out var backgroundImageOpacity);
|
|
var backgroundImageOpacity = 1f;
|
|
ImGui.BeginChild("##graphbackground", new Vector2(0, windowContentHeight), ImGuiChildFlags.None,
|
|
ImGuiWindowFlags.NoScrollbar
|
|
| ImGuiWindowFlags.NoMove
|
|
| ImGuiWindowFlags.NoScrollWithMouse
|
|
| ImGuiWindowFlags.NoDecoration
|
|
| ImGuiWindowFlags.NoTitleBar
|
|
| ImGuiWindowFlags.NoBackground
|
|
| ImGuiWindowFlags.ChildWindow);
|
|
{
|
|
}
|
|
ImGui.EndChild();
|
|
ImGui.SetCursorPos(Vector2.Zero);
|
|
|
|
ImGui.BeginChild("##graph", new Vector2(0, windowContentHeight), ImGuiChildFlags.None,
|
|
ImGuiWindowFlags.NoScrollbar
|
|
| ImGuiWindowFlags.NoMove
|
|
| ImGuiWindowFlags.NoScrollWithMouse
|
|
| ImGuiWindowFlags.NoDecoration
|
|
| ImGuiWindowFlags.NoTitleBar
|
|
| ImGuiWindowFlags.NoBackground
|
|
| ImGuiWindowFlags.ChildWindow);
|
|
{
|
|
// ImageBackground
|
|
ProjectView.GraphImageBackground.Draw(backgroundImageOpacity);
|
|
|
|
var graphHiddenWhileInteractiveWithBackground = ProjectView.GraphImageBackground.IsActive && TransformGizmoHandling.IsDragging;
|
|
if (!graphHiddenWhileInteractiveWithBackground)
|
|
{
|
|
var drawList = ImGui.GetWindowDrawList();
|
|
DrawGraphContent(drawList);
|
|
}
|
|
}
|
|
ImGui.EndChild();
|
|
|
|
if (ProjectView == null)
|
|
return;
|
|
|
|
ProjectView.CheckDisposal();
|
|
|
|
if (UserSettings.Config.ShowTimeline)
|
|
{
|
|
const int splitterWidth = 3;
|
|
var availableRestHeight = ImGui.GetContentRegionAvail().Y;
|
|
if (availableRestHeight <= splitterWidth)
|
|
{
|
|
//Log.Warning($"skipping rending of timeline because layout is inconsistent: only {availableRestHeight}px left.");
|
|
}
|
|
else
|
|
{
|
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + splitterWidth - 1); // leave gap for splitter
|
|
ImGui.PushStyleVar(ImGuiStyleVar.ChildBorderSize, 0);
|
|
|
|
ImGui.BeginChild("##timeline", Vector2.Zero, ImGuiChildFlags.None,
|
|
ImGuiWindowFlags.NoResize
|
|
| ImGuiWindowFlags.NoBackground
|
|
);
|
|
{
|
|
if (ProjectView.CompositionInstance != null)
|
|
ProjectView.TimeLineCanvas.Draw(ProjectView, Playback.Current);
|
|
}
|
|
ImGui.EndChild();
|
|
ImGui.PopStyleVar(1);
|
|
}
|
|
}
|
|
|
|
if (UserSettings.Config.ShowMiniMap && GraphCanvas != null)
|
|
UiElements.DrawMiniMap(ProjectView.InstView, GraphCanvas.Canvas);
|
|
}
|
|
|
|
private void DrawGraphContent(ImDrawListPtr drawList)
|
|
{
|
|
if (_focusOnNextFrame)
|
|
{
|
|
ImGui.SetWindowFocus();
|
|
_focusOnNextFrame = false;
|
|
}
|
|
|
|
ImGui.SetScrollX(0);
|
|
|
|
drawList.ChannelsSplit(2);
|
|
|
|
// Draw Foreground content first
|
|
drawList.ChannelsSetCurrent(1);
|
|
{
|
|
if (UserSettings.Config.ShowTitleAndDescription)
|
|
GraphTitleAndBreadCrumbs.Draw(ProjectView);
|
|
|
|
TourInteraction.Draw(ProjectView);
|
|
|
|
// Breadcrumbs may have requested close...
|
|
if (ProjectView == null)
|
|
return;
|
|
|
|
TimelineToolbar.Draw(ProjectView);
|
|
}
|
|
|
|
// Draw content
|
|
drawList.ChannelsSetCurrent(0);
|
|
{
|
|
ImageBackgroundFading.HandleGraphFading(ProjectView.GraphImageBackground, drawList, out var graphOpacity);
|
|
|
|
var isGraphHidden = graphOpacity <= 0;
|
|
if (!isGraphHidden && GraphCanvas != null)
|
|
{
|
|
GraphCanvas.BeginDraw(ProjectView.GraphImageBackground.IsActive,
|
|
ProjectView.GraphImageBackground.HasInteractionFocus);
|
|
|
|
GraphBookmarkNavigation.HandleForCanvas(ProjectView);
|
|
|
|
ImGui.BeginGroup();
|
|
ImGui.SetScrollY(0);
|
|
|
|
if (!LayoutHandling.FocusMode)
|
|
CustomComponents.DrawWindowFocusFrame();
|
|
|
|
if (ImGui.IsWindowFocused())
|
|
{
|
|
ProjectView?.SetAsFocused();
|
|
}
|
|
|
|
GraphCanvas.DrawGraph(drawList, graphOpacity);
|
|
|
|
ImGui.EndGroup();
|
|
|
|
if (ProjectView != null)
|
|
ParameterPopUp.DrawParameterPopUp(ProjectView);
|
|
}
|
|
}
|
|
drawList.ChannelsMerge();
|
|
|
|
// if (ProjectView?.InstView != null)
|
|
// _editDescriptionDialog.Draw(ProjectView.InstView.Symbol);
|
|
//
|
|
}
|
|
#endregion
|
|
|
|
private IGraphView? GraphCanvas => ProjectView?.GraphView;
|
|
// private static readonly EditSymbolDescriptionDialog _editDescriptionDialog = new();
|
|
// private static readonly EditTourPointsDialog _editTourPointsDialog = new();
|
|
} |