632 lines
24 KiB
C#
632 lines
24 KiB
C#
#nullable enable
|
|
using System.IO;
|
|
using ImGuiNET;
|
|
using T3.Core.DataTypes.Vector;
|
|
using T3.Core.Operator;
|
|
using T3.Core.Operator.Slots;
|
|
using T3.Core.Resource;
|
|
using T3.Core.Resource.Assets;
|
|
using T3.Core.SystemUi;
|
|
using T3.Core.Settings;
|
|
using T3.Core.Utils;
|
|
using T3.Editor.Gui.Input;
|
|
using T3.Editor.Gui.Styling;
|
|
using T3.Editor.Gui.UiHelpers;
|
|
using T3.Editor.Gui.UiHelpers.Thumbnails;
|
|
using T3.Editor.UiModel.Commands;
|
|
using T3.Editor.UiModel.Commands.Graph;
|
|
using T3.Editor.UiModel.ProjectHandling;
|
|
|
|
namespace T3.Editor.Gui.Windows.AssetLib;
|
|
|
|
internal sealed partial class AssetLibrary
|
|
{
|
|
private void DrawLibContent()
|
|
{
|
|
var iconCount = 2;
|
|
_state.TreeHandler.Update();
|
|
|
|
_state.SearchStringChanged |= CustomComponents.DrawInputFieldWithPlaceholder("Search Assets...",
|
|
ref _state.SearchString,
|
|
-ImGui.GetFrameHeight() * iconCount + 18 * T3Ui.UiScaleFactor);
|
|
|
|
// Collapse icon
|
|
{
|
|
ImGui.SameLine();
|
|
var collapseIconState = _state.TreeHandler.NoFolderOpen
|
|
? CustomComponents.ButtonStates.Default
|
|
: CustomComponents.ButtonStates.Emphasized;
|
|
|
|
if (CustomComponents.IconButton(Icon.TreeCollapse, Vector2.Zero, collapseIconState))
|
|
{
|
|
_state.TreeHandler.CollapseAll();
|
|
}
|
|
}
|
|
|
|
// Tools and settings
|
|
{
|
|
ImGui.SameLine();
|
|
var toolItemState = _state.ActiveTypeFilters.Count > 0
|
|
? CustomComponents.ButtonStates.NeedsAttention
|
|
: CustomComponents.ButtonStates.Emphasized;
|
|
|
|
if (CustomComponents.IconButton(Icon.Settings2, Vector2.Zero, toolItemState))
|
|
{
|
|
ImGui.OpenPopup(SettingsPopUpId);
|
|
}
|
|
|
|
DrawAssetToolsPopup();
|
|
}
|
|
|
|
ImGui.BeginChild("scrolling", Vector2.Zero, ImGuiChildFlags.None, ImGuiWindowFlags.NoBackground);
|
|
{
|
|
ImGui.PushStyleVar(ImGuiStyleVar.IndentSpacing, 10);
|
|
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(0));
|
|
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(0));
|
|
DrawFolder(_state.RootFolder);
|
|
ImGui.PopStyleVar(3);
|
|
}
|
|
|
|
CustomComponents.HandleDragScrolling(this);
|
|
ImGui.EndChild();
|
|
}
|
|
|
|
private bool _expandToFileTriggered;
|
|
private static AssetFolder? _folderForMenu;
|
|
|
|
private void DrawFolder(AssetFolder folder)
|
|
{
|
|
if (folder.IsHidden)
|
|
return;
|
|
|
|
var folderName = folder.Name.AsSpan();
|
|
if (folderName == AssetFolder.RootNodeId)
|
|
{
|
|
DrawFolderContent(folder);
|
|
}
|
|
else
|
|
{
|
|
var hasMatches = folder.MatchingAssetCount > 0;
|
|
var isSearching = !string.IsNullOrEmpty(_state.SearchString);
|
|
var isFiltering = _state.CompatibleExtensionIds.Count > 0 || isSearching;
|
|
var isCurrentCompositionPackage = _state.Composition?.Symbol.SymbolPackage.Name == folderName;
|
|
|
|
|
|
|
|
if (isSearching && !hasMatches)
|
|
return;
|
|
|
|
if (isFiltering && !hasMatches)
|
|
return;
|
|
|
|
// Open main folders automatically
|
|
if (!_state.OpenedExamplesFolderOnce
|
|
&& folderName.Equals(FileLocations.ExamplesPackageName, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
ImGui.SetNextItemOpen(true);
|
|
_state.OpenedExamplesFolderOnce = true;
|
|
}
|
|
|
|
if (!_state.OpenedProjectsFolderOnce
|
|
&& folderName.Equals(ProjectView.Focused?.RootInstance.Symbol.SymbolPackage.Name ?? string.Empty, StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
ImGui.SetNextItemOpen(true);
|
|
_state.OpenedProjectsFolderOnce = true;
|
|
}
|
|
|
|
|
|
ImGui.PushID(folder.HashCode);
|
|
|
|
// Prepare drawing
|
|
ImGui.SetNextItemWidth(10);
|
|
|
|
var textMutedRgba = (isFiltering && !hasMatches) ? UiColors.TextMuted : UiColors.Text;
|
|
textMutedRgba = textMutedRgba.Fade(isCurrentCompositionPackage ? 1 : 0.8f);
|
|
|
|
ImGui.PushStyleColor(ImGuiCol.Text, textMutedRgba.Rgba);
|
|
ImGui.PushStyleColor(ImGuiCol.HeaderHovered, Color.Transparent.Rgba);
|
|
ImGui.PushStyleColor(ImGuiCol.HeaderActive, Color.Transparent.Rgba);
|
|
|
|
var containsTargetFile = ContainsTargetFile(folder);
|
|
if (_expandToFileTriggered && containsTargetFile)
|
|
{
|
|
ImGui.SetNextItemOpen(true);
|
|
}
|
|
|
|
_state.TreeHandler.UpdateForNode(folder.HashCode);
|
|
|
|
var lastPos = ImGui.GetCursorScreenPos();
|
|
|
|
// Draw the actual folder item
|
|
ImGui.PushFont(isCurrentCompositionPackage ? Fonts.FontBold : Fonts.FontNormal);
|
|
var isOpen = ImGui.TreeNodeEx(folderName);
|
|
ImGui.PopFont();
|
|
ImGui.PopStyleColor(3);
|
|
|
|
CustomComponents.DrawHoverHighlightOnLastItem();
|
|
|
|
CustomComponents.DrawSearchMatchUnderline(_state.SearchString, folderName,
|
|
ImGui.GetItemRectMin()
|
|
+ new Vector2(ImGui.GetFontSize(), 0));
|
|
|
|
HandleDropFilesIntoFolder(folder);
|
|
HandleDropAssetsIntoFolder(folder);
|
|
|
|
_folderForMenu = folder;
|
|
CustomComponents.ContextMenuForItem(() =>
|
|
{
|
|
CustomComponents.StylizedText(folder.Name, Fonts.FontSmall, UiColors.TextMuted);
|
|
if (ImGui.MenuItem("Open in Explorer"))
|
|
{
|
|
if (!string.IsNullOrEmpty(_folderForMenu.AbsolutePath))
|
|
{
|
|
CoreUi.Instance.OpenWithDefaultApplication(_folderForMenu.AbsolutePath);
|
|
}
|
|
else
|
|
{
|
|
Log.Warning($"Failed to get path for {_folderForMenu.Address}");
|
|
}
|
|
}
|
|
|
|
if (ImGui.MenuItem("Create sub folder"))
|
|
{
|
|
CreateSubFolder(folder);
|
|
}
|
|
|
|
if (ImGui.MenuItem("Rename"))
|
|
{
|
|
_state.RenamingInProcessId = folder.Asset?.Id ?? Guid.Empty;
|
|
_state.RenameBuffer = folder.Name;
|
|
}
|
|
|
|
if (ImGui.MenuItem("Delete folder"))
|
|
{
|
|
try
|
|
{
|
|
if (Directory.Exists(folder.AbsolutePath))
|
|
{
|
|
Log.Debug("Deleting " + folder.Address);
|
|
Directory.Delete(folder.AbsolutePath);
|
|
}
|
|
|
|
AssetRegistry.RemoveObsoleteAsset(folder.Asset);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Log.Warning($"Can't remove folder {folder.AbsolutePath} ({e.Message}");
|
|
}
|
|
}
|
|
});
|
|
|
|
// Show filter count
|
|
if (isFiltering && hasMatches)
|
|
{
|
|
ShowMatchCount(folder, containsTargetFile, isOpen);
|
|
}
|
|
|
|
_state.TreeHandler.NoFolderOpen = false;
|
|
|
|
ImGui.PopID();
|
|
|
|
HandleRenameFolder(folder, lastPos);
|
|
|
|
if (isOpen)
|
|
{
|
|
DrawFolderContent(folder);
|
|
_state.TreeHandler.FlagLastItemWasVisible();
|
|
ImGui.TreePop();
|
|
}
|
|
else
|
|
{
|
|
if (ContainsTargetFile(folder))
|
|
{
|
|
var h = ImGui.GetFontSize();
|
|
CustomComponents.RightAlign(h);
|
|
|
|
var clicked = ImGui.InvisibleButton("Reveal", new Vector2(h));
|
|
if (ImGui.IsItemHovered())
|
|
{
|
|
CustomComponents.TooltipForLastItem("Reveal selected asset");
|
|
}
|
|
|
|
if (_state.HasActiveInstanceChanged && !IsLastItemFullyVisible())
|
|
{
|
|
ImGui.SetScrollHereY(0.5f);
|
|
}
|
|
|
|
var timeSinceChange = (float)(ImGui.GetTime() - _state.TimeActiveInstanceChanged);
|
|
var fadeProgress = (timeSinceChange / 0.7f).Clamp(0, 1);
|
|
var blinkFade = MathUtils.Lerp(-MathF.Cos(timeSinceChange * 15f) * 0.8f + 0.2f, 1, fadeProgress);
|
|
var color = UiColors.StatusActivated.Fade(blinkFade);
|
|
Icons.DrawIconOnLastItem(Icon.Aim, color);
|
|
|
|
if (clicked)
|
|
//if (CustomComponents.IconButton(Icon.Aim, new Vector2(h)))
|
|
{
|
|
_expandToFileTriggered = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Extracted to separate method to limit hot code reloading block from stack alloc **/
|
|
private static void ShowMatchCount(AssetFolder folder, bool containsTargetFile, bool isOpen)
|
|
{
|
|
Span<char> buffer = stackalloc char[32];
|
|
var countLabel = buffer.Format($"{folder.MatchingAssetCount}");
|
|
|
|
var labelSize = ImGui.CalcTextSize(countLabel); // skip null byte
|
|
CustomComponents.RightAlign(labelSize.X + 4 + ((containsTargetFile && !isOpen) ? Icons.FontSize : 0));
|
|
ImGui.PushStyleColor(ImGuiCol.Text, UiColors.ForegroundFull.Fade(0.3f).Rgba);
|
|
ImGui.TextUnformatted(countLabel);
|
|
ImGui.PopStyleColor();
|
|
}
|
|
|
|
private static bool IsLastItemFullyVisible()
|
|
{
|
|
var windowTop = ImGui.GetWindowPos().Y;
|
|
var windowBottom = windowTop + ImGui.GetWindowSize().Y;
|
|
return ImGui.GetItemRectMin().Y >= windowTop && ImGui.GetItemRectMax().Y <= windowBottom;
|
|
}
|
|
|
|
private static bool ContainsTargetFile(AssetFolder folder)
|
|
{
|
|
var containsTargetFile = _state.ActivePathInput != null
|
|
&& !string.IsNullOrEmpty(folder.Address)
|
|
&& !string.IsNullOrEmpty(_state.ActiveAssetAddress)
|
|
&& _state.ActiveAssetAddress.StartsWith(folder.Address);
|
|
return containsTargetFile;
|
|
}
|
|
|
|
private void DrawFolderContent(AssetFolder folder)
|
|
{
|
|
// Using a for loop to prevent modification during iteration exception
|
|
for (var index = 0; index < folder.SubFolders.Count; index++)
|
|
{
|
|
var subspace = folder.SubFolders[index];
|
|
DrawFolder(subspace);
|
|
}
|
|
|
|
for (var index = 0; index < folder.FolderAssets.Count; index++)
|
|
{
|
|
var asset = folder.FolderAssets[index];
|
|
if (asset.IsDirectory || asset.Package == AssetRegistry.ExternalAssetsPackage)
|
|
continue;
|
|
|
|
DrawAssetItem(asset);
|
|
}
|
|
}
|
|
|
|
private void DrawAssetItem(Asset asset)
|
|
{
|
|
var isActive = asset.Address == _state.ActiveAssetAddress;
|
|
|
|
var fileConsumerOpSelected = _state.CompatibleExtensionIds.Count > 0;
|
|
var fileConsumerOpIsCompatible = fileConsumerOpSelected
|
|
&& _state.CompatibleExtensionIds.Contains(asset.ExtensionId);
|
|
|
|
// Skip not matching asset
|
|
if (fileConsumerOpSelected && !fileConsumerOpIsCompatible)
|
|
return;
|
|
|
|
_state.KeepVisibleTreeItemIds.Add(asset.Id);
|
|
|
|
ImGui.PushID(asset.Id.GetHashCode());
|
|
{
|
|
var fade = !fileConsumerOpSelected
|
|
? 1.0f
|
|
: fileConsumerOpIsCompatible
|
|
? 1f
|
|
: 0.2f;
|
|
|
|
var knownType = asset.AssetType != AssetType.Unknown;
|
|
var iconColor = ColorVariations.OperatorLabel.Apply(knownType ? asset.AssetType.Color : UiColors.Text);
|
|
var icon = knownType
|
|
? (Icon)asset.AssetType.IconId
|
|
: Icon.FileImage;
|
|
|
|
var isSelected = _state.Selection.IsSelected(asset.Id);
|
|
|
|
// Draw Item
|
|
var cursorScreenPos = ImGui.GetCursorScreenPos();
|
|
ImGui.SetCursorPosX(ImGui.GetCursorPosX() - 6);
|
|
if (ButtonWithIcon(string.Empty,
|
|
asset.FileSystemInfo?.Name ?? string.Empty,
|
|
icon,
|
|
iconColor.Fade(fade),
|
|
isSelected ? UiColors.StatusActivated : UiColors.Text.Fade(fade),
|
|
isActive
|
|
))
|
|
{
|
|
var stringInput = _state.ActivePathInput;
|
|
if (stringInput != null && !isActive && fileConsumerOpIsCompatible)
|
|
{
|
|
_state.ActiveAssetAddress = asset.Address;
|
|
|
|
ApplyResourcePath(asset, stringInput);
|
|
}
|
|
|
|
var io = ImGui.GetIO();
|
|
bool ctrl = io.KeyCtrl;
|
|
bool shift = io.KeyShift;
|
|
|
|
if (shift && _state.AnchorSelectionKey != default)
|
|
{
|
|
// TODO: This needs to be fixed for tree.
|
|
var range = GetRange(_state.LastVisibleTreeItemIds, _state.AnchorSelectionKey, asset.Id);
|
|
if (!ctrl) _state.Selection.Clear();
|
|
_state.Selection.AddSelection(range);
|
|
}
|
|
else if (ctrl)
|
|
{
|
|
if (isActive) _state.Selection.Deselect(asset.Id);
|
|
else _state.Selection.Select(asset.Id);
|
|
_state.AnchorSelectionKey = asset.Id;
|
|
}
|
|
else
|
|
{
|
|
_state.Selection.Clear();
|
|
_state.Selection.Select(asset.Id);
|
|
_state.AnchorSelectionKey = asset.Id;
|
|
}
|
|
}
|
|
|
|
CustomComponents.DrawSearchMatchUnderline(_state.SearchString, asset.FileSystemInfo?.Name,
|
|
ImGui.GetItemRectMin()
|
|
+ new Vector2(ImGui.GetFontSize() + 5, 3));
|
|
|
|
// IsItemVisible() would be true for partially visible items, so check the full rect
|
|
if (isActive && _state.HasActiveInstanceChanged && !IsLastItemFullyVisible())
|
|
{
|
|
ImGui.SetScrollHereY(0.5f);
|
|
}
|
|
|
|
// Stop expanding if item becomes visible
|
|
if (isActive && _expandToFileTriggered)
|
|
{
|
|
_expandToFileTriggered = false;
|
|
ImGui.SetScrollHereY(0.5f);
|
|
}
|
|
|
|
CustomComponents.ContextMenuForItem(drawMenuItems: () =>
|
|
{
|
|
if (ImGui.MenuItem("Edit externally"))
|
|
{
|
|
var absolutePath = asset.FullPath;
|
|
if (!string.IsNullOrEmpty(absolutePath))
|
|
{
|
|
CoreUi.Instance.OpenWithDefaultApplication(absolutePath);
|
|
}
|
|
}
|
|
|
|
if (ImGui.MenuItem("Reveal in Explorer"))
|
|
{
|
|
var absolutePath = asset.FullPath;
|
|
|
|
var folder = Path.GetDirectoryName(absolutePath);
|
|
if (!string.IsNullOrEmpty(folder))
|
|
{
|
|
try
|
|
{
|
|
CoreUi.Instance.OpenWithDefaultApplication(folder);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Log.Warning($"Failed to get directory for {folder} {e.Message}");
|
|
}
|
|
}
|
|
}
|
|
},
|
|
title: asset.FileSystemInfo?.Name,
|
|
id: "##symbolTreeSymbolContextMenu");
|
|
|
|
var draggingStarted = DragAndDropHandling.HandleDragSourceForLastItem(DragAndDropHandling.DragTypes.FileAsset, asset.Address);
|
|
if (draggingStarted && !isSelected)
|
|
{
|
|
_state.Selection.Clear();
|
|
_state.Selection.Select(asset.Id);
|
|
_state.AnchorSelectionKey = asset.Id;
|
|
}
|
|
|
|
var hasUses = AssetRegistry.ReferencesForAssetId.TryGetValue(asset.Id, out var uses);
|
|
if (!hasUses)
|
|
{
|
|
var pos = new Vector2(ImGui.GetWindowPos().X, cursorScreenPos.Y + (ImGui.GetFrameHeight() - 16 + 10) / 2);
|
|
Icons.DrawIconAtScreenPosition(Icon.Sleeping, pos, ImGui.GetWindowDrawList(), UiColors.Text.Fade(0.4f));
|
|
}
|
|
|
|
DrawAssetTooltip(asset, hasUses, uses);
|
|
|
|
}
|
|
|
|
ImGui.PopID();
|
|
}
|
|
|
|
private static void DrawAssetTooltip(Asset asset, bool hasUses, List<AssetReference>? uses)
|
|
{
|
|
if (!ImGui.IsItemHovered())
|
|
return;
|
|
|
|
ImGui.SetMouseCursor(ImGuiMouseCursor.ResizeAll); // Indicator for drag (actually not part of tooltip)
|
|
|
|
if (CustomComponents.BeginTooltip(600))
|
|
{
|
|
ImGui.BeginGroup();
|
|
{
|
|
var absolutePath = asset.FullPath;
|
|
var fileName = asset.FileSystemInfo?.Name ?? "Unknown";
|
|
var path = absolutePath != null && absolutePath.EndsWith(fileName)
|
|
? absolutePath[..^fileName.Length]
|
|
: absolutePath;
|
|
|
|
// FormInputs.AddVerticalSpace(2);
|
|
// CustomComponents.StylizedText($"in {path}", Fonts.FontSmall, UiColors.TextMuted);
|
|
|
|
FormInputs.AddVerticalSpace();
|
|
}
|
|
ImGui.EndGroup();
|
|
//ImGui.SameLine(0,10);
|
|
|
|
ImGui.BeginGroup();
|
|
{
|
|
var package = ResourcePackageManager.SharedResourcePackages.FirstOrDefault(p => p.Id == asset.PackageId);
|
|
ThumbnailManager.GetThumbnail(asset, package).AsImguiImage();
|
|
FormInputs.AddVerticalSpace();
|
|
}
|
|
|
|
CustomComponents.StylizedText($"File size : {StringUtils.GetReadableFileSize(asset.FileSize)}", Fonts.FontSmall, UiColors.TextMuted);
|
|
CustomComponents.StylizedText($"Last modified :{asset.FileSystemInfo?.LastWriteTime}",
|
|
Fonts.FontSmall, UiColors.TextMuted);
|
|
|
|
int useCount = uses != null ? uses.Count : 0;
|
|
|
|
string usedString = useCount > 0 ? $"Used by : {useCount} operators" : "Not used by any operator";
|
|
|
|
CustomComponents.StylizedText(usedString, Fonts.FontSmall, UiColors.TextMuted);
|
|
|
|
if (ImGui.GetIO().KeyShift)
|
|
{
|
|
ImGui.NewLine();
|
|
if (hasUses && uses != null)
|
|
{
|
|
CustomComponents.StylizedText("Symbols using this...", Fonts.FontSmall, UiColors.TextMuted);
|
|
foreach (var reference in uses)
|
|
{
|
|
DrawAssetReference(reference);
|
|
}
|
|
}
|
|
}
|
|
|
|
ImGui.EndGroup();
|
|
|
|
}
|
|
|
|
CustomComponents.EndTooltip();
|
|
}
|
|
|
|
private static void DrawAssetReference(AssetReference reference)
|
|
{
|
|
if (!SymbolRegistry.TryGetSymbol(reference.SymbolId, out var symbol))
|
|
{
|
|
Log.Debug("Symbol for asset reference not found? " + reference.SymbolId);
|
|
return;
|
|
}
|
|
|
|
if (!reference.IsDefaultValueReference)
|
|
{
|
|
if (!symbol.Children.TryGetValue(reference.SymbolChildId, out var symbolChild))
|
|
{
|
|
ImGui.TextUnformatted("??? child not found");
|
|
return;
|
|
}
|
|
|
|
ImGui.TextColored(UiColors.TextMuted, $"{symbol.Namespace}.");
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted($"{symbol.Name}");
|
|
ImGui.SameLine();
|
|
ImGui.TextColored(UiColors.TextMuted, $" » {symbolChild.Symbol.Name}");
|
|
return;
|
|
}
|
|
|
|
var inputDefinition = symbol.InputDefinitions.FirstOrDefault(i => i.Id == reference.InputId);
|
|
var inputName = inputDefinition?.Name ?? "???";
|
|
ImGui.TextColored(UiColors.TextMuted, $"{symbol.Namespace}.");
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted($"{symbol.Name}");
|
|
ImGui.SameLine();
|
|
|
|
ImGui.TextColored(UiColors.TextMuted, $".{inputName} (Default)");
|
|
}
|
|
|
|
private static bool ButtonWithIcon(string id, string label, Icon icon, Color iconColor, Color textColor, bool isActive)
|
|
{
|
|
var cursorPos = ImGui.GetCursorScreenPos();
|
|
var frameHeight = ImGui.GetFrameHeight();
|
|
|
|
var dummyDim = new Vector2(frameHeight);
|
|
if (!ImGui.IsRectVisible(cursorPos, cursorPos + dummyDim))
|
|
{
|
|
ImGui.Dummy(dummyDim); // maintain layout spacing
|
|
return false;
|
|
}
|
|
|
|
var iconSize = Icons.FontSize;
|
|
var padding = 4f;
|
|
Vector2 iconDim = new(iconSize);
|
|
|
|
var textSize = ImGui.CalcTextSize(label);
|
|
var buttonSize = new Vector2(iconDim.X + padding + textSize.X + padding * 2,
|
|
Math.Max(iconDim.Y + padding * 2, ImGui.GetFrameHeight()));
|
|
|
|
var pressed = ImGui.InvisibleButton(id, buttonSize);
|
|
|
|
var drawList = ImGui.GetWindowDrawList();
|
|
var buttonMin = ImGui.GetItemRectMin();
|
|
var buttonMax = ImGui.GetItemRectMax();
|
|
if (ImGui.IsItemHovered())
|
|
{
|
|
drawList.AddRectFilled(buttonMin, buttonMax, UiColors.BackgroundActive.Fade(0.2f), 5);
|
|
}
|
|
|
|
if (isActive)
|
|
{
|
|
drawList.AddRect(buttonMin, buttonMax, UiColors.StatusActivated, 5);
|
|
}
|
|
|
|
var iconPos = new Vector2(buttonMin.X + padding,
|
|
(int)(buttonMin.Y + (buttonSize.Y - iconDim.Y) * 0.5f) + 1);
|
|
|
|
Icons.GetGlyphDefinition(icon, out var uvRange, out _);
|
|
drawList.AddImage(ImGui.GetIO().Fonts.TexID,
|
|
iconPos,
|
|
iconPos + iconDim,
|
|
uvRange.Min,
|
|
uvRange.Max,
|
|
iconColor);
|
|
|
|
Vector2 textPos = new(iconPos.X + iconDim.X + padding,
|
|
buttonMin.Y + (buttonSize.Y - textSize.Y) * 0.5f);
|
|
|
|
drawList.AddText(textPos, textColor, label);
|
|
return pressed;
|
|
}
|
|
|
|
private static void ApplyResourcePath(Asset asset, InputSlot<string> inputSlot)
|
|
{
|
|
var instance = inputSlot.Parent;
|
|
var composition = instance.Parent;
|
|
if (composition == null)
|
|
{
|
|
Log.Warning("Can't find composition to apply resource path");
|
|
return;
|
|
}
|
|
|
|
inputSlot.Input.IsDefault = false;
|
|
|
|
var changeInputValueCommand = new ChangeInputValueCommand(composition.Symbol,
|
|
instance.SymbolChildId,
|
|
inputSlot.Input,
|
|
inputSlot.Input.Value);
|
|
|
|
// warning: we must not use Value because this will use by abstract resource to detect changes
|
|
inputSlot.TypedInputValue.Value = asset.Address;
|
|
|
|
inputSlot.DirtyFlag.ForceInvalidate();
|
|
inputSlot.Parent.Parent?.Symbol.InvalidateInputInAllChildInstances(inputSlot);
|
|
changeInputValueCommand.AssignNewValue(inputSlot.Input.Value);
|
|
UndoRedoStack.Add(changeInputValueCommand);
|
|
}
|
|
|
|
// Helper to find IDs between two points
|
|
private static IEnumerable<Guid> GetRange(List<Guid> list, Guid startId, Guid endId)
|
|
{
|
|
var start = list.FindIndex(id => id == startId);
|
|
var end = list.FindIndex(id => id == endId);
|
|
|
|
var min = Math.Min(start, end);
|
|
var max = Math.Max(start, end);
|
|
|
|
return list.Skip(min).Take(max - min + 1);
|
|
}
|
|
} |