|
|
|
|
@@ -24,7 +24,6 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
|
|
|
|
private readonly ProfileTagService _profileTagService;
|
|
|
|
|
private readonly UiSharedService _uiSharedService;
|
|
|
|
|
private readonly UserData? _userData;
|
|
|
|
|
private readonly GroupFullInfoDto? _groupInfo;
|
|
|
|
|
private readonly GroupData? _groupData;
|
|
|
|
|
private readonly bool _isGroupProfile;
|
|
|
|
|
private readonly bool _isLightfinderContext;
|
|
|
|
|
@@ -55,11 +54,11 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
|
|
|
|
PairUiService pairUiService,
|
|
|
|
|
Pair? pair,
|
|
|
|
|
UserData? userData,
|
|
|
|
|
GroupFullInfoDto? groupInfo,
|
|
|
|
|
GroupData? groupData,
|
|
|
|
|
bool isLightfinderContext,
|
|
|
|
|
string? lightfinderCid,
|
|
|
|
|
PerformanceCollectorService performanceCollector)
|
|
|
|
|
: base(logger, mediator, BuildWindowTitle(userData, groupInfo, isLightfinderContext), performanceCollector)
|
|
|
|
|
: base(logger, mediator, BuildWindowTitle(userData, groupData, isLightfinderContext), performanceCollector)
|
|
|
|
|
{
|
|
|
|
|
_uiSharedService = uiBuilder;
|
|
|
|
|
_serverManager = serverManager;
|
|
|
|
|
@@ -68,9 +67,8 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
|
|
|
|
Pair = pair;
|
|
|
|
|
_pairUiService = pairUiService;
|
|
|
|
|
_userData = userData;
|
|
|
|
|
_groupInfo = groupInfo;
|
|
|
|
|
_groupData = groupInfo?.Group;
|
|
|
|
|
_isGroupProfile = groupInfo is not null;
|
|
|
|
|
_groupData = groupData;
|
|
|
|
|
_isGroupProfile = groupData is not null;
|
|
|
|
|
_isLightfinderContext = isLightfinderContext;
|
|
|
|
|
_lightfinderCid = lightfinderCid;
|
|
|
|
|
|
|
|
|
|
@@ -117,12 +115,12 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
|
|
|
|
return fallback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string BuildWindowTitle(UserData? userData, GroupFullInfoDto? groupInfo, bool isLightfinderContext)
|
|
|
|
|
private static string BuildWindowTitle(UserData? userData, GroupData? groupData, bool isLightfinderContext)
|
|
|
|
|
{
|
|
|
|
|
if (groupInfo is not null)
|
|
|
|
|
if (groupData is not null)
|
|
|
|
|
{
|
|
|
|
|
var alias = groupInfo.GroupAliasOrGID;
|
|
|
|
|
return $"Syncshell Profile of {alias}##LightlessSyncStandaloneGroupProfileUI{groupInfo.Group.GID}";
|
|
|
|
|
var alias = groupData.AliasOrGID;
|
|
|
|
|
return $"Syncshell Profile of {alias}##LightlessSyncStandaloneGroupProfileUI{groupData.GID}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (userData is null)
|
|
|
|
|
@@ -185,7 +183,7 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
|
|
|
|
|
|
|
|
|
var profile = _lightlessProfileManager.GetLightlessProfile(userData);
|
|
|
|
|
IReadOnlyList<ProfileTagDefinition> profileTags = profile.Tags.Count > 0
|
|
|
|
|
? _profileTagService.ResolveTags(profile.Tags)
|
|
|
|
|
? ProfileTagService.ResolveTags(profile.Tags)
|
|
|
|
|
: Array.Empty<ProfileTagDefinition>();
|
|
|
|
|
|
|
|
|
|
if (_textureWrap == null || !profile.ImageData.Value.SequenceEqual(_lastProfilePicture))
|
|
|
|
|
@@ -705,7 +703,7 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
|
|
|
|
|
|
|
|
|
private void DrawGroupProfileWindow()
|
|
|
|
|
{
|
|
|
|
|
if (_groupInfo is null || _groupData is null)
|
|
|
|
|
if (_groupData is null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var scale = ImGuiHelpers.GlobalScale;
|
|
|
|
|
@@ -745,7 +743,7 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
|
|
|
|
|
|
|
|
|
var profile = _lightlessProfileManager.GetLightlessGroupProfile(_groupData);
|
|
|
|
|
IReadOnlyList<ProfileTagDefinition> profileTags = profile.Tags.Count > 0
|
|
|
|
|
? _profileTagService.ResolveTags(profile.Tags)
|
|
|
|
|
? ProfileTagService.ResolveTags(profile.Tags)
|
|
|
|
|
: Array.Empty<ProfileTagDefinition>();
|
|
|
|
|
|
|
|
|
|
if (_textureWrap == null || !profile.ProfileImageData.Value.SequenceEqual(_lastProfilePicture))
|
|
|
|
|
@@ -787,8 +785,8 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
|
|
|
|
int memberCount = 0;
|
|
|
|
|
List<Pair>? groupMembers = null;
|
|
|
|
|
var snapshot = _pairUiService.GetSnapshot();
|
|
|
|
|
var groupInfo = _groupInfo;
|
|
|
|
|
if (groupInfo is not null && snapshot.GroupsByGid.TryGetValue(groupInfo.GID, out var refreshedGroupInfo))
|
|
|
|
|
GroupFullInfoDto groupInfo = null;
|
|
|
|
|
if (_groupData is not null && snapshot.GroupsByGid.TryGetValue(_groupData.GID, out var refreshedGroupInfo))
|
|
|
|
|
{
|
|
|
|
|
groupInfo = refreshedGroupInfo;
|
|
|
|
|
}
|
|
|
|
|
@@ -912,172 +910,175 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
|
|
|
|
|
bool useVanityColors = false;
|
|
|
|
|
Vector4? vanityTextColor = null;
|
|
|
|
|
Vector4? vanityGlowColor = null;
|
|
|
|
|
string primaryHeaderText = _groupInfo.GroupAliasOrGID;
|
|
|
|
|
|
|
|
|
|
List<(string Text, bool UseVanityColor, bool Disabled)> secondaryHeaderLines = new()
|
|
|
|
|
if (_groupData is not null && groupInfo is not null)
|
|
|
|
|
{
|
|
|
|
|
string primaryHeaderText = _groupData.AliasOrGID;
|
|
|
|
|
|
|
|
|
|
List<(string Text, bool UseVanityColor, bool Disabled)> secondaryHeaderLines =
|
|
|
|
|
[
|
|
|
|
|
(_groupData.GID, false, true)
|
|
|
|
|
};
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
if (_groupInfo.Owner is not null)
|
|
|
|
|
secondaryHeaderLines.Add(($"Owner: {_groupInfo.Owner.AliasOrUID}", false, true));
|
|
|
|
|
if (groupInfo.Owner is not null)
|
|
|
|
|
secondaryHeaderLines.Add(($"Owner: {groupInfo.Owner.AliasOrUID}", false, true));
|
|
|
|
|
|
|
|
|
|
var infoStartY = MathF.Max(contentStartY, bannerHeight + style.WindowPadding.Y);
|
|
|
|
|
var aliasColumnX = infoOffsetX + 18f * scale;
|
|
|
|
|
ImGui.SetCursorPos(new Vector2(aliasColumnX, infoStartY));
|
|
|
|
|
var infoStartY = MathF.Max(contentStartY, bannerHeight + style.WindowPadding.Y);
|
|
|
|
|
var aliasColumnX = infoOffsetX + 18f * scale;
|
|
|
|
|
ImGui.SetCursorPos(new Vector2(aliasColumnX, infoStartY));
|
|
|
|
|
|
|
|
|
|
ImGui.BeginGroup();
|
|
|
|
|
using (_uiSharedService.UidFont.Push())
|
|
|
|
|
{
|
|
|
|
|
ImGui.TextUnformatted(primaryHeaderText);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var (text, useColor, disabled) in secondaryHeaderLines)
|
|
|
|
|
{
|
|
|
|
|
if (useColor && useVanityColors)
|
|
|
|
|
ImGui.BeginGroup();
|
|
|
|
|
using (_uiSharedService.UidFont.Push())
|
|
|
|
|
{
|
|
|
|
|
var seString = SeStringUtils.BuildFormattedPlayerName(text, vanityTextColor, vanityGlowColor);
|
|
|
|
|
SeStringUtils.RenderSeStringWithHitbox(seString, ImGui.GetCursorScreenPos(), ImGui.GetFont());
|
|
|
|
|
ImGui.TextUnformatted(primaryHeaderText);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var (text, useColor, disabled) in secondaryHeaderLines)
|
|
|
|
|
{
|
|
|
|
|
if (useColor && useVanityColors)
|
|
|
|
|
{
|
|
|
|
|
var seString = SeStringUtils.BuildFormattedPlayerName(text, vanityTextColor, vanityGlowColor);
|
|
|
|
|
SeStringUtils.RenderSeStringWithHitbox(seString, ImGui.GetCursorScreenPos(), ImGui.GetFont());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (disabled)
|
|
|
|
|
ImGui.TextDisabled(text);
|
|
|
|
|
else
|
|
|
|
|
ImGui.TextUnformatted(text);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ImGui.EndGroup();
|
|
|
|
|
var namesEnd = ImGui.GetCursorPos();
|
|
|
|
|
|
|
|
|
|
var aliasGroupRectMin = ImGui.GetItemRectMin();
|
|
|
|
|
var aliasGroupRectMax = ImGui.GetItemRectMax();
|
|
|
|
|
var aliasGroupLocalMin = aliasGroupRectMin - windowPos;
|
|
|
|
|
var aliasGroupLocalMax = aliasGroupRectMax - windowPos;
|
|
|
|
|
|
|
|
|
|
var tagsStartLocal = new Vector2(aliasGroupLocalMax.X + style.ItemSpacing.X + 25f * scale, aliasGroupLocalMin.Y + style.FramePadding.Y + 2f * scale);
|
|
|
|
|
ImGui.SetCursorPos(tagsStartLocal);
|
|
|
|
|
if (profileTags.Count > 0)
|
|
|
|
|
RenderProfileTags(profileTags, scale);
|
|
|
|
|
else
|
|
|
|
|
ImGui.TextDisabled("-- No tags set --");
|
|
|
|
|
var tagsEndLocal = ImGui.GetCursorPos();
|
|
|
|
|
var tagsBlockBottom = windowPos.Y + tagsEndLocal.Y;
|
|
|
|
|
var aliasBlockBottom = windowPos.Y + aliasGroupLocalMax.Y;
|
|
|
|
|
var aliasAndTagsBottomLocal = MathF.Max(aliasGroupLocalMax.Y, tagsEndLocal.Y);
|
|
|
|
|
var aliasAndTagsBlockBottom = MathF.Max(aliasBlockBottom, tagsBlockBottom);
|
|
|
|
|
|
|
|
|
|
var descriptionSeparatorSpacing = style.ItemSpacing.Y * 0.35f;
|
|
|
|
|
var descriptionSeparatorThickness = MathF.Max(1f, scale);
|
|
|
|
|
var descriptionExtraOffset = groupInfo.Owner is not null ? style.ItemSpacing.Y * 0.6f : 0f;
|
|
|
|
|
var descriptionStartLocal = new Vector2(aliasColumnX, aliasAndTagsBottomLocal + descriptionSeparatorSpacing + descriptionExtraOffset);
|
|
|
|
|
var horizontalInset = style.ItemSpacing.X * 0.5f;
|
|
|
|
|
var descriptionSeparatorStart = windowPos + new Vector2(aliasColumnX - horizontalInset, descriptionStartLocal.Y);
|
|
|
|
|
var descriptionSeparatorEnd = new Vector2(windowPos.X + windowSize.X - style.WindowPadding.X + horizontalInset, descriptionSeparatorStart.Y);
|
|
|
|
|
drawList.AddLine(descriptionSeparatorStart, descriptionSeparatorEnd, ImGui.GetColorU32(portraitFrameBorder), descriptionSeparatorThickness);
|
|
|
|
|
|
|
|
|
|
var descriptionContentStartLocal = new Vector2(aliasColumnX, descriptionStartLocal.Y + descriptionSeparatorThickness + descriptionSeparatorSpacing + style.FramePadding.Y * 0.75f);
|
|
|
|
|
ImGui.SetCursorPos(descriptionContentStartLocal);
|
|
|
|
|
ImGui.TextDisabled("Description");
|
|
|
|
|
ImGui.SetCursorPosX(aliasColumnX);
|
|
|
|
|
var descriptionRegionWidth = ImGui.GetContentRegionAvail().X;
|
|
|
|
|
if (descriptionRegionWidth <= 0f)
|
|
|
|
|
descriptionRegionWidth = 1f;
|
|
|
|
|
var measurementWrapWidth = MathF.Max(1f, descriptionRegionWidth - style.WindowPadding.X * 2f);
|
|
|
|
|
var hasDescription = !string.IsNullOrWhiteSpace(profile.Description);
|
|
|
|
|
float descriptionContentHeight;
|
|
|
|
|
float lineHeightWithSpacing;
|
|
|
|
|
using (_uiSharedService.GameFont.Push())
|
|
|
|
|
{
|
|
|
|
|
lineHeightWithSpacing = ImGui.GetTextLineHeightWithSpacing();
|
|
|
|
|
var measurementText = hasDescription
|
|
|
|
|
? NormalizeDescriptionForMeasurement(profile.Description!)
|
|
|
|
|
: GroupDescriptionPlaceholder;
|
|
|
|
|
if (string.IsNullOrWhiteSpace(measurementText))
|
|
|
|
|
measurementText = GroupDescriptionPlaceholder;
|
|
|
|
|
|
|
|
|
|
descriptionContentHeight = ImGui.CalcTextSize(measurementText, wrapWidth: measurementWrapWidth).Y;
|
|
|
|
|
if (descriptionContentHeight <= 0f)
|
|
|
|
|
descriptionContentHeight = lineHeightWithSpacing;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var maxDescriptionHeight = lineHeightWithSpacing * DescriptionMaxVisibleLines;
|
|
|
|
|
var descriptionChildHeight = Math.Clamp(descriptionContentHeight, lineHeightWithSpacing, maxDescriptionHeight);
|
|
|
|
|
|
|
|
|
|
RenderDescriptionChild(
|
|
|
|
|
"##StandaloneGroupDescription",
|
|
|
|
|
new Vector2(descriptionRegionWidth, descriptionChildHeight),
|
|
|
|
|
hasDescription ? profile.Description : null,
|
|
|
|
|
GroupDescriptionPlaceholder);
|
|
|
|
|
var descriptionEndLocal = ImGui.GetCursorPos();
|
|
|
|
|
var descriptionBlockBottom = windowPos.Y + descriptionEndLocal.Y;
|
|
|
|
|
aliasAndTagsBottomLocal = MathF.Max(aliasAndTagsBottomLocal, descriptionEndLocal.Y);
|
|
|
|
|
aliasAndTagsBlockBottom = MathF.Max(aliasAndTagsBlockBottom, descriptionBlockBottom);
|
|
|
|
|
|
|
|
|
|
var presenceLabelSpacing = style.ItemSpacing.Y * 0.35f;
|
|
|
|
|
var presenceAnchorY = MathF.Max(portraitFrameLocalMax.Y, aliasGroupLocalMax.Y);
|
|
|
|
|
var presenceStartLocal = new Vector2(portraitFrameLocalMin.X, presenceAnchorY + presenceLabelSpacing);
|
|
|
|
|
ImGui.SetCursorPos(presenceStartLocal);
|
|
|
|
|
ImGui.TextDisabled("Presence");
|
|
|
|
|
ImGui.SetCursorPosX(portraitFrameLocalMin.X);
|
|
|
|
|
if (presenceTokens.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
var presenceColumnWidth = MathF.Max(1f, aliasColumnX - portraitFrameLocalMin.X - style.ItemSpacing.X);
|
|
|
|
|
RenderPresenceTokens(presenceTokens, scale, presenceColumnWidth);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (disabled)
|
|
|
|
|
ImGui.TextDisabled(text);
|
|
|
|
|
else
|
|
|
|
|
ImGui.TextUnformatted(text);
|
|
|
|
|
ImGui.TextDisabled("-- No status flags --");
|
|
|
|
|
ImGui.Dummy(new Vector2(0f, style.ItemSpacing.Y * 0.25f));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var presenceContentEnd = ImGui.GetCursorPos();
|
|
|
|
|
var separatorSpacing = style.ItemSpacing.Y * 0.2f;
|
|
|
|
|
var separatorThickness = MathF.Max(1f, scale);
|
|
|
|
|
var separatorStartLocal = new Vector2(portraitFrameLocalMin.X, presenceContentEnd.Y + separatorSpacing);
|
|
|
|
|
var separatorStart = windowPos + separatorStartLocal;
|
|
|
|
|
var separatorEnd = new Vector2(portraitFrameMax.X, separatorStart.Y);
|
|
|
|
|
drawList.AddLine(separatorStart, separatorEnd, ImGui.GetColorU32(portraitFrameBorder), separatorThickness);
|
|
|
|
|
var afterSeparatorLocal = separatorStartLocal + new Vector2(0f, separatorThickness + separatorSpacing * 0.75f);
|
|
|
|
|
|
|
|
|
|
var columnStartLocalY = afterSeparatorLocal.Y;
|
|
|
|
|
var leftColumnX = portraitFrameLocalMin.X;
|
|
|
|
|
ImGui.SetCursorPos(new Vector2(leftColumnX, columnStartLocalY));
|
|
|
|
|
float leftColumnEndY = columnStartLocalY;
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(noteText))
|
|
|
|
|
{
|
|
|
|
|
ImGui.TextDisabled("Notes");
|
|
|
|
|
ImGui.SetCursorPosX(leftColumnX);
|
|
|
|
|
ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + ImGui.GetContentRegionAvail().X);
|
|
|
|
|
ImGui.TextUnformatted(noteText);
|
|
|
|
|
ImGui.PopTextWrapPos();
|
|
|
|
|
ImGui.SetCursorPos(new Vector2(leftColumnX, ImGui.GetCursorPosY() + style.ItemSpacing.Y * 0.5f));
|
|
|
|
|
leftColumnEndY = ImGui.GetCursorPosY();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
leftColumnEndY = MathF.Max(leftColumnEndY, ImGui.GetCursorPosY());
|
|
|
|
|
|
|
|
|
|
var columnsBottomLocal = leftColumnEndY;
|
|
|
|
|
var columnsBottom = windowPos.Y + columnsBottomLocal;
|
|
|
|
|
var topAreaBase = windowPos.Y + topAreaStart.Y;
|
|
|
|
|
var contentBlockBottom = MathF.Max(columnsBottom, aliasAndTagsBlockBottom);
|
|
|
|
|
var leftBlockBottom = MathF.Max(portraitBlockBottom, contentBlockBottom);
|
|
|
|
|
var topAreaHeight = leftBlockBottom - topAreaBase;
|
|
|
|
|
if (topAreaHeight < 0f)
|
|
|
|
|
topAreaHeight = 0f;
|
|
|
|
|
|
|
|
|
|
ImGui.SetCursorPos(new Vector2(leftColumnX, topAreaStart.Y + topAreaHeight + style.ItemSpacing.Y));
|
|
|
|
|
|
|
|
|
|
var finalCursorY = ImGui.GetCursorPosY();
|
|
|
|
|
var paddingY = ImGui.GetStyle().WindowPadding.Y;
|
|
|
|
|
var computedHeight = finalCursorY + paddingY;
|
|
|
|
|
var adjustedHeight = Math.Clamp(computedHeight, minHeight, maxAllowedHeight);
|
|
|
|
|
_lastComputedWindowHeight = adjustedHeight;
|
|
|
|
|
|
|
|
|
|
var finalSize = new Vector2(baseWidth, adjustedHeight);
|
|
|
|
|
Size = finalSize;
|
|
|
|
|
ImGui.SetWindowSize(finalSize, ImGuiCond.Always);
|
|
|
|
|
}
|
|
|
|
|
ImGui.EndGroup();
|
|
|
|
|
var namesEnd = ImGui.GetCursorPos();
|
|
|
|
|
|
|
|
|
|
var aliasGroupRectMin = ImGui.GetItemRectMin();
|
|
|
|
|
var aliasGroupRectMax = ImGui.GetItemRectMax();
|
|
|
|
|
var aliasGroupLocalMin = aliasGroupRectMin - windowPos;
|
|
|
|
|
var aliasGroupLocalMax = aliasGroupRectMax - windowPos;
|
|
|
|
|
|
|
|
|
|
var tagsStartLocal = new Vector2(aliasGroupLocalMax.X + style.ItemSpacing.X + 25f * scale, aliasGroupLocalMin.Y + style.FramePadding.Y + 2f * scale);
|
|
|
|
|
ImGui.SetCursorPos(tagsStartLocal);
|
|
|
|
|
if (profileTags.Count > 0)
|
|
|
|
|
RenderProfileTags(profileTags, scale);
|
|
|
|
|
else
|
|
|
|
|
ImGui.TextDisabled("-- No tags set --");
|
|
|
|
|
var tagsEndLocal = ImGui.GetCursorPos();
|
|
|
|
|
var tagsBlockBottom = windowPos.Y + tagsEndLocal.Y;
|
|
|
|
|
var aliasBlockBottom = windowPos.Y + aliasGroupLocalMax.Y;
|
|
|
|
|
var aliasAndTagsBottomLocal = MathF.Max(aliasGroupLocalMax.Y, tagsEndLocal.Y);
|
|
|
|
|
var aliasAndTagsBlockBottom = MathF.Max(aliasBlockBottom, tagsBlockBottom);
|
|
|
|
|
|
|
|
|
|
var descriptionSeparatorSpacing = style.ItemSpacing.Y * 0.35f;
|
|
|
|
|
var descriptionSeparatorThickness = MathF.Max(1f, scale);
|
|
|
|
|
var descriptionExtraOffset = _groupInfo.Owner is not null ? style.ItemSpacing.Y * 0.6f : 0f;
|
|
|
|
|
var descriptionStartLocal = new Vector2(aliasColumnX, aliasAndTagsBottomLocal + descriptionSeparatorSpacing + descriptionExtraOffset);
|
|
|
|
|
var horizontalInset = style.ItemSpacing.X * 0.5f;
|
|
|
|
|
var descriptionSeparatorStart = windowPos + new Vector2(aliasColumnX - horizontalInset, descriptionStartLocal.Y);
|
|
|
|
|
var descriptionSeparatorEnd = new Vector2(windowPos.X + windowSize.X - style.WindowPadding.X + horizontalInset, descriptionSeparatorStart.Y);
|
|
|
|
|
drawList.AddLine(descriptionSeparatorStart, descriptionSeparatorEnd, ImGui.GetColorU32(portraitFrameBorder), descriptionSeparatorThickness);
|
|
|
|
|
|
|
|
|
|
var descriptionContentStartLocal = new Vector2(aliasColumnX, descriptionStartLocal.Y + descriptionSeparatorThickness + descriptionSeparatorSpacing + style.FramePadding.Y * 0.75f);
|
|
|
|
|
ImGui.SetCursorPos(descriptionContentStartLocal);
|
|
|
|
|
ImGui.TextDisabled("Description");
|
|
|
|
|
ImGui.SetCursorPosX(aliasColumnX);
|
|
|
|
|
var descriptionRegionWidth = ImGui.GetContentRegionAvail().X;
|
|
|
|
|
if (descriptionRegionWidth <= 0f)
|
|
|
|
|
descriptionRegionWidth = 1f;
|
|
|
|
|
var measurementWrapWidth = MathF.Max(1f, descriptionRegionWidth - style.WindowPadding.X * 2f);
|
|
|
|
|
var hasDescription = !string.IsNullOrWhiteSpace(profile.Description);
|
|
|
|
|
float descriptionContentHeight;
|
|
|
|
|
float lineHeightWithSpacing;
|
|
|
|
|
using (_uiSharedService.GameFont.Push())
|
|
|
|
|
{
|
|
|
|
|
lineHeightWithSpacing = ImGui.GetTextLineHeightWithSpacing();
|
|
|
|
|
var measurementText = hasDescription
|
|
|
|
|
? NormalizeDescriptionForMeasurement(profile.Description!)
|
|
|
|
|
: GroupDescriptionPlaceholder;
|
|
|
|
|
if (string.IsNullOrWhiteSpace(measurementText))
|
|
|
|
|
measurementText = GroupDescriptionPlaceholder;
|
|
|
|
|
|
|
|
|
|
descriptionContentHeight = ImGui.CalcTextSize(measurementText, wrapWidth: measurementWrapWidth).Y;
|
|
|
|
|
if (descriptionContentHeight <= 0f)
|
|
|
|
|
descriptionContentHeight = lineHeightWithSpacing;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var maxDescriptionHeight = lineHeightWithSpacing * DescriptionMaxVisibleLines;
|
|
|
|
|
var descriptionChildHeight = Math.Clamp(descriptionContentHeight, lineHeightWithSpacing, maxDescriptionHeight);
|
|
|
|
|
|
|
|
|
|
RenderDescriptionChild(
|
|
|
|
|
"##StandaloneGroupDescription",
|
|
|
|
|
new Vector2(descriptionRegionWidth, descriptionChildHeight),
|
|
|
|
|
hasDescription ? profile.Description : null,
|
|
|
|
|
GroupDescriptionPlaceholder);
|
|
|
|
|
var descriptionEndLocal = ImGui.GetCursorPos();
|
|
|
|
|
var descriptionBlockBottom = windowPos.Y + descriptionEndLocal.Y;
|
|
|
|
|
aliasAndTagsBottomLocal = MathF.Max(aliasAndTagsBottomLocal, descriptionEndLocal.Y);
|
|
|
|
|
aliasAndTagsBlockBottom = MathF.Max(aliasAndTagsBlockBottom, descriptionBlockBottom);
|
|
|
|
|
|
|
|
|
|
var presenceLabelSpacing = style.ItemSpacing.Y * 0.35f;
|
|
|
|
|
var presenceAnchorY = MathF.Max(portraitFrameLocalMax.Y, aliasGroupLocalMax.Y);
|
|
|
|
|
var presenceStartLocal = new Vector2(portraitFrameLocalMin.X, presenceAnchorY + presenceLabelSpacing);
|
|
|
|
|
ImGui.SetCursorPos(presenceStartLocal);
|
|
|
|
|
ImGui.TextDisabled("Presence");
|
|
|
|
|
ImGui.SetCursorPosX(portraitFrameLocalMin.X);
|
|
|
|
|
if (presenceTokens.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
var presenceColumnWidth = MathF.Max(1f, aliasColumnX - portraitFrameLocalMin.X - style.ItemSpacing.X);
|
|
|
|
|
RenderPresenceTokens(presenceTokens, scale, presenceColumnWidth);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ImGui.TextDisabled("-- No status flags --");
|
|
|
|
|
ImGui.Dummy(new Vector2(0f, style.ItemSpacing.Y * 0.25f));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var presenceContentEnd = ImGui.GetCursorPos();
|
|
|
|
|
var separatorSpacing = style.ItemSpacing.Y * 0.2f;
|
|
|
|
|
var separatorThickness = MathF.Max(1f, scale);
|
|
|
|
|
var separatorStartLocal = new Vector2(portraitFrameLocalMin.X, presenceContentEnd.Y + separatorSpacing);
|
|
|
|
|
var separatorStart = windowPos + separatorStartLocal;
|
|
|
|
|
var separatorEnd = new Vector2(portraitFrameMax.X, separatorStart.Y);
|
|
|
|
|
drawList.AddLine(separatorStart, separatorEnd, ImGui.GetColorU32(portraitFrameBorder), separatorThickness);
|
|
|
|
|
var afterSeparatorLocal = separatorStartLocal + new Vector2(0f, separatorThickness + separatorSpacing * 0.75f);
|
|
|
|
|
|
|
|
|
|
var columnStartLocalY = afterSeparatorLocal.Y;
|
|
|
|
|
var leftColumnX = portraitFrameLocalMin.X;
|
|
|
|
|
ImGui.SetCursorPos(new Vector2(leftColumnX, columnStartLocalY));
|
|
|
|
|
float leftColumnEndY = columnStartLocalY;
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(noteText))
|
|
|
|
|
{
|
|
|
|
|
ImGui.TextDisabled("Notes");
|
|
|
|
|
ImGui.SetCursorPosX(leftColumnX);
|
|
|
|
|
ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + ImGui.GetContentRegionAvail().X);
|
|
|
|
|
ImGui.TextUnformatted(noteText);
|
|
|
|
|
ImGui.PopTextWrapPos();
|
|
|
|
|
ImGui.SetCursorPos(new Vector2(leftColumnX, ImGui.GetCursorPosY() + style.ItemSpacing.Y * 0.5f));
|
|
|
|
|
leftColumnEndY = ImGui.GetCursorPosY();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
leftColumnEndY = MathF.Max(leftColumnEndY, ImGui.GetCursorPosY());
|
|
|
|
|
|
|
|
|
|
var columnsBottomLocal = leftColumnEndY;
|
|
|
|
|
var columnsBottom = windowPos.Y + columnsBottomLocal;
|
|
|
|
|
var topAreaBase = windowPos.Y + topAreaStart.Y;
|
|
|
|
|
var contentBlockBottom = MathF.Max(columnsBottom, aliasAndTagsBlockBottom);
|
|
|
|
|
var leftBlockBottom = MathF.Max(portraitBlockBottom, contentBlockBottom);
|
|
|
|
|
var topAreaHeight = leftBlockBottom - topAreaBase;
|
|
|
|
|
if (topAreaHeight < 0f)
|
|
|
|
|
topAreaHeight = 0f;
|
|
|
|
|
|
|
|
|
|
ImGui.SetCursorPos(new Vector2(leftColumnX, topAreaStart.Y + topAreaHeight + style.ItemSpacing.Y));
|
|
|
|
|
|
|
|
|
|
var finalCursorY = ImGui.GetCursorPosY();
|
|
|
|
|
var paddingY = ImGui.GetStyle().WindowPadding.Y;
|
|
|
|
|
var computedHeight = finalCursorY + paddingY;
|
|
|
|
|
var adjustedHeight = Math.Clamp(computedHeight, minHeight, maxAllowedHeight);
|
|
|
|
|
_lastComputedWindowHeight = adjustedHeight;
|
|
|
|
|
|
|
|
|
|
var finalSize = new Vector2(baseWidth, adjustedHeight);
|
|
|
|
|
Size = finalSize;
|
|
|
|
|
ImGui.SetWindowSize(finalSize, ImGuiCond.Always);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private IDalamudTextureWrap? GetBannerTexture(byte[] bannerBytes)
|
|
|
|
|
|