Files
2026-07-13 13:13:17 +08:00

429 lines
16 KiB
C#

#nullable enable
using System.Diagnostics;
using System.Text;
using ImGuiNET;
using T3.Core.DataTypes.Vector;
using T3.Core.Operator;
using T3.Editor.Gui.Input;
using T3.Editor.Gui.MagGraph.Interaction;
using T3.Editor.Gui.Styling;
using T3.Editor.UiModel;
using T3.Editor.UiModel.Modification;
using T3.Editor.UiModel.ProjectHandling;
using T3.Editor.UiModel.Selection;
namespace T3.Editor.Gui.Graph.Dialogs;
internal static class EditTourPointsPopup
{
private static bool _isOpen;
internal static void ShowNextFrame()
{
_isOpen = true;
}
private static string GetSelectionMarkdown()
{
if (_compositionUi == null)
return string.Empty;
var sb = new StringBuilder();
var hasCurrentCompositionTour = _compositionUi.TourPoints.Count > 0;
if (hasCurrentCompositionTour)
{
TourDataMarkdownExport.WriteSymbolTourMarkdown(_compositionUi, sb);
}
else
{
var orderedChildUis = _selectedChildIds
.Select(id => _compositionUi.ChildUis.TryGetValue(id, out var childUi) ? childUi : null)
.Where(childUi => childUi != null)
.OrderBy(childUi => childUi!.PosOnCanvas.Y);
foreach (var childUi in orderedChildUis)
{
if (childUi == null)
continue;
TourDataMarkdownExport.WriteSymbolTourMarkdown(childUi.SymbolChild.Symbol.GetSymbolUi(), sb);
sb.AppendLine();
}
}
return sb.ToString();
}
internal static ChangeSymbol.SymbolModificationResults Draw(Symbol operatorSymbol, ProjectView projectView)
{
var result = ChangeSymbol.SymbolModificationResults.Nothing;
if (!_isOpen)
return ChangeSymbol.SymbolModificationResults.Nothing;
ImGui.SetNextWindowSize(new Vector2(500, 500) * T3Ui.UiScaleFactor, ImGuiCond.Once);
ImGui.PushStyleVar(ImGuiStyleVar.WindowBorderSize, 1);
if (ImGui.Begin("Edit tour points", ref _isOpen))
{
ImGui.PushStyleColor(ImGuiCol.ChildBg, UiColors.WindowBackground.Fade(0.8f).Rgba);
ImGui.BeginChild("Inner", Vector2.Zero, ImGuiChildFlags.None, ImGuiWindowFlags.NoMove);
{
_compositionUi = operatorSymbol.GetSymbolUi();
if (CustomComponents.IconButton(Icon.CopyToClipboard, Vector2.Zero))
{
ImGui.SetClipboardText(GetSelectionMarkdown());
}
if (ImGui.IsItemHovered())
{
ImGui.BeginTooltip();
{
ImGui.PushFont(Fonts.Code);
ImGui.PushTextWrapPos(400);
ImGui.TextWrapped(GetSelectionMarkdown());
ImGui.PopTextWrapPos();
ImGui.PopFont();
}
ImGui.EndTooltip();
}
ImGui.SameLine();
if (CustomComponents.IconButton(Icon.PasteFromClipboard, Vector2.Zero))
{
TourDataMarkdownExport.TryPasteTourData(_compositionUi, projectView);
}
// Handle selection
_selectedChildIds.Clear();
_firstSelectedChildId = Guid.Empty;
ImGui.Indent(20);
FormInputs.AddVerticalSpace(20);
foreach (var c in projectView.NodeSelection.GetSelectedChildUis())
{
if (_firstSelectedChildId == Guid.Empty)
_firstSelectedChildId = c.Id;
_selectedChildIds.Add(c.Id);
}
var modified = false;
_completedDragging = false;
// List...
if (!_isDragging && _listOrderWhileDragging.Count != _compositionUi.TourPoints.Count)
{
_listOrderWhileDragging.Clear();
for (var index = 0; index < _compositionUi.TourPoints.Count; index++)
{
_listOrderWhileDragging.Add(index);
}
}
for (var index = 0; index < _compositionUi.TourPoints.Count; index++)
{
var tourPoint = _compositionUi.TourPoints[index];
ImGui.PushID(tourPoint.Id.GetHashCode());
// Draw floating + button...
{
var keepCursorPos = ImGui.GetCursorPos();
var h = ImGui.GetFrameHeight();
ImGui.SetCursorPos(keepCursorPos - new Vector2(h, h * 0.5f));
if (CustomComponents.TransparentIconButton(Icon.Plus, Vector2.Zero))
{
InsertNewTourPoint(index);
}
ImGui.SetCursorPos(keepCursorPos);
}
modified |= DrawItem(tourPoint, index);
FormInputs.AddVerticalSpace(2);
ImGui.PopID();
}
if (_completedDragging)
{
_isDragging = false;
_listOrderWhileDragging.Clear();
modified = true;
}
if (CustomComponents.DisablableButton("Add Tour Point", CanAdd))
{
InsertNewTourPoint(_compositionUi.TourPoints.Count);
}
if (modified)
_compositionUi.FlagAsModified();
}
ImGui.EndChild();
ImGui.PopStyleColor();
}
ImGui.End();
ImGui.PopStyleVar();
return result;
}
private static readonly Dictionary<int, float> _lastItemHeights = new();
private static bool DrawItem(TourPoint tourPoint, int index)
{
Debug.Assert(_compositionUi != null);
var modified = false;
var isSelected = _selectedChildIds.Contains(tourPoint.ChildId) && tourPoint.Style == TourPoint.Styles.InfoFor;
ImGui.PushStyleColor(ImGuiCol.ChildBg, isSelected
? Color.Mix(UiColors.BackgroundButton, UiColors.BackgroundActive, 0.1f).Rgba
: UiColors.BackgroundButton);
ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 5);
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(5, 5)); // inner spacing
if (!_lastItemHeights.TryGetValue(index, out var height))
{
height = 0;
}
ImGui.BeginChild("item", new Vector2(-5, height), ImGuiChildFlags.Borders);
{
FormInputs.AddVerticalSpace(3);
var padding = 10;
ImGui.PushFont(Fonts.FontSmall);
{
ImGui.Indent(6);
ImGui.SetNextItemWidth(10);
ImGui.AlignTextToFramePadding();
ImGui.PushStyleColor(ImGuiCol.Text, UiColors.TextMuted.Rgba);
ImGui.PushStyleColor(ImGuiCol.Button, Color.Transparent.Rgba);
var dragIndex = _isDragging
? _listOrderWhileDragging[index]
: index;
ImGui.Button($"{dragIndex + 1}.");
ImGui.PopStyleColor(2);
if (ImGui.IsItemActive())
{
_isDragging = true;
var itemMin = ImGui.GetWindowPos();
var itemMax = ImGui.GetWindowPos() + ImGui.GetWindowSize();
ImGui.GetForegroundDrawList().AddRect(itemMin, itemMax, Color.Gray);
var mouseY = ImGui.GetMousePos().Y;
var halfHeight = ImGui.GetWindowSize().Y / 2;
var indexDelta = 0;
if (mouseY < itemMin.Y - halfHeight && index > 0)
{
indexDelta = -1;
}
else if (mouseY > itemMax.Y + halfHeight && index < _compositionUi.TourPoints.Count - 1)
{
indexDelta = 1;
}
if (indexDelta != 0)
{
var newIndex = index + indexDelta;
if (newIndex >= 0 && index < _compositionUi.TourPoints.Count && newIndex < _compositionUi.TourPoints.Count)
{
(_compositionUi.TourPoints[newIndex], _compositionUi.TourPoints[index]) =
(_compositionUi.TourPoints[index], _compositionUi.TourPoints[newIndex]);
(_listOrderWhileDragging[newIndex], _listOrderWhileDragging[index]) =
(_listOrderWhileDragging[index], _listOrderWhileDragging[newIndex]);
}
}
}
if (ImGui.IsItemDeactivated())
{
_completedDragging = true;
}
// TourPoint type
ImGui.SameLine(0, padding);
ImGui.SetNextItemWidth(120);
modified |= FormInputs.DrawEnumDropdown(ref tourPoint.Style, "style");
// Highlight child
if (_compositionUi.ChildUis.TryGetValue(tourPoint.ChildId, out var childUi))
{
ImGui.SameLine(0, padding);
ImGui.TextUnformatted("on");
ImGui.SameLine(0, padding);
if (ImGui.Button(childUi.SymbolChild.ReadableName))
{
var comp = ProjectView.Focused!.CompositionInstance;
if (comp != null && comp.Children.TryGetChildInstance(tourPoint.ChildId, out var instance))
{
ProjectView.Focused.GraphView.OpenAndFocusInstance(instance.InstancePath);
}
}
if (ImGui.IsItemHovered())
{
FrameStats.AddHoveredId(tourPoint.ChildId);
}
}
else
{
CustomComponents.TooltipForLastItem("" + tourPoint.ChildId);
}
if (!CanAdd && tourPoint.ChildId != _firstSelectedChildId)
{
ImGui.SameLine();
if (CustomComponents.IconButton(Icon.Close, Vector2.Zero))
{
tourPoint.ChildId = Guid.Empty;
tourPoint.InputId = Guid.Empty;
modified = true;
}
}
else if (CanAdd && tourPoint.ChildId != _firstSelectedChildId)
{
ImGui.SameLine();
if (CustomComponents.IconButton(Icon.ApplySelection, Vector2.Zero))
{
tourPoint.ChildId = _firstSelectedChildId;
tourPoint.InputId = Guid.Empty;
modified = true;
}
}
if (tourPoint.ChildId != Guid.Empty)
{
ImGui.SameLine(0, 10);
ImGui.SetNextItemWidth(100);
ImGui.PushStyleColor(ImGuiCol.FrameBg, UiColors.BackgroundButton.Rgba);
ImGui.PushStyleColor(ImGuiCol.FrameBgHovered, UiColors.BackgroundButton.Rgba);
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(4));
if (_compositionUi.ChildUis.TryGetValue(tourPoint.ChildId, out var symbolUi))
{
var label = "select input";
if (tourPoint.InputId != Guid.Empty)
{
var inputDefinition = symbolUi.SymbolChild.Symbol.InputDefinitions.FirstOrDefault(i => i.Id == tourPoint.InputId);
if (inputDefinition != null)
label = inputDefinition.Name;
}
if (ImGui.BeginCombo("##test", label))
{
if (ImGui.Selectable("--none--", tourPoint.InputId == Guid.Empty))
{
tourPoint.InputId = Guid.Empty;
modified = true;
}
foreach (var i in symbolUi.SymbolChild.Symbol.InputDefinitions)
{
if (ImGui.Selectable(i.Name, i.Id == tourPoint.InputId))
{
tourPoint.InputId = i.Id;
modified = true;
}
}
ImGui.EndCombo();
}
}
ImGui.PopStyleColor(2);
ImGui.PopStyleVar();
}
}
ImGui.PopFont();
var x = ImGui.GetContentRegionAvail().X - ImGui.GetFrameHeight();
ImGui.SameLine(x);
if (CustomComponents.TransparentIconButton(Icon.Trash, Vector2.Zero, CustomComponents.ButtonStates.Default))
{
_compositionUi.TourPoints.Remove(tourPoint);
modified = true;
}
if (_editedTourPointId == tourPoint.Id)
{
if (_shouldFocusInput)
{
ImGui.SetKeyboardFocusHere();
_shouldFocusInput = false;
}
if (ImGui.InputTextMultiline("##Text", ref tourPoint.Description, 16384, new Vector2(-10, 60) * T3Ui.UiScaleFactor))
{
modified = true;
}
if (ImGui.IsItemDeactivated())
{
_editedTourPointId = Guid.Empty;
}
}
else
{
var text = string.IsNullOrEmpty(tourPoint.Description) ? "Add description..." : tourPoint.Description;
ImGui.TextWrapped(text);
if (ImGui.IsItemClicked())
{
_editedTourPointId = tourPoint.Id;
_shouldFocusInput = true;
}
}
ImGui.Unindent(10);
// Activate tour point
if (ImGui.IsWindowHovered() && ImGui.IsMouseClicked(ImGuiMouseButton.Left))
{
TourInteraction.SetProgressIndex(_compositionUi.Symbol.Id, index);
}
FormInputs.AddVerticalSpace();
_lastItemHeights[index] = ImGui.GetCursorPosY();
}
ImGui.EndChild();
ImGui.PopStyleVar(2);
ImGui.PopStyleColor();
return modified;
}
private static void InsertNewTourPoint(int index)
{
_compositionUi?.TourPoints.Insert(index, new TourPoint
{
Description = string.Empty,
Id = Guid.NewGuid(),
ChildId = _firstSelectedChildId,
Style = TourPoint.Styles.Info
});
}
private static bool CanAdd => _selectedChildIds.Count == 1;
private static bool _shouldFocusInput;
private static bool _isDragging;
private static readonly List<int> _listOrderWhileDragging = [];
private static bool _completedDragging;
private static Guid _editedTourPointId;
private static SymbolUi? _compositionUi;
private static Guid _firstSelectedChildId;
private static readonly HashSet<Guid> _selectedChildIds = [];
}