collapsible texture details
This commit is contained in:
@@ -29,6 +29,9 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
private const float MaxTextureFilterPaneWidth = 405f;
|
private const float MaxTextureFilterPaneWidth = 405f;
|
||||||
private const float MinTextureDetailPaneWidth = 480f;
|
private const float MinTextureDetailPaneWidth = 480f;
|
||||||
private const float MaxTextureDetailPaneWidth = 720f;
|
private const float MaxTextureDetailPaneWidth = 720f;
|
||||||
|
private const float TextureFilterSplitterWidth = 8f;
|
||||||
|
private const float TextureDetailSplitterWidth = 12f;
|
||||||
|
private const float TextureDetailSplitterCollapsedWidth = 18f;
|
||||||
private const float SelectedFilePanelLogicalHeight = 90f;
|
private const float SelectedFilePanelLogicalHeight = 90f;
|
||||||
private static readonly Vector4 SelectedTextureRowTextColor = new(0f, 0f, 0f, 1f);
|
private static readonly Vector4 SelectedTextureRowTextColor = new(0f, 0f, 0f, 1f);
|
||||||
|
|
||||||
@@ -80,6 +83,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
private bool _modalOpen = false;
|
private bool _modalOpen = false;
|
||||||
private bool _showModal = false;
|
private bool _showModal = false;
|
||||||
private bool _textureRowsDirty = true;
|
private bool _textureRowsDirty = true;
|
||||||
|
private bool _textureDetailCollapsed = false;
|
||||||
private bool _conversionFailed;
|
private bool _conversionFailed;
|
||||||
private bool _showAlreadyAddedTransients = false;
|
private bool _showAlreadyAddedTransients = false;
|
||||||
private bool _acknowledgeReview = false;
|
private bool _acknowledgeReview = false;
|
||||||
@@ -1205,35 +1209,52 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
var availableSize = ImGui.GetContentRegionAvail();
|
var availableSize = ImGui.GetContentRegionAvail();
|
||||||
var windowPos = ImGui.GetWindowPos();
|
var windowPos = ImGui.GetWindowPos();
|
||||||
var spacingX = ImGui.GetStyle().ItemSpacing.X;
|
var spacingX = ImGui.GetStyle().ItemSpacing.X;
|
||||||
var splitterWidth = 6f * scale;
|
var filterSplitterWidth = TextureFilterSplitterWidth * scale;
|
||||||
|
var detailSplitterWidth = (_textureDetailCollapsed ? TextureDetailSplitterCollapsedWidth : TextureDetailSplitterWidth) * scale;
|
||||||
|
var totalSplitterWidth = filterSplitterWidth + detailSplitterWidth;
|
||||||
|
var totalSpacing = 2 * spacingX;
|
||||||
const float minFilterWidth = MinTextureFilterPaneWidth;
|
const float minFilterWidth = MinTextureFilterPaneWidth;
|
||||||
const float minDetailWidth = MinTextureDetailPaneWidth;
|
const float minDetailWidth = MinTextureDetailPaneWidth;
|
||||||
const float minCenterWidth = 340f;
|
const float minCenterWidth = 340f;
|
||||||
|
|
||||||
var dynamicFilterMax = Math.Max(minFilterWidth, availableSize.X - minDetailWidth - minCenterWidth - 2 * (splitterWidth + spacingX));
|
var detailMinForLayout = _textureDetailCollapsed ? 0f : minDetailWidth;
|
||||||
|
var dynamicFilterMax = Math.Max(minFilterWidth, availableSize.X - detailMinForLayout - minCenterWidth - totalSplitterWidth - totalSpacing);
|
||||||
var filterMaxBound = Math.Min(MaxTextureFilterPaneWidth, dynamicFilterMax);
|
var filterMaxBound = Math.Min(MaxTextureFilterPaneWidth, dynamicFilterMax);
|
||||||
var filterWidth = Math.Clamp(_textureFilterPaneWidth, minFilterWidth, filterMaxBound);
|
var filterWidth = Math.Clamp(_textureFilterPaneWidth, minFilterWidth, filterMaxBound);
|
||||||
|
|
||||||
var dynamicDetailMax = Math.Max(minDetailWidth, availableSize.X - filterWidth - minCenterWidth - 2 * (splitterWidth + spacingX));
|
var dynamicDetailMax = Math.Max(detailMinForLayout, availableSize.X - filterWidth - minCenterWidth - totalSplitterWidth - totalSpacing);
|
||||||
var detailMaxBound = Math.Min(MaxTextureDetailPaneWidth, dynamicDetailMax);
|
var detailMaxBound = _textureDetailCollapsed ? 0f : Math.Min(MaxTextureDetailPaneWidth, dynamicDetailMax);
|
||||||
var detailWidth = Math.Clamp(_textureDetailPaneWidth, minDetailWidth, detailMaxBound);
|
var detailWidth = _textureDetailCollapsed ? 0f : Math.Clamp(_textureDetailPaneWidth, minDetailWidth, detailMaxBound);
|
||||||
|
|
||||||
var centerWidth = availableSize.X - filterWidth - detailWidth - 2 * (splitterWidth + spacingX);
|
var centerWidth = availableSize.X - filterWidth - detailWidth - totalSplitterWidth - totalSpacing;
|
||||||
|
|
||||||
if (centerWidth < minCenterWidth)
|
if (centerWidth < minCenterWidth)
|
||||||
{
|
{
|
||||||
var deficit = minCenterWidth - centerWidth;
|
var deficit = minCenterWidth - centerWidth;
|
||||||
detailWidth = Math.Clamp(detailWidth - deficit, minDetailWidth,
|
if (!_textureDetailCollapsed)
|
||||||
Math.Min(MaxTextureDetailPaneWidth, Math.Max(minDetailWidth, availableSize.X - filterWidth - minCenterWidth - 2 * (splitterWidth + spacingX))));
|
{
|
||||||
centerWidth = availableSize.X - filterWidth - detailWidth - 2 * (splitterWidth + spacingX);
|
detailWidth = Math.Clamp(detailWidth - deficit, minDetailWidth,
|
||||||
if (centerWidth < minCenterWidth)
|
Math.Min(MaxTextureDetailPaneWidth, Math.Max(minDetailWidth, availableSize.X - filterWidth - minCenterWidth - totalSplitterWidth - totalSpacing)));
|
||||||
|
centerWidth = availableSize.X - filterWidth - detailWidth - totalSplitterWidth - totalSpacing;
|
||||||
|
if (centerWidth < minCenterWidth)
|
||||||
|
{
|
||||||
|
deficit = minCenterWidth - centerWidth;
|
||||||
|
filterWidth = Math.Clamp(filterWidth - deficit, minFilterWidth,
|
||||||
|
Math.Min(MaxTextureFilterPaneWidth, Math.Max(minFilterWidth, availableSize.X - detailWidth - minCenterWidth - totalSplitterWidth - totalSpacing)));
|
||||||
|
detailWidth = Math.Clamp(detailWidth, minDetailWidth,
|
||||||
|
Math.Min(MaxTextureDetailPaneWidth, Math.Max(minDetailWidth, availableSize.X - filterWidth - minCenterWidth - totalSplitterWidth - totalSpacing)));
|
||||||
|
centerWidth = availableSize.X - filterWidth - detailWidth - totalSplitterWidth - totalSpacing;
|
||||||
|
if (centerWidth < minCenterWidth)
|
||||||
|
{
|
||||||
|
centerWidth = minCenterWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
deficit = minCenterWidth - centerWidth;
|
|
||||||
filterWidth = Math.Clamp(filterWidth - deficit, minFilterWidth,
|
filterWidth = Math.Clamp(filterWidth - deficit, minFilterWidth,
|
||||||
Math.Min(MaxTextureFilterPaneWidth, Math.Max(minFilterWidth, availableSize.X - detailWidth - minCenterWidth - 2 * (splitterWidth + spacingX))));
|
Math.Min(MaxTextureFilterPaneWidth, Math.Max(minFilterWidth, availableSize.X - minCenterWidth - totalSplitterWidth - totalSpacing)));
|
||||||
detailWidth = Math.Clamp(detailWidth, minDetailWidth,
|
centerWidth = availableSize.X - filterWidth - detailWidth - totalSplitterWidth - totalSpacing;
|
||||||
Math.Min(MaxTextureDetailPaneWidth, Math.Max(minDetailWidth, availableSize.X - filterWidth - minCenterWidth - 2 * (splitterWidth + spacingX))));
|
|
||||||
centerWidth = availableSize.X - filterWidth - detailWidth - 2 * (splitterWidth + spacingX);
|
|
||||||
if (centerWidth < minCenterWidth)
|
if (centerWidth < minCenterWidth)
|
||||||
{
|
{
|
||||||
centerWidth = minCenterWidth;
|
centerWidth = minCenterWidth;
|
||||||
@@ -1242,7 +1263,10 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
_textureFilterPaneWidth = filterWidth;
|
_textureFilterPaneWidth = filterWidth;
|
||||||
_textureDetailPaneWidth = detailWidth;
|
if (!_textureDetailCollapsed)
|
||||||
|
{
|
||||||
|
_textureDetailPaneWidth = detailWidth;
|
||||||
|
}
|
||||||
|
|
||||||
ImGui.BeginGroup();
|
ImGui.BeginGroup();
|
||||||
using (var filters = ImRaii.Child("textureFilters", new Vector2(filterWidth, 0), true))
|
using (var filters = ImRaii.Child("textureFilters", new Vector2(filterWidth, 0), true))
|
||||||
@@ -1264,8 +1288,8 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
var filterMax = ImGui.GetItemRectMax();
|
var filterMax = ImGui.GetItemRectMax();
|
||||||
var filterHeight = filterMax.Y - filterMin.Y;
|
var filterHeight = filterMax.Y - filterMin.Y;
|
||||||
var filterTopLocal = filterMin - windowPos;
|
var filterTopLocal = filterMin - windowPos;
|
||||||
var maxFilterResize = Math.Min(MaxTextureFilterPaneWidth, Math.Max(minFilterWidth, availableSize.X - minCenterWidth - minDetailWidth - 2 * (splitterWidth + spacingX)));
|
var maxFilterResize = Math.Min(MaxTextureFilterPaneWidth, Math.Max(minFilterWidth, availableSize.X - minCenterWidth - detailMinForLayout - totalSplitterWidth - totalSpacing));
|
||||||
DrawVerticalResizeHandle("##textureFilterSplitter", filterTopLocal.Y, filterHeight, ref _textureFilterPaneWidth, minFilterWidth, maxFilterResize);
|
DrawVerticalResizeHandle("##textureFilterSplitter", filterTopLocal.Y, filterHeight, ref _textureFilterPaneWidth, minFilterWidth, maxFilterResize, out _);
|
||||||
|
|
||||||
TextureRow? selectedRow;
|
TextureRow? selectedRow;
|
||||||
ImGui.BeginGroup();
|
ImGui.BeginGroup();
|
||||||
@@ -1279,15 +1303,36 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
var tableMax = ImGui.GetItemRectMax();
|
var tableMax = ImGui.GetItemRectMax();
|
||||||
var tableHeight = tableMax.Y - tableMin.Y;
|
var tableHeight = tableMax.Y - tableMin.Y;
|
||||||
var tableTopLocal = tableMin - windowPos;
|
var tableTopLocal = tableMin - windowPos;
|
||||||
var maxDetailResize = Math.Min(MaxTextureDetailPaneWidth, Math.Max(minDetailWidth, availableSize.X - _textureFilterPaneWidth - minCenterWidth - 2 * (splitterWidth + spacingX)));
|
var maxDetailResize = Math.Min(MaxTextureDetailPaneWidth, Math.Max(minDetailWidth, availableSize.X - _textureFilterPaneWidth - minCenterWidth - totalSplitterWidth - totalSpacing));
|
||||||
DrawVerticalResizeHandle("##textureDetailSplitter", tableTopLocal.Y, tableHeight, ref _textureDetailPaneWidth, minDetailWidth, maxDetailResize, invert: true);
|
var detailToggle = DrawVerticalResizeHandle(
|
||||||
|
"##textureDetailSplitter",
|
||||||
ImGui.BeginGroup();
|
tableTopLocal.Y,
|
||||||
using (var detailChild = ImRaii.Child("textureDetailPane", new Vector2(detailWidth, 0), true))
|
tableHeight,
|
||||||
|
ref _textureDetailPaneWidth,
|
||||||
|
minDetailWidth,
|
||||||
|
maxDetailResize,
|
||||||
|
out var detailDragging,
|
||||||
|
invert: true,
|
||||||
|
showToggle: true,
|
||||||
|
isCollapsed: _textureDetailCollapsed);
|
||||||
|
if (detailToggle)
|
||||||
{
|
{
|
||||||
DrawTextureDetail(selectedRow);
|
_textureDetailCollapsed = !_textureDetailCollapsed;
|
||||||
|
}
|
||||||
|
if (_textureDetailCollapsed && detailDragging)
|
||||||
|
{
|
||||||
|
_textureDetailCollapsed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_textureDetailCollapsed)
|
||||||
|
{
|
||||||
|
ImGui.BeginGroup();
|
||||||
|
using (var detailChild = ImRaii.Child("textureDetailPane", new Vector2(detailWidth, 0), true))
|
||||||
|
{
|
||||||
|
DrawTextureDetail(selectedRow);
|
||||||
|
}
|
||||||
|
ImGui.EndGroup();
|
||||||
}
|
}
|
||||||
ImGui.EndGroup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawTextureFilters(
|
private void DrawTextureFilters(
|
||||||
@@ -1935,26 +1980,118 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawVerticalResizeHandle(string id, float topY, float height, ref float leftWidth, float minWidth, float maxWidth, bool invert = false)
|
private bool DrawVerticalResizeHandle(
|
||||||
|
string id,
|
||||||
|
float topY,
|
||||||
|
float height,
|
||||||
|
ref float leftWidth,
|
||||||
|
float minWidth,
|
||||||
|
float maxWidth,
|
||||||
|
out bool isDragging,
|
||||||
|
bool invert = false,
|
||||||
|
bool showToggle = false,
|
||||||
|
bool isCollapsed = false)
|
||||||
{
|
{
|
||||||
var scale = ImGuiHelpers.GlobalScale;
|
var scale = ImGuiHelpers.GlobalScale;
|
||||||
var splitterWidth = 8f * scale;
|
var splitterWidth = (showToggle
|
||||||
|
? (isCollapsed ? TextureDetailSplitterCollapsedWidth : TextureDetailSplitterWidth)
|
||||||
|
: TextureFilterSplitterWidth) * scale;
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
var cursor = ImGui.GetCursorPos();
|
var cursor = ImGui.GetCursorPos();
|
||||||
ImGui.SetCursorPos(new Vector2(cursor.X, topY));
|
var contentMin = ImGui.GetWindowContentRegionMin();
|
||||||
ImGui.PushStyleColor(ImGuiCol.Button, UIColors.Get("ButtonDefault"));
|
var contentMax = ImGui.GetWindowContentRegionMax();
|
||||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, UIColors.Get("LightlessPurple"));
|
var clampedTop = MathF.Max(topY, contentMin.Y);
|
||||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, UIColors.Get("LightlessPurpleActive"));
|
var clampedBottom = MathF.Min(topY + height, contentMax.Y);
|
||||||
ImGui.Button(id, new Vector2(splitterWidth, height));
|
var clampedHeight = MathF.Max(0f, clampedBottom - clampedTop);
|
||||||
ImGui.PopStyleColor(3);
|
var splitterRounding = ImGui.GetStyle().FrameRounding;
|
||||||
|
ImGui.SetCursorPos(new Vector2(cursor.X, clampedTop));
|
||||||
|
if (clampedHeight <= 0f)
|
||||||
|
{
|
||||||
|
isDragging = false;
|
||||||
|
ImGui.SetCursorPos(new Vector2(cursor.X + splitterWidth + ImGui.GetStyle().ItemSpacing.X, cursor.Y));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (ImGui.IsItemActive())
|
ImGui.InvisibleButton(id, new Vector2(splitterWidth, clampedHeight));
|
||||||
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
|
var rectMin = ImGui.GetItemRectMin();
|
||||||
|
var rectMax = ImGui.GetItemRectMax();
|
||||||
|
var windowPos = ImGui.GetWindowPos();
|
||||||
|
var clipMin = windowPos + contentMin;
|
||||||
|
var clipMax = windowPos + contentMax;
|
||||||
|
drawList.PushClipRect(clipMin, clipMax, true);
|
||||||
|
var clipInset = 1f * scale;
|
||||||
|
var drawMin = new Vector2(
|
||||||
|
MathF.Max(rectMin.X, clipMin.X),
|
||||||
|
MathF.Max(rectMin.Y, clipMin.Y));
|
||||||
|
var drawMax = new Vector2(
|
||||||
|
MathF.Min(rectMax.X, clipMax.X - clipInset),
|
||||||
|
MathF.Min(rectMax.Y, clipMax.Y));
|
||||||
|
var hovered = ImGui.IsItemHovered();
|
||||||
|
isDragging = ImGui.IsItemActive();
|
||||||
|
var baseColor = UIColors.Get("ButtonDefault");
|
||||||
|
var hoverColor = UIColors.Get("LightlessPurple");
|
||||||
|
var activeColor = UIColors.Get("LightlessPurpleActive");
|
||||||
|
var handleColor = isDragging ? activeColor : hovered ? hoverColor : baseColor;
|
||||||
|
drawList.AddRectFilled(drawMin, drawMax, UiSharedService.Color(handleColor), splitterRounding);
|
||||||
|
drawList.AddRect(drawMin, drawMax, UiSharedService.Color(new Vector4(1f, 1f, 1f, 0.12f)), splitterRounding);
|
||||||
|
|
||||||
|
bool toggleHovered = false;
|
||||||
|
bool toggleClicked = false;
|
||||||
|
if (showToggle)
|
||||||
|
{
|
||||||
|
var icon = isCollapsed ? FontAwesomeIcon.ChevronRight : FontAwesomeIcon.ChevronLeft;
|
||||||
|
Vector2 iconSize;
|
||||||
|
using (_uiSharedService.IconFont.Push())
|
||||||
|
{
|
||||||
|
iconSize = ImGui.CalcTextSize(icon.ToIconString());
|
||||||
|
}
|
||||||
|
|
||||||
|
var toggleHeight = MathF.Min(clampedHeight, 64f * scale);
|
||||||
|
var toggleMin = new Vector2(
|
||||||
|
drawMin.X,
|
||||||
|
drawMin.Y + (drawMax.Y - drawMin.Y - toggleHeight) / 2f);
|
||||||
|
var toggleMax = new Vector2(
|
||||||
|
drawMax.X,
|
||||||
|
toggleMin.Y + toggleHeight);
|
||||||
|
var toggleColorBase = UIColors.Get("LightlessPurple");
|
||||||
|
toggleHovered = ImGui.IsMouseHoveringRect(toggleMin, toggleMax);
|
||||||
|
var toggleBg = toggleHovered
|
||||||
|
? new Vector4(toggleColorBase.X, toggleColorBase.Y, toggleColorBase.Z, 0.65f)
|
||||||
|
: new Vector4(toggleColorBase.X, toggleColorBase.Y, toggleColorBase.Z, 0.35f);
|
||||||
|
if (toggleHovered)
|
||||||
|
{
|
||||||
|
UiSharedService.AttachToolTip(isCollapsed ? "Show texture details." : "Hide texture details.");
|
||||||
|
}
|
||||||
|
|
||||||
|
drawList.AddRectFilled(toggleMin, toggleMax, UiSharedService.Color(toggleBg), splitterRounding);
|
||||||
|
drawList.AddRect(toggleMin, toggleMax, UiSharedService.Color(toggleColorBase), splitterRounding);
|
||||||
|
|
||||||
|
var iconPos = new Vector2(
|
||||||
|
drawMin.X + (drawMax.X - drawMin.X - iconSize.X) / 2f,
|
||||||
|
drawMin.Y + (drawMax.Y - drawMin.Y - iconSize.Y) / 2f);
|
||||||
|
using (_uiSharedService.IconFont.Push())
|
||||||
|
{
|
||||||
|
drawList.AddText(iconPos, ImGui.GetColorU32(ImGuiCol.Text), icon.ToIconString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toggleHovered && ImGui.IsMouseReleased(ImGuiMouseButton.Left) && !ImGui.IsMouseDragging(ImGuiMouseButton.Left))
|
||||||
|
{
|
||||||
|
toggleClicked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDragging && !toggleHovered)
|
||||||
{
|
{
|
||||||
var delta = ImGui.GetIO().MouseDelta.X / scale;
|
var delta = ImGui.GetIO().MouseDelta.X / scale;
|
||||||
leftWidth += invert ? -delta : delta;
|
leftWidth += invert ? -delta : delta;
|
||||||
leftWidth = Math.Clamp(leftWidth, minWidth, maxWidth);
|
leftWidth = Math.Clamp(leftWidth, minWidth, maxWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drawList.PopClipRect();
|
||||||
|
|
||||||
ImGui.SetCursorPos(new Vector2(cursor.X + splitterWidth + ImGui.GetStyle().ItemSpacing.X, cursor.Y));
|
ImGui.SetCursorPos(new Vector2(cursor.X + splitterWidth + ImGui.GetStyle().ItemSpacing.X, cursor.Y));
|
||||||
|
return toggleClicked;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (IDalamudTextureWrap? Texture, bool IsLoading, string? Error) GetTexturePreview(TextureRow row)
|
private (IDalamudTextureWrap? Texture, bool IsLoading, string? Error) GetTexturePreview(TextureRow row)
|
||||||
@@ -2094,7 +2231,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ImGui.TextDisabled("-");
|
_uiSharedService.IconText(FontAwesomeIcon.Check, ImGuiColors.DalamudWhite);
|
||||||
UiSharedService.AttachToolTip("Already stored in a compressed format; additional compression is disabled.");
|
UiSharedService.AttachToolTip("Already stored in a compressed format; additional compression is disabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2175,6 +2312,10 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
|
|||||||
_textureSelections[key] = target;
|
_textureSelections[key] = target;
|
||||||
currentSelection = target;
|
currentSelection = target;
|
||||||
}
|
}
|
||||||
|
if (TextureMetadataHelper.TryGetRecommendationInfo(target, out var targetInfo))
|
||||||
|
{
|
||||||
|
UiSharedService.AttachToolTip($"{targetInfo.Title}{UiSharedService.TooltipSeparator}{targetInfo.Description}");
|
||||||
|
}
|
||||||
if (targetSelected)
|
if (targetSelected)
|
||||||
{
|
{
|
||||||
ImGui.SetItemDefaultFocus();
|
ImGui.SetItemDefaultFocus();
|
||||||
|
|||||||
Submodule Penumbra.Api updated: 1750c41b53...52a3216a52
Reference in New Issue
Block a user