improvements to data analysis ui
This commit is contained in:
@@ -34,6 +34,8 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
private const float TextureDetailSplitterWidth = 12f;
|
private const float TextureDetailSplitterWidth = 12f;
|
||||||
private const float TextureDetailSplitterCollapsedWidth = 18f;
|
private const float TextureDetailSplitterCollapsedWidth = 18f;
|
||||||
private const float SelectedFilePanelLogicalHeight = 90f;
|
private const float SelectedFilePanelLogicalHeight = 90f;
|
||||||
|
private const float TextureHoverPreviewDelaySeconds = 1.75f;
|
||||||
|
private const float TextureHoverPreviewSize = 350f;
|
||||||
private static readonly Vector4 SelectedTextureRowTextColor = new(0f, 0f, 0f, 1f);
|
private static readonly Vector4 SelectedTextureRowTextColor = new(0f, 0f, 0f, 1f);
|
||||||
|
|
||||||
private readonly CharacterAnalyzer _characterAnalyzer;
|
private readonly CharacterAnalyzer _characterAnalyzer;
|
||||||
@@ -77,6 +79,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
private string _selectedJobEntry = string.Empty;
|
private string _selectedJobEntry = string.Empty;
|
||||||
private string _filterGamePath = string.Empty;
|
private string _filterGamePath = string.Empty;
|
||||||
private string _filterFilePath = string.Empty;
|
private string _filterFilePath = string.Empty;
|
||||||
|
private string _textureHoverKey = string.Empty;
|
||||||
|
|
||||||
private int _conversionCurrentFileProgress = 0;
|
private int _conversionCurrentFileProgress = 0;
|
||||||
private int _conversionTotalJobs;
|
private int _conversionTotalJobs;
|
||||||
@@ -87,6 +90,11 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
private bool _textureRowsDirty = true;
|
private bool _textureRowsDirty = true;
|
||||||
private bool _textureDetailCollapsed = false;
|
private bool _textureDetailCollapsed = false;
|
||||||
private bool _conversionFailed;
|
private bool _conversionFailed;
|
||||||
|
private double _textureHoverStartTime = 0;
|
||||||
|
#if DEBUG
|
||||||
|
private bool _debugCompressionModalOpen = false;
|
||||||
|
private TextureConversionProgress? _debugConversionProgress;
|
||||||
|
#endif
|
||||||
private bool _showAlreadyAddedTransients = false;
|
private bool _showAlreadyAddedTransients = false;
|
||||||
private bool _acknowledgeReview = false;
|
private bool _acknowledgeReview = false;
|
||||||
|
|
||||||
@@ -135,21 +143,30 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
private void HandleConversionModal()
|
private void HandleConversionModal()
|
||||||
{
|
{
|
||||||
if (_conversionTask == null)
|
bool hasConversion = _conversionTask != null;
|
||||||
|
#if DEBUG
|
||||||
|
bool showDebug = _debugCompressionModalOpen && !hasConversion;
|
||||||
|
#else
|
||||||
|
const bool showDebug = false;
|
||||||
|
#endif
|
||||||
|
if (!hasConversion && !showDebug)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_conversionTask.IsCompleted)
|
if (hasConversion && _conversionTask!.IsCompleted)
|
||||||
{
|
{
|
||||||
ResetConversionModalState();
|
ResetConversionModalState();
|
||||||
|
if (!showDebug)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_showModal = true;
|
_showModal = true;
|
||||||
if (ImGui.BeginPopupModal("Texture Compression in Progress", ImGuiWindowFlags.AlwaysAutoResize))
|
if (ImGui.BeginPopupModal("Texture Compression in Progress", UiSharedService.PopupWindowFlags))
|
||||||
{
|
{
|
||||||
DrawConversionModalContent();
|
DrawConversionModalContent(showDebug);
|
||||||
ImGui.EndPopup();
|
ImGui.EndPopup();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -164,31 +181,190 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawConversionModalContent()
|
private void DrawConversionModalContent(bool isDebugPreview)
|
||||||
{
|
{
|
||||||
var progress = _lastConversionProgress;
|
var scale = ImGuiHelpers.GlobalScale;
|
||||||
|
TextureConversionProgress? progress;
|
||||||
|
#if DEBUG
|
||||||
|
progress = isDebugPreview ? _debugConversionProgress : _lastConversionProgress;
|
||||||
|
#else
|
||||||
|
progress = _lastConversionProgress;
|
||||||
|
#endif
|
||||||
var total = progress?.Total ?? Math.Max(_conversionTotalJobs, 1);
|
var total = progress?.Total ?? Math.Max(_conversionTotalJobs, 1);
|
||||||
var completed = progress != null
|
var completed = progress != null
|
||||||
? Math.Min(progress.Completed + 1, total)
|
? Math.Clamp(progress.Completed + 1, 0, total)
|
||||||
: _conversionCurrentFileProgress;
|
: Math.Clamp(_conversionCurrentFileProgress, 0, total);
|
||||||
var currentLabel = !string.IsNullOrEmpty(_conversionCurrentFileName)
|
var percent = total > 0 ? Math.Clamp(completed / (float)total, 0f, 1f) : 0f;
|
||||||
? _conversionCurrentFileName
|
|
||||||
: "Preparing...";
|
|
||||||
|
|
||||||
ImGui.TextUnformatted($"Compressing textures ({completed}/{total})");
|
var job = progress?.CurrentJob;
|
||||||
UiSharedService.TextWrapped("Current file: " + currentLabel);
|
var inputPath = job?.InputFile ?? string.Empty;
|
||||||
|
var targetLabel = job != null ? job.TargetType.ToString() : "Unknown";
|
||||||
|
var currentLabel = !string.IsNullOrEmpty(inputPath)
|
||||||
|
? Path.GetFileName(inputPath)
|
||||||
|
: !string.IsNullOrEmpty(_conversionCurrentFileName) ? _conversionCurrentFileName : "Preparing...";
|
||||||
|
var mapKind = !string.IsNullOrEmpty(inputPath)
|
||||||
|
? _textureMetadataHelper.DetermineMapKind(inputPath)
|
||||||
|
: TextureMapKind.Unknown;
|
||||||
|
|
||||||
if (_conversionFailed)
|
var accent = UIColors.Get("LightlessPurple");
|
||||||
|
var accentBg = new Vector4(accent.X, accent.Y, accent.Z, 0.18f);
|
||||||
|
var accentBorder = new Vector4(accent.X, accent.Y, accent.Z, 0.4f);
|
||||||
|
var headerHeight = MathF.Max(ImGui.GetTextLineHeightWithSpacing() * 2.6f, 46f * scale);
|
||||||
|
|
||||||
|
using (ImRaii.PushStyle(ImGuiStyleVar.ChildRounding, 6f * scale))
|
||||||
|
using (ImRaii.PushStyle(ImGuiStyleVar.ChildBorderSize, MathF.Max(1f, ImGui.GetStyle().ChildBorderSize)))
|
||||||
|
using (ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, new Vector2(12f * scale, 6f * scale)))
|
||||||
|
using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(12f * scale, 2f * scale)))
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.ChildBg, UiSharedService.Color(accentBg)))
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.Border, UiSharedService.Color(accentBorder)))
|
||||||
|
using (var header = ImRaii.Child("compressionHeader", new Vector2(-1f, headerHeight), true, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse))
|
||||||
{
|
{
|
||||||
UiSharedService.ColorText("Conversion encountered errors. Please review the log for details.", ImGuiColors.DalamudRed);
|
if (header)
|
||||||
|
{
|
||||||
|
if (ImGui.BeginTable("compressionHeaderTable", 2,
|
||||||
|
ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.NoBordersInBody | ImGuiTableFlags.NoHostExtendX))
|
||||||
|
{
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
DrawCompressionTitle(accent, scale);
|
||||||
|
|
||||||
|
var statusText = isDebugPreview ? "Preview mode" : "Working...";
|
||||||
|
var statusColor = isDebugPreview ? UIColors.Get("LightlessYellow") : ImGuiColors.DalamudGrey;
|
||||||
|
UiSharedService.ColorText(statusText, statusColor);
|
||||||
|
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
var progressText = $"{completed}/{total}";
|
||||||
|
var percentText = $"{percent * 100f:0}%";
|
||||||
|
var summaryText = $"{progressText} ({percentText})";
|
||||||
|
var summaryWidth = ImGui.CalcTextSize(summaryText).X;
|
||||||
|
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + MathF.Max(0f, ImGui.GetColumnWidth() - summaryWidth));
|
||||||
|
UiSharedService.ColorText(summaryText, ImGuiColors.DalamudGrey);
|
||||||
|
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(6);
|
||||||
|
|
||||||
|
using (ImRaii.PushStyle(ImGuiStyleVar.FrameRounding, 4f * scale))
|
||||||
|
using (ImRaii.PushStyle(ImGuiStyleVar.FramePadding, new Vector2(0f, 4f * scale)))
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.FrameBg, UiSharedService.Color(new Vector4(0.15f, 0.15f, 0.18f, 1f))))
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.PlotHistogram, UiSharedService.Color(accent)))
|
||||||
|
{
|
||||||
|
ImGui.ProgressBar(percent, new Vector2(-1f, 0f), $"{percent * 100f:0}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(6);
|
||||||
|
|
||||||
|
var infoAccent = UIColors.Get("LightlessBlue");
|
||||||
|
var infoBg = new Vector4(infoAccent.X, infoAccent.Y, infoAccent.Z, 0.12f);
|
||||||
|
var infoBorder = new Vector4(infoAccent.X, infoAccent.Y, infoAccent.Z, 0.32f);
|
||||||
|
const int detailRows = 3;
|
||||||
|
var detailHeight = MathF.Max(ImGui.GetTextLineHeightWithSpacing() * (detailRows + 1.2f), 72f * scale);
|
||||||
|
|
||||||
|
using (ImRaii.PushStyle(ImGuiStyleVar.ChildRounding, 5f * scale))
|
||||||
|
using (ImRaii.PushStyle(ImGuiStyleVar.ChildBorderSize, MathF.Max(1f, ImGui.GetStyle().ChildBorderSize)))
|
||||||
|
using (ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, new Vector2(10f * scale, 6f * scale)))
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.ChildBg, UiSharedService.Color(infoBg)))
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.Border, UiSharedService.Color(infoBorder)))
|
||||||
|
using (var details = ImRaii.Child("compressionDetail", new Vector2(-1f, detailHeight), true, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse))
|
||||||
|
{
|
||||||
|
if (details)
|
||||||
|
{
|
||||||
|
if (ImGui.BeginTable("compressionDetailTable", 2,
|
||||||
|
ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoBordersInBody | ImGuiTableFlags.PadOuterX))
|
||||||
|
{
|
||||||
|
DrawDetailRow("Current file", currentLabel, inputPath);
|
||||||
|
DrawDetailRow("Target format", targetLabel, null);
|
||||||
|
DrawDetailRow("Map type", mapKind.ToString(), null);
|
||||||
|
ImGui.EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_conversionFailed && !isDebugPreview)
|
||||||
|
{
|
||||||
|
ImGuiHelpers.ScaledDummy(4);
|
||||||
|
_uiSharedService.IconText(FontAwesomeIcon.ExclamationTriangle, ImGuiColors.DalamudRed);
|
||||||
|
ImGui.SameLine(0f, 6f * scale);
|
||||||
|
UiSharedService.TextWrapped("Conversion encountered errors. Please review the log for details.", color: ImGuiColors.DalamudRed);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(6);
|
||||||
|
if (!isDebugPreview)
|
||||||
|
{
|
||||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.StopCircle, "Cancel conversion"))
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.StopCircle, "Cancel conversion"))
|
||||||
{
|
{
|
||||||
_conversionCancellationTokenSource.Cancel();
|
_conversionCancellationTokenSource.Cancel();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Times, "Close preview"))
|
||||||
|
{
|
||||||
|
CloseDebugCompressionModal();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
UiSharedService.SetScaledWindowSize(520);
|
UiSharedService.SetScaledWindowSize(600);
|
||||||
|
|
||||||
|
void DrawDetailRow(string label, string value, string? tooltip)
|
||||||
|
{
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudGrey))
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted(label);
|
||||||
|
}
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.TextUnformatted(value);
|
||||||
|
if (!string.IsNullOrEmpty(tooltip))
|
||||||
|
{
|
||||||
|
UiSharedService.AttachToolTip(tooltip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawCompressionTitle(Vector4 iconColor, float localScale)
|
||||||
|
{
|
||||||
|
const string title = "Texture Compression";
|
||||||
|
var spacing = 6f * localScale;
|
||||||
|
|
||||||
|
var iconText = FontAwesomeIcon.CompressArrowsAlt.ToIconString();
|
||||||
|
Vector2 iconSize;
|
||||||
|
using (_uiSharedService.IconFont.Push())
|
||||||
|
{
|
||||||
|
iconSize = ImGui.CalcTextSize(iconText);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 titleSize;
|
||||||
|
using (_uiSharedService.MediumFont.Push())
|
||||||
|
{
|
||||||
|
titleSize = ImGui.CalcTextSize(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
var lineHeight = MathF.Max(iconSize.Y, titleSize.Y);
|
||||||
|
var iconOffsetY = (lineHeight - iconSize.Y) / 2f;
|
||||||
|
var textOffsetY = (lineHeight - titleSize.Y) / 2f;
|
||||||
|
|
||||||
|
var start = ImGui.GetCursorScreenPos();
|
||||||
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
|
|
||||||
|
using (_uiSharedService.IconFont.Push())
|
||||||
|
{
|
||||||
|
drawList.AddText(new Vector2(start.X, start.Y + iconOffsetY), UiSharedService.Color(iconColor), iconText);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (_uiSharedService.MediumFont.Push())
|
||||||
|
{
|
||||||
|
var textPos = new Vector2(start.X + iconSize.X + spacing, start.Y + textOffsetY);
|
||||||
|
drawList.AddText(textPos, ImGui.GetColorU32(ImGuiCol.Text), title);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Dummy(new Vector2(iconSize.X + spacing + titleSize.X, lineHeight));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResetConversionModalState()
|
private void ResetConversionModalState()
|
||||||
@@ -202,6 +378,41 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
_conversionTotalJobs = 0;
|
_conversionTotalJobs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
private void OpenCompressionDebugModal()
|
||||||
|
{
|
||||||
|
if (_conversionTask != null && !_conversionTask.IsCompleted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_debugCompressionModalOpen = true;
|
||||||
|
_debugConversionProgress = new TextureConversionProgress(
|
||||||
|
Completed: 3,
|
||||||
|
Total: 10,
|
||||||
|
CurrentJob: new TextureConversionJob(
|
||||||
|
@"C:\Lightless\Mods\Textures\example_diffuse.tex",
|
||||||
|
@"C:\Lightless\Mods\Textures\example_diffuse_bc7.tex",
|
||||||
|
Penumbra.Api.Enums.TextureType.Bc7Tex));
|
||||||
|
_showModal = true;
|
||||||
|
_modalOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetDebugCompressionModalState()
|
||||||
|
{
|
||||||
|
_debugCompressionModalOpen = false;
|
||||||
|
_debugConversionProgress = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloseDebugCompressionModal()
|
||||||
|
{
|
||||||
|
ResetDebugCompressionModalState();
|
||||||
|
_showModal = false;
|
||||||
|
_modalOpen = false;
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private void RefreshAnalysisCache()
|
private void RefreshAnalysisCache()
|
||||||
{
|
{
|
||||||
if (!_hasUpdate)
|
if (!_hasUpdate)
|
||||||
@@ -757,6 +968,9 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
ResetTextureFilters();
|
ResetTextureFilters();
|
||||||
InvalidateTextureRows();
|
InvalidateTextureRows();
|
||||||
_conversionFailed = false;
|
_conversionFailed = false;
|
||||||
|
#if DEBUG
|
||||||
|
ResetDebugCompressionModalState();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
@@ -1955,6 +2169,17 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
InvalidateTextureRows();
|
InvalidateTextureRows();
|
||||||
}
|
}
|
||||||
|
#if DEBUG
|
||||||
|
ImGui.SameLine();
|
||||||
|
using (ImRaii.Disabled(conversionRunning || !UiSharedService.CtrlPressed()))
|
||||||
|
{
|
||||||
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Cog, "Preview popup (debug)", 200f * scale))
|
||||||
|
{
|
||||||
|
OpenCompressionDebugModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UiSharedService.AttachToolTip("Hold CTRL to open the compression popup preview.");
|
||||||
|
#endif
|
||||||
|
|
||||||
TextureRow? lastSelected = null;
|
TextureRow? lastSelected = null;
|
||||||
using (var table = ImRaii.Table("textureDataTable", 9,
|
using (var table = ImRaii.Table("textureDataTable", 9,
|
||||||
@@ -2335,11 +2560,30 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
if (_texturePreviews.TryGetValue(key, out var state))
|
if (_texturePreviews.TryGetValue(key, out var state))
|
||||||
{
|
{
|
||||||
|
var loadTask = state.LoadTask;
|
||||||
|
if (loadTask is { IsCompleted: false })
|
||||||
|
{
|
||||||
|
_ = loadTask.ContinueWith(_ =>
|
||||||
|
{
|
||||||
|
state.Texture?.Dispose();
|
||||||
|
}, TaskScheduler.Default);
|
||||||
|
}
|
||||||
|
|
||||||
state.Texture?.Dispose();
|
state.Texture?.Dispose();
|
||||||
_texturePreviews.Remove(key);
|
_texturePreviews.Remove(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ClearHoverPreview(TextureRow row)
|
||||||
|
{
|
||||||
|
if (string.Equals(_selectedTextureKey, row.Key, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResetPreview(row.Key);
|
||||||
|
}
|
||||||
|
|
||||||
private TextureResolutionInfo? GetTextureResolution(TextureRow row)
|
private TextureResolutionInfo? GetTextureResolution(TextureRow row)
|
||||||
{
|
{
|
||||||
if (_textureResolutionCache.TryGetValue(row.Key, out var cached))
|
if (_textureResolutionCache.TryGetValue(row.Key, out var cached))
|
||||||
@@ -2440,7 +2684,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
UiSharedService.AttachToolTip("Already stored in a compressed format; additional compression is disabled.");
|
UiSharedService.AttachToolTip("Already stored in a compressed format; additional compression is disabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawSelectableColumn(isSelected, () =>
|
var nameHovered = DrawSelectableColumn(isSelected, () =>
|
||||||
{
|
{
|
||||||
var selectableLabel = $"{row.DisplayName}##texName{index}";
|
var selectableLabel = $"{row.DisplayName}##texName{index}";
|
||||||
if (ImGui.Selectable(selectableLabel, isSelected))
|
if (ImGui.Selectable(selectableLabel, isSelected))
|
||||||
@@ -2448,20 +2692,20 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
_selectedTextureKey = isSelected ? string.Empty : key;
|
_selectedTextureKey = isSelected ? string.Empty : key;
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => UiSharedService.AttachToolTip($"{row.PrimaryFilePath}{UiSharedService.TooltipSeparator}{string.Join(Environment.NewLine, row.GamePaths)}");
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
DrawSelectableColumn(isSelected, () =>
|
_ = DrawSelectableColumn(isSelected, () =>
|
||||||
{
|
{
|
||||||
ImGui.TextUnformatted(row.Slot);
|
ImGui.TextUnformatted(row.Slot);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
DrawSelectableColumn(isSelected, () =>
|
_ = DrawSelectableColumn(isSelected, () =>
|
||||||
{
|
{
|
||||||
ImGui.TextUnformatted(row.MapKind.ToString());
|
ImGui.TextUnformatted(row.MapKind.ToString());
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
DrawSelectableColumn(isSelected, () =>
|
_ = DrawSelectableColumn(isSelected, () =>
|
||||||
{
|
{
|
||||||
Action? tooltipAction = null;
|
Action? tooltipAction = null;
|
||||||
ImGui.TextUnformatted(row.Format);
|
ImGui.TextUnformatted(row.Format);
|
||||||
@@ -2475,7 +2719,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
return tooltipAction;
|
return tooltipAction;
|
||||||
});
|
});
|
||||||
|
|
||||||
DrawSelectableColumn(isSelected, () =>
|
_ = DrawSelectableColumn(isSelected, () =>
|
||||||
{
|
{
|
||||||
if (row.SuggestedTarget.HasValue)
|
if (row.SuggestedTarget.HasValue)
|
||||||
{
|
{
|
||||||
@@ -2537,19 +2781,21 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
UiSharedService.AttachToolTip("This texture is already compressed and cannot be processed again.");
|
UiSharedService.AttachToolTip("This texture is already compressed and cannot be processed again.");
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawSelectableColumn(isSelected, () =>
|
_ = DrawSelectableColumn(isSelected, () =>
|
||||||
{
|
{
|
||||||
ImGui.TextUnformatted(UiSharedService.ByteToString(row.OriginalSize));
|
ImGui.TextUnformatted(UiSharedService.ByteToString(row.OriginalSize));
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
DrawSelectableColumn(isSelected, () =>
|
_ = DrawSelectableColumn(isSelected, () =>
|
||||||
{
|
{
|
||||||
ImGui.TextUnformatted(UiSharedService.ByteToString(row.CompressedSize));
|
ImGui.TextUnformatted(UiSharedService.ByteToString(row.CompressedSize));
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
DrawTextureRowHoverTooltip(row, nameHovered);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawSelectableColumn(bool isSelected, Func<Action?> draw)
|
private static bool DrawSelectableColumn(bool isSelected, Func<Action?> draw)
|
||||||
{
|
{
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
if (isSelected)
|
if (isSelected)
|
||||||
@@ -2558,6 +2804,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
var after = draw();
|
var after = draw();
|
||||||
|
var hovered = ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled | ImGuiHoveredFlags.AllowWhenBlockedByActiveItem);
|
||||||
|
|
||||||
if (isSelected)
|
if (isSelected)
|
||||||
{
|
{
|
||||||
@@ -2565,6 +2812,127 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
after?.Invoke();
|
after?.Invoke();
|
||||||
|
return hovered;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawTextureRowHoverTooltip(TextureRow row, bool isHovered)
|
||||||
|
{
|
||||||
|
if (!isHovered)
|
||||||
|
{
|
||||||
|
if (string.Equals(_textureHoverKey, row.Key, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
_textureHoverKey = string.Empty;
|
||||||
|
_textureHoverStartTime = 0;
|
||||||
|
ClearHoverPreview(row);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var now = ImGui.GetTime();
|
||||||
|
if (!string.Equals(_textureHoverKey, row.Key, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
_textureHoverKey = row.Key;
|
||||||
|
_textureHoverStartTime = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
var elapsed = now - _textureHoverStartTime;
|
||||||
|
if (elapsed < TextureHoverPreviewDelaySeconds)
|
||||||
|
{
|
||||||
|
var progress = (float)Math.Clamp(elapsed / TextureHoverPreviewDelaySeconds, 0f, 1f);
|
||||||
|
DrawTextureRowTextTooltip(row, progress);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawTextureRowPreviewTooltip(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawTextureRowTextTooltip(TextureRow row, float progress)
|
||||||
|
{
|
||||||
|
ImGui.BeginTooltip();
|
||||||
|
ImGui.SetWindowFontScale(1f);
|
||||||
|
DrawTextureRowTooltipBody(row);
|
||||||
|
ImGuiHelpers.ScaledDummy(4);
|
||||||
|
DrawTextureHoverProgressBar(progress, GetTooltipContentWidth());
|
||||||
|
ImGui.EndTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawTextureRowPreviewTooltip(TextureRow row)
|
||||||
|
{
|
||||||
|
ImGui.BeginTooltip();
|
||||||
|
ImGui.SetWindowFontScale(1f);
|
||||||
|
|
||||||
|
DrawTextureRowTooltipBody(row);
|
||||||
|
ImGuiHelpers.ScaledDummy(4);
|
||||||
|
|
||||||
|
var previewSize = new Vector2(TextureHoverPreviewSize * ImGuiHelpers.GlobalScale);
|
||||||
|
var (previewTexture, previewLoading, previewError) = GetTexturePreview(row);
|
||||||
|
if (previewTexture != null)
|
||||||
|
{
|
||||||
|
ImGui.Image(previewTexture.Handle, previewSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using (ImRaii.Child("textureHoverPreview", previewSize, true))
|
||||||
|
{
|
||||||
|
UiSharedService.TextWrapped(previewLoading ? "Loading preview..." : previewError ?? "Preview unavailable.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.EndTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DrawTextureRowTooltipBody(TextureRow row)
|
||||||
|
{
|
||||||
|
var text = row.GamePaths.Count > 0
|
||||||
|
? $"{row.PrimaryFilePath}{UiSharedService.TooltipSeparator}{string.Join(Environment.NewLine, row.GamePaths)}"
|
||||||
|
: row.PrimaryFilePath;
|
||||||
|
|
||||||
|
var wrapWidth = GetTextureHoverTooltipWidth();
|
||||||
|
ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + wrapWidth);
|
||||||
|
if (text.Contains(UiSharedService.TooltipSeparator, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
var splitText = text.Split(UiSharedService.TooltipSeparator, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
for (int i = 0; i < splitText.Length; i++)
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted(splitText[i]);
|
||||||
|
if (i != splitText.Length - 1)
|
||||||
|
{
|
||||||
|
ImGui.Separator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted(text);
|
||||||
|
}
|
||||||
|
ImGui.PopTextWrapPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DrawTextureHoverProgressBar(float progress, float width)
|
||||||
|
{
|
||||||
|
var scale = ImGuiHelpers.GlobalScale;
|
||||||
|
var barHeight = 4f * scale;
|
||||||
|
var barWidth = width > 0f ? width : -1f;
|
||||||
|
using (ImRaii.PushStyle(ImGuiStyleVar.FrameRounding, 3f * scale))
|
||||||
|
using (ImRaii.PushStyle(ImGuiStyleVar.FramePadding, Vector2.Zero))
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.PlotHistogram, UiSharedService.Color(UIColors.Get("LightlessPurple"))))
|
||||||
|
{
|
||||||
|
ImGui.ProgressBar(progress, new Vector2(barWidth, barHeight), string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float GetTextureHoverTooltipWidth()
|
||||||
|
=> ImGui.GetFontSize() * 35f;
|
||||||
|
|
||||||
|
private static float GetTooltipContentWidth()
|
||||||
|
{
|
||||||
|
var min = ImGui.GetWindowContentRegionMin();
|
||||||
|
var max = ImGui.GetWindowContentRegionMax();
|
||||||
|
var width = max.X - min.X;
|
||||||
|
if (width <= 0f)
|
||||||
|
{
|
||||||
|
width = ImGui.GetContentRegionAvail().X;
|
||||||
|
}
|
||||||
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ApplyTextureRowBackground(TextureRow row, bool isSelected)
|
private static void ApplyTextureRowBackground(TextureRow row, bool isSelected)
|
||||||
|
|||||||
Reference in New Issue
Block a user