UI Update

This commit is contained in:
2025-10-19 21:56:19 +02:00
parent 89fa1a999f
commit d891dceb28
12 changed files with 1002 additions and 472 deletions

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<AssemblyName>UmbraSync</AssemblyName>
<RootNamespace>UmbraSync</RootNamespace>
<Version>0.1.9.5</Version>
<Version>0.1.9.6</Version>
</PropertyGroup>
<ItemGroup>

View File

@@ -182,17 +182,22 @@ public sealed class Plugin : IDalamudPlugin
// add scoped services
collection.AddScoped<CacheMonitor>();
collection.AddScoped<UiFactory>();
collection.AddScoped<WindowMediatorSubscriberBase, SettingsUi>();
collection.AddScoped<WindowMediatorSubscriberBase, CompactUi>();
collection.AddScoped<SettingsUi>();
collection.AddScoped<CompactUi>();
collection.AddScoped<EditProfileUi>();
collection.AddScoped<DataAnalysisUi>();
collection.AddScoped<AutoDetectUi>();
collection.AddScoped<WindowMediatorSubscriberBase>(sp => sp.GetRequiredService<SettingsUi>());
collection.AddScoped<WindowMediatorSubscriberBase>(sp => sp.GetRequiredService<CompactUi>());
collection.AddScoped<WindowMediatorSubscriberBase, IntroUi>();
collection.AddScoped<WindowMediatorSubscriberBase, DownloadUi>();
collection.AddScoped<WindowMediatorSubscriberBase, AutoDetectUi>();
collection.AddScoped<WindowMediatorSubscriberBase>(sp => sp.GetRequiredService<AutoDetectUi>());
collection.AddScoped<WindowMediatorSubscriberBase, ChangelogUi>();
collection.AddScoped<WindowMediatorSubscriberBase, PopoutProfileUi>();
collection.AddScoped<WindowMediatorSubscriberBase, DataAnalysisUi>();
collection.AddScoped<WindowMediatorSubscriberBase>(sp => sp.GetRequiredService<DataAnalysisUi>());
collection.AddScoped<WindowMediatorSubscriberBase, EventViewerUI>();
collection.AddScoped<WindowMediatorSubscriberBase, CharaDataHubUi>();
collection.AddScoped<WindowMediatorSubscriberBase, EditProfileUi>();
collection.AddScoped<WindowMediatorSubscriberBase>(sp => sp.GetRequiredService<EditProfileUi>());
collection.AddScoped<WindowMediatorSubscriberBase, PopupHandler>();
collection.AddScoped<WindowMediatorSubscriberBase, TypingIndicatorOverlay>();
collection.AddScoped<IPopupHandler, ReportPopupHandler>();

View File

@@ -90,6 +90,11 @@ public class AutoDetectUi : WindowMediatorSubscriberBase
}
}
public void DrawInline()
{
DrawInternal();
}
private static void DrawStyledTab(string label, Vector4 accent, Vector4 inactive, Vector4 hover, Action draw, bool disabled = false)
{
var tabColor = disabled ? ImGuiColors.DalamudGrey3 : inactive;

View File

@@ -21,7 +21,9 @@ using MareSynchronos.WebAPI.Files;
using MareSynchronos.WebAPI.Files.Models;
using MareSynchronos.WebAPI.SignalR.Utils;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Numerics;
@@ -51,6 +53,10 @@ public class CompactUi : WindowMediatorSubscriberBase
private readonly CharacterAnalyzer _characterAnalyzer;
private readonly UidDisplayHandler _uidDisplayHandler;
private readonly UiSharedService _uiSharedService;
private readonly EditProfileUi _editProfileUi;
private readonly SettingsUi _settingsUi;
private readonly AutoDetectUi _autoDetectUi;
private readonly DataAnalysisUi _dataAnalysisUi;
private bool _buttonState;
private string _characterOrCommentFilter = string.Empty;
private Pair? _lastAddedUser;
@@ -60,19 +66,48 @@ public class CompactUi : WindowMediatorSubscriberBase
private string _pairToAdd = string.Empty;
private int _secretKeyIdx = -1;
private bool _showModalForUserAddition;
private bool _showSyncShells;
private bool _wasOpen;
private bool _nearbyOpen = true;
private bool _selfAnalysisOpen = false;
private List<Services.Mediator.NearbyEntry> _nearbyEntries = new();
private const long SelfAnalysisSizeWarningThreshold = 300L * 1024 * 1024;
private const long SelfAnalysisTriangleWarningThreshold = 150_000;
private CompactUiSection _activeSection = CompactUiSection.VisiblePairs;
private const float SidebarWidth = 42f;
private const float SidebarIconSize = 22f;
private const float ContentFontScale = 0.92f;
private static readonly Vector4 SidebarButtonColor = new(0.08f, 0.08f, 0.10f, 0.92f);
private static readonly Vector4 SidebarButtonHoverColor = new(0.12f, 0.12f, 0.16f, 0.95f);
private static readonly Vector4 SidebarButtonActiveColor = new(0.16f, 0.16f, 0.22f, 0.95f);
private enum CompactUiSection
{
VisiblePairs,
IndividualPairs,
Syncshells,
AutoDetect,
CharacterAnalysis,
CharacterDataHub,
EditProfile,
Settings
}
private enum PairContentMode
{
All,
VisibleOnly
}
public CompactUi(ILogger<CompactUi> logger, UiSharedService uiShared, MareConfigService configService, ApiController apiController, PairManager pairManager, ChatService chatService,
ServerConfigurationManager serverManager, MareMediator mediator, FileUploadManager fileTransferManager, UidDisplayHandler uidDisplayHandler, CharaDataManager charaDataManager,
NearbyPendingService nearbyPendingService,
AutoDetectRequestService autoDetectRequestService,
CharacterAnalyzer characterAnalyzer,
PerformanceCollectorService performanceCollectorService)
PerformanceCollectorService performanceCollectorService,
EditProfileUi editProfileUi,
SettingsUi settingsUi,
AutoDetectUi autoDetectUi,
DataAnalysisUi dataAnalysisUi)
: base(logger, mediator, "###UmbraSyncMainUI", performanceCollectorService)
{
_uiSharedService = uiShared;
@@ -86,6 +121,10 @@ public class CompactUi : WindowMediatorSubscriberBase
_nearbyPending = nearbyPendingService;
_autoDetectRequestService = autoDetectRequestService;
_characterAnalyzer = characterAnalyzer;
_editProfileUi = editProfileUi;
_settingsUi = settingsUi;
_autoDetectUi = autoDetectUi;
_dataAnalysisUi = dataAnalysisUi;
var tagHandler = new TagHandler(_serverManager);
_groupPanel = new(this, uiShared, _pairManager, chatService, uidDisplayHandler, _configService, _serverManager, _charaDataManager, _autoDetectRequestService);
@@ -127,8 +166,8 @@ public class CompactUi : WindowMediatorSubscriberBase
SizeConstraints = new WindowSizeConstraints()
{
MinimumSize = new Vector2(350, 400),
MaximumSize = new Vector2(350, 2000),
MinimumSize = new Vector2(420, 320),
MaximumSize = new Vector2(1400, 2000),
};
}
@@ -144,130 +183,43 @@ public class CompactUi : WindowMediatorSubscriberBase
using var buttonHover = ImRaii.PushColor(ImGuiCol.ButtonHovered, UiSharedService.AccentHoverColor);
using var buttonActive = ImRaii.PushColor(ImGuiCol.ButtonActive, UiSharedService.AccentActiveColor);
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().WindowPadding.Y - 1f * ImGuiHelpers.GlobalScale + ImGui.GetStyle().ItemSpacing.Y);
var sidebarWidth = ImGuiHelpers.ScaledVector2(SidebarWidth, 0).X;
ImGui.SetWindowFontScale(ContentFontScale);
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ImGui.GetStyle().FramePadding * ContentFontScale);
ImGui.BeginChild("compact-sidebar", new Vector2(sidebarWidth, 0), false, ImGuiWindowFlags.NoScrollbar);
DrawSidebar();
ImGui.EndChild();
ImGui.SameLine();
float separatorHeight = ImGui.GetWindowHeight() - ImGui.GetStyle().WindowPadding.Y * 2f;
float separatorX = ImGui.GetCursorPosX();
float separatorY = ImGui.GetCursorPosY();
var drawList = ImGui.GetWindowDrawList();
var start = ImGui.GetCursorScreenPos();
var end = new Vector2(start.X, start.Y + separatorHeight);
drawList.AddLine(start, end, ImGui.GetColorU32(new Vector4(1f, 1f, 1f, 0.08f)), 1f * ImGuiHelpers.GlobalScale);
ImGui.SetCursorPos(new Vector2(separatorX + 6f * ImGuiHelpers.GlobalScale, separatorY));
ImGui.BeginChild("compact-content", Vector2.Zero, false);
WindowContentWidth = UiSharedService.GetWindowContentRegionWidth();
if (!_apiController.IsCurrentVersion)
{
var ver = _apiController.CurrentClientVersion;
var unsupported = "UNSUPPORTED VERSION";
using (_uiSharedService.UidFont.Push())
{
var uidTextSize = ImGui.CalcTextSize(unsupported);
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMax().X + ImGui.GetWindowContentRegionMin().X) / 2 - uidTextSize.X / 2);
ImGui.AlignTextToFramePadding();
ImGui.TextColored(UiSharedService.AccentColor, unsupported);
}
UiSharedService.ColorTextWrapped($"Your UmbraSync installation is out of date, the current version is {ver.Major}.{ver.Minor}.{ver.Build}. " +
$"It is highly recommended to keep UmbraSync up to date. Open /xlplugins and update the plugin.", UiSharedService.AccentColor);
DrawUnsupportedVersionBanner();
ImGui.Separator();
}
using (ImRaii.PushId("header")) DrawUIDHeader();
ImGui.Separator();
using (ImRaii.PushId("serverstatus")) DrawServerStatus();
if (_apiController.ServerState is ServerState.Connected)
{
var hasShownSyncShells = _showSyncShells;
using (var hoverColor = ImRaii.PushColor(ImGuiCol.ButtonHovered, UiSharedService.AccentHoverColor))
using (var activeColor = ImRaii.PushColor(ImGuiCol.ButtonActive, UiSharedService.AccentActiveColor))
{
if (!hasShownSyncShells)
{
using var selectedColor = ImRaii.PushColor(ImGuiCol.Button, accent);
using (ImRaii.PushFont(UiBuilder.IconFont))
{
if (ImGui.Button(FontAwesomeIcon.User.ToIconString(), new Vector2((UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X) / 2, 30 * ImGuiHelpers.GlobalScale)))
{
_showSyncShells = false;
}
}
}
else
{
using (ImRaii.PushFont(UiBuilder.IconFont))
{
if (ImGui.Button(FontAwesomeIcon.User.ToIconString(), new Vector2((UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X) / 2, 30 * ImGuiHelpers.GlobalScale)))
{
_showSyncShells = false;
}
}
}
UiSharedService.AttachToolTip("Individual pairs");
ImGui.SameLine();
if (hasShownSyncShells)
{
using var selectedColor = ImRaii.PushColor(ImGuiCol.Button, accent);
using (ImRaii.PushFont(UiBuilder.IconFont))
{
if (ImGui.Button(FontAwesomeIcon.UserFriends.ToIconString(), new Vector2((UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X) / 2, 30 * ImGuiHelpers.GlobalScale)))
{
_showSyncShells = true;
}
}
}
else
{
using (ImRaii.PushFont(UiBuilder.IconFont))
{
if (ImGui.Button(FontAwesomeIcon.UserFriends.ToIconString(), new Vector2((UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X) / 2, 30 * ImGuiHelpers.GlobalScale)))
{
_showSyncShells = true;
}
}
}
UiSharedService.AttachToolTip("Syncshells");
}
DrawDefaultSyncSettings();
if (!hasShownSyncShells)
{
using (ImRaii.PushId("pairlist")) DrawPairList();
}
else
{
using (ImRaii.PushId("syncshells")) _groupPanel.DrawSyncshells();
}
ImGui.Separator();
using (ImRaii.PushId("transfers")) DrawTransfers();
TransferPartHeight = ImGui.GetCursorPosY() - TransferPartHeight;
using (ImRaii.PushId("group-user-popup")) _selectPairsForGroupUi.Draw(_pairManager.DirectPairs);
using (ImRaii.PushId("grouping-popup")) _selectGroupForPairUi.Draw();
}
if (_configService.Current.OpenPopupOnAdd && _pairManager.LastAddedUser != null)
{
_lastAddedUser = _pairManager.LastAddedUser;
_pairManager.LastAddedUser = null;
ImGui.OpenPopup("Set Notes for New User");
_showModalForUserAddition = true;
_lastAddedUserComment = string.Empty;
}
DrawMainContent();
if (ImGui.BeginPopupModal("Set Notes for New User", ref _showModalForUserAddition, UiSharedService.PopupWindowFlags))
{
if (_lastAddedUser == null)
{
_showModalForUserAddition = false;
}
else
{
UiSharedService.TextWrapped($"You have successfully added {_lastAddedUser.UserData.AliasOrUID}. Set a local note for the user in the field below:");
ImGui.InputTextWithHint("##noteforuser", $"Note for {_lastAddedUser.UserData.AliasOrUID}", ref _lastAddedUserComment, 100);
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, "Save Note"))
{
_serverManager.SetNoteForUid(_lastAddedUser.UserData.UID, _lastAddedUserComment);
_lastAddedUser = null;
_lastAddedUserComment = string.Empty;
_showModalForUserAddition = false;
}
}
UiSharedService.SetScaledWindowSize(275);
ImGui.EndPopup();
}
ImGui.EndChild();
var pos = ImGui.GetWindowPos();
var size = ImGui.GetWindowSize();
@@ -277,6 +229,9 @@ public class CompactUi : WindowMediatorSubscriberBase
_lastPosition = pos;
Mediator.Publish(new CompactUiChange(_lastSize, _lastPosition));
}
ImGui.PopStyleVar();
ImGui.SetWindowFontScale(1f);
}
public override void OnClose()
@@ -287,7 +242,7 @@ public class CompactUi : WindowMediatorSubscriberBase
private void DrawDefaultSyncSettings()
{
ImGuiHelpers.ScaledDummy(4f);
ImGuiHelpers.ScaledDummy(3f);
using (ImRaii.PushId("sync-defaults"))
{
const string soundLabel = "Audio";
@@ -303,9 +258,6 @@ public class CompactUi : WindowMediatorSubscriberBase
bool showNearby = _configService.Current.EnableAutoDetectDiscovery;
int pendingInvites = _nearbyPending.Pending.Count;
const string nearbyLabel = "AutoDetect";
var soundIcon = soundsDisabled ? FontAwesomeIcon.VolumeMute : FontAwesomeIcon.VolumeUp;
var animIcon = animsDisabled ? FontAwesomeIcon.WindowClose : FontAwesomeIcon.Running;
var vfxIcon = vfxDisabled ? FontAwesomeIcon.TimesCircle : FontAwesomeIcon.Sun;
@@ -314,9 +266,7 @@ public class CompactUi : WindowMediatorSubscriberBase
float audioWidth = _uiSharedService.GetIconTextButtonSize(soundIcon, soundLabel);
float animWidth = _uiSharedService.GetIconTextButtonSize(animIcon, animLabel);
float vfxWidth = _uiSharedService.GetIconTextButtonSize(vfxIcon, vfxLabel);
float nearbyWidth = showNearby ? _uiSharedService.GetIconTextButtonSize(FontAwesomeIcon.UserPlus, pendingInvites > 0 ? $"{nearbyLabel} ({pendingInvites})" : nearbyLabel) : 0f;
int buttonCount = 3 + (showNearby ? 1 : 0);
float totalWidth = audioWidth + animWidth + vfxWidth + nearbyWidth + spacing * (buttonCount - 1);
float totalWidth = audioWidth + animWidth + vfxWidth + spacing * 2f;
float available = ImGui.GetContentRegionAvail().X;
float startCursorX = ImGui.GetCursorPosX();
if (totalWidth < available)
@@ -351,18 +301,10 @@ public class CompactUi : WindowMediatorSubscriberBase
},
() => DisableStateTooltip(vfxSubject, _configService.Current.DefaultDisableVfx), spacing);
if (showNearby)
if (showNearby && pendingInvites > 0)
{
ImGui.SameLine(0, spacing);
var autodetectLabel = pendingInvites > 0 ? $"{nearbyLabel} ({pendingInvites})" : nearbyLabel;
if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserPlus, autodetectLabel, nearbyWidth))
{
Mediator.Publish(new UiToggleMessage(typeof(AutoDetectUi)));
}
string tooltip = pendingInvites > 0
? string.Format("Vous avez {0} invitation{1} reçue. Ouvrez l\'interface AutoDetect pour y répondre.", pendingInvites, pendingInvites > 1 ? "s" : string.Empty)
: "Ouvrir les outils AutoDetect (invitations et proximité).\n\nLes demandes reçues sont listées dans l\'onglet 'Invitations'.";
UiSharedService.AttachToolTip(tooltip);
ImGuiHelpers.ScaledDummy(3f);
UiSharedService.ColorTextWrapped($"AutoDetect : {pendingInvites} invitation(s) en attente. Utilisez l'icône AutoDetect dans la barre latérale pour y répondre.", ImGuiColors.DalamudYellow);
}
DrawSelfAnalysisPreview();
@@ -374,11 +316,30 @@ public class CompactUi : WindowMediatorSubscriberBase
{
using (ImRaii.PushId("self-analysis"))
{
if (!ImGui.CollapsingHeader("Self Analysis"))
UiSharedService.DrawCard("self-analysis-card", () =>
{
bool arrowState = _selfAnalysisOpen;
UiSharedService.DrawArrowToggle(ref arrowState, "##self-analysis-toggle");
if (arrowState != _selfAnalysisOpen)
{
_selfAnalysisOpen = arrowState;
}
ImGui.SameLine(0f, 6f * ImGuiHelpers.GlobalScale);
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Self Analysis");
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
{
_selfAnalysisOpen = !_selfAnalysisOpen;
}
if (!_selfAnalysisOpen)
{
return;
}
ImGuiHelpers.ScaledDummy(4f);
var summary = _characterAnalyzer.CurrentSummary;
bool isAnalyzing = _characterAnalyzer.IsAnalysisRunning;
@@ -420,7 +381,7 @@ public class CompactUi : WindowMediatorSubscriberBase
ImGuiColors.DalamudYellow);
}
ImGuiHelpers.ScaledDummy(4f);
ImGuiHelpers.ScaledDummy(3f);
UiSharedService.DrawGrouped(() =>
{
@@ -467,7 +428,7 @@ public class CompactUi : WindowMediatorSubscriberBase
ImGui.EndTable();
}
}, rounding: 4f, expectedWidth: ImGui.GetContentRegionAvail().X);
}, rounding: 4f, expectedWidth: ImGui.GetContentRegionAvail().X, drawBorder: false);
string lastAnalysisText;
Vector4 lastAnalysisColor = ImGuiColors.DalamudGrey2;
@@ -489,12 +450,13 @@ public class CompactUi : WindowMediatorSubscriberBase
ImGuiHelpers.ScaledDummy(2f);
UiSharedService.ColorTextWrapped(lastAnalysisText, lastAnalysisColor);
ImGuiHelpers.ScaledDummy(4f);
ImGuiHelpers.ScaledDummy(3f);
if (_uiSharedService.IconTextButton(FontAwesomeIcon.PersonCircleQuestion, "Ouvrir l'analyse détaillée"))
{
Mediator.Publish(new UiToggleMessage(typeof(DataAnalysisUi)));
}
}, stretchWidth: true);
}
}
@@ -688,50 +650,124 @@ public class CompactUi : WindowMediatorSubscriberBase
}
}
private void DrawPairList()
private void DrawPairList(PairContentMode mode)
{
if (mode == PairContentMode.All)
{
using (ImRaii.PushId("addpair")) DrawAddPair();
using (ImRaii.PushId("pairs")) DrawPairs();
}
using (ImRaii.PushId("pairs")) DrawPairs(mode);
TransferPartHeight = ImGui.GetCursorPosY();
using (ImRaii.PushId("filter")) DrawFilter();
}
private void DrawPairs()
private void DrawPairs(PairContentMode mode)
{
var ySize = TransferPartHeight == 0
? 1
: (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y) - TransferPartHeight - ImGui.GetCursorPosY();
var users = GetFilteredUsers().OrderBy(u => u.GetPairSortKey(), StringComparer.Ordinal);
float availableHeight = ImGui.GetContentRegionAvail().Y;
float ySize;
if (TransferPartHeight <= 0)
{
float reserve = ImGui.GetFrameHeightWithSpacing() * 2f;
ySize = availableHeight - reserve;
if (ySize <= 0)
{
ySize = System.Math.Max(availableHeight, 1f);
}
}
else
{
ySize = (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y) - TransferPartHeight - ImGui.GetCursorPosY();
}
var allUsers = GetFilteredUsers().OrderBy(u => u.GetPairSortKey(), StringComparer.Ordinal).ToList();
var visibleUsersSource = allUsers.Where(u => u.IsVisible).ToList();
var nonVisibleUsers = allUsers.Where(u => !u.IsVisible).ToList();
ImGui.BeginChild("list", new Vector2(WindowContentWidth, ySize), border: false);
if (mode == PairContentMode.All)
{
var pendingCount = _nearbyPending?.Pending.Count ?? 0;
if (pendingCount > 0)
{
UiSharedService.ColorTextWrapped("Invitation AutoDetect en attente. Ouvrez l\'interface AutoDetect pour gérer vos demandes.", ImGuiColors.DalamudYellow);
ImGuiHelpers.ScaledDummy(4);
}
}
var onlineUsers = users.Where(u => u.UserPair!.OtherPermissions.IsPaired() && (u.IsOnline || u.UserPair!.OwnPermissions.IsPaused())).Select(c => new DrawUserPair("Online" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager, _serverManager)).ToList();
var visibleUsers = users.Where(u => u.IsVisible).Select(c => new DrawUserPair("Visible" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager, _serverManager)).ToList();
var offlineUsers = users.Where(u => !u.UserPair!.OtherPermissions.IsPaired() || (!u.IsOnline && !u.UserPair!.OwnPermissions.IsPaused())).Select(c => new DrawUserPair("Offline" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager, _serverManager)).ToList();
_pairGroupsUi.Draw(visibleUsers, onlineUsers, offlineUsers);
if (mode == PairContentMode.VisibleOnly)
{
var visibleUsers = visibleUsersSource.Select(c => new DrawUserPair("Visible" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager, _serverManager)).ToList();
if (visibleUsers.Count == 0)
{
UiSharedService.ColorTextWrapped("Aucune paire visible pour l'instant.", ImGuiColors.DalamudGrey3);
}
else
{
foreach (var visibleUser in visibleUsers)
{
visibleUser.DrawPairedClient();
}
}
if (_configService.Current.EnableAutoDetectDiscovery)
{
DrawNearbyCard();
}
}
else
{
var visibleUsers = visibleUsersSource.Select(c => new DrawUserPair("Visible" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager, _serverManager)).ToList();
var onlineUsers = nonVisibleUsers.Where(u => u.UserPair!.OtherPermissions.IsPaired() && (u.IsOnline || u.UserPair!.OwnPermissions.IsPaused()))
.Select(c => new DrawUserPair("Online" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager, _serverManager))
.ToList();
var offlineUsers = nonVisibleUsers.Where(u => !u.UserPair!.OtherPermissions.IsPaired() || (!u.IsOnline && !u.UserPair!.OwnPermissions.IsPaused()))
.Select(c => new DrawUserPair("Offline" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager, _serverManager))
.ToList();
Action? drawVisibleExtras = null;
if (_configService.Current.EnableAutoDetectDiscovery)
{
drawVisibleExtras = () => DrawNearbyCard();
}
_pairGroupsUi.Draw(visibleUsers, onlineUsers, offlineUsers, drawVisibleExtras);
}
ImGui.EndChild();
}
private void DrawNearbyCard()
{
ImGuiHelpers.ScaledDummy(4f);
using (ImRaii.PushId("group-Nearby"))
{
var icon = _nearbyOpen ? FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight;
_uiSharedService.IconText(icon);
if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) _nearbyOpen = !_nearbyOpen;
ImGui.SameLine();
var onUmbra = _nearbyEntries?.Count(e => e.IsMatch && e.AcceptPairRequests && !string.IsNullOrEmpty(e.Token) && !IsAlreadyPairedQuickMenu(e)) ?? 0;
ImGui.TextUnformatted($"Nearby ({onUmbra})");
if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) _nearbyOpen = !_nearbyOpen;
if (_nearbyOpen)
UiSharedService.DrawCard("nearby-card", () =>
{
ImGui.Indent();
bool nearbyState = _nearbyOpen;
UiSharedService.DrawArrowToggle(ref nearbyState, "##nearby-toggle");
if (nearbyState != _nearbyOpen)
{
_nearbyOpen = nearbyState;
}
ImGui.SameLine(0f, 6f * ImGuiHelpers.GlobalScale);
var onUmbra = _nearbyEntries?.Count(e => e.IsMatch && e.AcceptPairRequests && !string.IsNullOrEmpty(e.Token) && !IsAlreadyPairedQuickMenu(e)) ?? 0;
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted($"Nearby ({onUmbra})");
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
{
_nearbyOpen = !_nearbyOpen;
}
if (!_nearbyOpen)
{
return;
}
ImGuiHelpers.ScaledDummy(4f);
var indent = 18f * ImGuiHelpers.GlobalScale;
ImGui.Indent(indent);
var nearby = _nearbyEntries == null
? new List<Services.Mediator.NearbyEntry>()
: _nearbyEntries.Where(e => e.IsMatch && e.AcceptPairRequests && !string.IsNullOrEmpty(e.Token) && !IsAlreadyPairedQuickMenu(e))
@@ -779,13 +815,295 @@ public class CompactUi : WindowMediatorSubscriberBase
}
}
}
ImGui.Unindent();
ImGui.Separator();
ImGui.Unindent(indent);
}, stretchWidth: true);
}
ImGuiHelpers.ScaledDummy(4f);
}
private void DrawSidebar()
{
bool isConnected = _apiController.ServerState is ServerState.Connected;
ImGuiHelpers.ScaledDummy(6f);
DrawConnectionIcon();
ImGuiHelpers.ScaledDummy(12f);
DrawSidebarButton(FontAwesomeIcon.Eye, "Visible pairs", CompactUiSection.VisiblePairs, isConnected);
ImGuiHelpers.ScaledDummy(3f);
DrawSidebarButton(FontAwesomeIcon.User, "Individual pairs", CompactUiSection.IndividualPairs, isConnected);
ImGuiHelpers.ScaledDummy(3f);
DrawSidebarButton(FontAwesomeIcon.UserFriends, "Syncshells", CompactUiSection.Syncshells, isConnected);
ImGuiHelpers.ScaledDummy(3f);
int pendingInvites = _nearbyPending?.Pending.Count ?? 0;
bool highlightAutoDetect = pendingInvites > 0;
string autoDetectTooltip = highlightAutoDetect
? $"AutoDetect — {pendingInvites} invitation(s) en attente"
: "AutoDetect";
DrawSidebarButton(FontAwesomeIcon.BroadcastTower, autoDetectTooltip, CompactUiSection.AutoDetect, isConnected, highlightAutoDetect, pendingInvites);
ImGuiHelpers.ScaledDummy(3f);
DrawSidebarButton(FontAwesomeIcon.PersonCircleQuestion, "Character Analysis", CompactUiSection.CharacterAnalysis, isConnected, _dataAnalysisUi.IsOpen, 0, () =>
{
Mediator.Publish(new UiToggleMessage(typeof(DataAnalysisUi)));
});
ImGuiHelpers.ScaledDummy(3f);
DrawSidebarButton(FontAwesomeIcon.Running, "Character Data Hub", CompactUiSection.CharacterDataHub, isConnected, false, 0, () =>
{
Mediator.Publish(new UiToggleMessage(typeof(CharaDataHubUi)));
});
ImGuiHelpers.ScaledDummy(12f);
DrawSidebarButton(FontAwesomeIcon.UserCircle, "Edit Profile", CompactUiSection.EditProfile, isConnected);
ImGuiHelpers.ScaledDummy(3f);
DrawSidebarButton(FontAwesomeIcon.Cog, "Settings", CompactUiSection.Settings, true, _settingsUi.IsOpen, 0, () =>
{
Mediator.Publish(new UiToggleMessage(typeof(SettingsUi)));
});
}
private void DrawSidebarButton(FontAwesomeIcon icon, string tooltip, CompactUiSection section, bool enabled = true, bool highlight = false, int badgeCount = 0, Action? onClick = null)
{
using var id = ImRaii.PushId((int)section);
float regionWidth = ImGui.GetContentRegionAvail().X;
float buttonWidth = SidebarIconSize * ImGuiHelpers.GlobalScale;
float offset = System.Math.Max(0f, (regionWidth - buttonWidth) / 2f);
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + offset);
bool isActive = _activeSection == section;
if (DrawSidebarSquareButton(icon, isActive, highlight, enabled, badgeCount))
{
if (onClick != null)
{
onClick.Invoke();
}
else
{
_activeSection = section;
}
}
ImGui.EndChild();
UiSharedService.AttachToolTip(tooltip);
}
private void DrawConnectionIcon()
{
var state = _apiController.ServerState;
bool hasServer = _serverManager.CurrentServer != null;
bool isLinked = hasServer && !_serverManager.CurrentServer!.FullPause;
var icon = isLinked ? FontAwesomeIcon.Unlink : FontAwesomeIcon.Link;
using var id = ImRaii.PushId("connection-icon");
float regionWidth = ImGui.GetContentRegionAvail().X;
float buttonWidth = SidebarIconSize * ImGuiHelpers.GlobalScale;
float offset = System.Math.Max(0f, (regionWidth - buttonWidth) / 2f);
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + offset);
bool isTogglingDisabled = !hasServer || state is ServerState.Reconnecting or ServerState.Disconnecting;
if (DrawSidebarSquareButton(icon, isLinked, false, !isTogglingDisabled, 0) && !isTogglingDisabled)
{
ToggleConnection();
}
if (hasServer)
{
var tooltip = isLinked
? $"Disconnect from {_serverManager.CurrentServer!.ServerName}"
: $"Connect to {_serverManager.CurrentServer!.ServerName}";
UiSharedService.AttachToolTip(tooltip);
}
else
{
UiSharedService.AttachToolTip("No server configured");
}
}
private bool DrawSidebarSquareButton(FontAwesomeIcon icon, bool isActive, bool highlight, bool enabled, int badgeCount)
{
float size = SidebarIconSize * ImGuiHelpers.GlobalScale;
bool useAccent = (isActive || highlight) && enabled;
var buttonColor = useAccent ? UiSharedService.AccentColor : SidebarButtonColor;
var hoverColor = useAccent ? UiSharedService.AccentHoverColor : SidebarButtonHoverColor;
var activeColor = useAccent ? UiSharedService.AccentActiveColor : SidebarButtonActiveColor;
string iconText = icon.ToIconString();
Vector2 iconSize;
using (_uiSharedService.IconFont.Push())
{
iconSize = ImGui.CalcTextSize(iconText);
}
var start = ImGui.GetCursorScreenPos();
bool clicked;
using var disabled = ImRaii.Disabled(!enabled);
using var buttonColorPush = ImRaii.PushColor(ImGuiCol.Button, buttonColor);
using var hoverColorPush = ImRaii.PushColor(ImGuiCol.ButtonHovered, hoverColor);
using var activeColorPush = ImRaii.PushColor(ImGuiCol.ButtonActive, activeColor);
clicked = ImGui.Button("##sidebar-icon", new Vector2(size, size));
using (_uiSharedService.IconFont.Push())
{
var textPos = new Vector2(
start.X + (size - iconSize.X) / 2f,
start.Y + (size - iconSize.Y) / 2f);
uint iconColor = ImGui.ColorConvertFloat4ToU32(new Vector4(0.85f, 0.85f, 0.9f, 1f));
if (highlight)
iconColor = ImGui.ColorConvertFloat4ToU32(new Vector4(0.45f, 0.85f, 0.45f, 1f));
else if (isActive)
iconColor = ImGui.GetColorU32(ImGuiCol.Text);
ImGui.GetWindowDrawList().AddText(textPos, iconColor, iconText);
}
if (badgeCount > 0)
{
var min = ImGui.GetItemRectMin();
var max = ImGui.GetItemRectMax();
float radius = 6f * ImGuiHelpers.GlobalScale;
var center = new Vector2(max.X - radius * 0.8f, min.Y + radius * 0.8f);
var drawList = ImGui.GetWindowDrawList();
drawList.AddCircleFilled(center, radius, ImGui.ColorConvertFloat4ToU32(UiSharedService.AccentColor));
string badgeText = badgeCount > 9 ? "9+" : badgeCount.ToString();
var textSize = ImGui.CalcTextSize(badgeText);
drawList.AddText(center - textSize / 2f, ImGui.GetColorU32(ImGuiCol.Text), badgeText);
}
return clicked && enabled;
}
private void ToggleConnection()
{
if (_serverManager.CurrentServer == null) return;
_serverManager.CurrentServer.FullPause = !_serverManager.CurrentServer.FullPause;
_serverManager.Save();
_ = _apiController.CreateConnections();
}
private void DrawUnsupportedVersionBanner()
{
var ver = _apiController.CurrentClientVersion;
var unsupported = "UNSUPPORTED VERSION";
using (_uiSharedService.UidFont.Push())
{
var uidTextSize = ImGui.CalcTextSize(unsupported);
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMax().X + ImGui.GetWindowContentRegionMin().X) / 2 - uidTextSize.X / 2);
ImGui.AlignTextToFramePadding();
ImGui.TextColored(UiSharedService.AccentColor, unsupported);
}
UiSharedService.ColorTextWrapped(
$"Your UmbraSync installation is out of date, the current version is {ver.Major}.{ver.Minor}.{ver.Build}. " +
"It is highly recommended to keep UmbraSync up to date. Open /xlplugins and update the plugin.",
UiSharedService.AccentColor);
}
private void DrawMainContent()
{
if (_activeSection is CompactUiSection.EditProfile)
{
_editProfileUi.DrawInline();
DrawNewUserNoteModal();
return;
}
bool requiresConnection = RequiresServerConnection(_activeSection);
if (requiresConnection && _apiController.ServerState is not ServerState.Connected)
{
UiSharedService.ColorTextWrapped("Connectez-vous au serveur pour accéder à cette section.", ImGuiColors.DalamudGrey3);
DrawNewUserNoteModal();
return;
}
switch (_activeSection)
{
case CompactUiSection.VisiblePairs:
DrawPairSection(PairContentMode.VisibleOnly);
break;
case CompactUiSection.IndividualPairs:
DrawPairSection(PairContentMode.All);
break;
case CompactUiSection.Syncshells:
DrawSyncshellSection();
break;
case CompactUiSection.AutoDetect:
DrawAutoDetectSection();
break;
}
DrawNewUserNoteModal();
}
private void DrawPairSection(PairContentMode mode)
{
DrawDefaultSyncSettings();
using (ImRaii.PushId("pairlist")) DrawPairList(mode);
ImGui.Separator();
using (ImRaii.PushId("transfers")) DrawTransfers();
TransferPartHeight = ImGui.GetCursorPosY() - TransferPartHeight;
using (ImRaii.PushId("group-user-popup")) _selectPairsForGroupUi.Draw(_pairManager.DirectPairs);
using (ImRaii.PushId("grouping-popup")) _selectGroupForPairUi.Draw();
}
private void DrawSyncshellSection()
{
using (ImRaii.PushId("syncshells")) _groupPanel.DrawSyncshells();
ImGui.Separator();
using (ImRaii.PushId("transfers")) DrawTransfers();
TransferPartHeight = ImGui.GetCursorPosY() - TransferPartHeight;
using (ImRaii.PushId("group-user-popup")) _selectPairsForGroupUi.Draw(_pairManager.DirectPairs);
using (ImRaii.PushId("grouping-popup")) _selectGroupForPairUi.Draw();
}
private void DrawAutoDetectSection()
{
using (ImRaii.PushId("autodetect-inline")) _autoDetectUi.DrawInline();
}
private void DrawNewUserNoteModal()
{
if (_configService.Current.OpenPopupOnAdd && _pairManager.LastAddedUser != null)
{
_lastAddedUser = _pairManager.LastAddedUser;
_pairManager.LastAddedUser = null;
ImGui.OpenPopup("Set Notes for New User");
_showModalForUserAddition = true;
_lastAddedUserComment = string.Empty;
}
if (ImGui.BeginPopupModal("Set Notes for New User", ref _showModalForUserAddition, UiSharedService.PopupWindowFlags))
{
if (_lastAddedUser == null)
{
_showModalForUserAddition = false;
}
else
{
UiSharedService.TextWrapped($"You have successfully added {_lastAddedUser.UserData.AliasOrUID}. Set a local note for the user in the field below:");
ImGui.InputTextWithHint("##noteforuser", $"Note for {_lastAddedUser.UserData.AliasOrUID}", ref _lastAddedUserComment, 100);
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, "Save Note"))
{
_serverManager.SetNoteForUid(_lastAddedUser.UserData.UID, _lastAddedUserComment);
_lastAddedUser = null;
_lastAddedUserComment = string.Empty;
_showModalForUserAddition = false;
}
}
UiSharedService.SetScaledWindowSize(275);
ImGui.EndPopup();
}
}
private static bool RequiresServerConnection(CompactUiSection section)
{
return section is CompactUiSection.VisiblePairs
or CompactUiSection.IndividualPairs
or CompactUiSection.Syncshells
or CompactUiSection.AutoDetect;
}
private bool IsAlreadyPairedQuickMenu(Services.Mediator.NearbyEntry entry)
@@ -811,7 +1129,6 @@ public class CompactUi : WindowMediatorSubscriberBase
private void DrawServerStatus()
{
var buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Link);
var userCount = _apiController.OnlineUsers.ToString(CultureInfo.InvariantCulture);
var userSize = ImGui.CalcTextSize(userCount);
var textSize = ImGui.CalcTextSize("Users Online");
@@ -841,43 +1158,6 @@ public class CompactUi : WindowMediatorSubscriberBase
ImGui.TextUnformatted(shardConnection);
}
ImGui.SameLine();
if (printShard)
{
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ((userSize.Y + textSize.Y) / 2 + shardTextSize.Y) / 2 - ImGui.GetStyle().ItemSpacing.Y + buttonSize.Y / 2);
}
var isLinked = !_serverManager.CurrentServer!.FullPause;
var color = isLinked ? new Vector4(0.63f, 0.25f, 1f, 1f) : UiSharedService.GetBoolColor(isLinked);
var connectedIcon = isLinked ? FontAwesomeIcon.Link : FontAwesomeIcon.Unlink;
if (_apiController.ServerState is ServerState.Connected)
{
ImGui.SetCursorPosX(0 + ImGui.GetStyle().ItemSpacing.X);
if (_uiSharedService.IconButton(FontAwesomeIcon.UserCircle))
{
Mediator.Publish(new UiToggleMessage(typeof(EditProfileUi)));
}
UiSharedService.AttachToolTip("Edit your Profile");
}
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X);
if (printShard)
{
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ((userSize.Y + textSize.Y) / 2 + shardTextSize.Y) / 2 - ImGui.GetStyle().ItemSpacing.Y + buttonSize.Y / 2);
}
if (_apiController.ServerState is not (ServerState.Reconnecting or ServerState.Disconnecting))
{
ImGui.PushStyleColor(ImGuiCol.Text, color);
if (_uiSharedService.IconButton(connectedIcon))
{
_serverManager.CurrentServer.FullPause = !_serverManager.CurrentServer.FullPause;
_serverManager.Save();
_ = _apiController.CreateConnections();
}
ImGui.PopStyleColor();
UiSharedService.AttachToolTip(!_serverManager.CurrentServer.FullPause ? "Disconnect from " + _serverManager.CurrentServer.ServerName : "Connect to " + _serverManager.CurrentServer.ServerName);
}
}
private void DrawTransfers()
@@ -923,25 +1203,12 @@ public class CompactUi : WindowMediatorSubscriberBase
ImGui.SameLine(WindowContentWidth - textSize.X);
ImGui.TextUnformatted(downloadText);
}
var spacing = ImGui.GetStyle().ItemSpacing.X;
var bottomButtonWidth = (WindowContentWidth - spacing) / 2f;
if (_uiSharedService.IconTextButton(FontAwesomeIcon.PersonCircleQuestion, "Character Analysis", bottomButtonWidth))
{
Mediator.Publish(new UiToggleMessage(typeof(DataAnalysisUi)));
}
ImGui.SameLine();
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Running, "Character Data Hub", bottomButtonWidth))
{
Mediator.Publish(new UiToggleMessage(typeof(CharaDataHubUi)));
}
ImGuiHelpers.ScaledDummy(2);
}
private void DrawUIDHeader()
{
var uidText = GetUidText();
var buttonSizeX = 0f;
Vector2 uidTextSize;
using (_uiSharedService.UidFont.Push())
@@ -951,23 +1218,14 @@ public class CompactUi : WindowMediatorSubscriberBase
var originalPos = ImGui.GetCursorPos();
ImGui.SetWindowFontScale(1.5f);
var buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Cog);
buttonSizeX -= buttonSize.X - ImGui.GetStyle().ItemSpacing.X * 2;
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X);
ImGui.SetCursorPosY(originalPos.Y + uidTextSize.Y / 2 - buttonSize.Y / 2);
if (_uiSharedService.IconButton(FontAwesomeIcon.Cog))
{
Mediator.Publish(new OpenSettingsUiMessage());
}
UiSharedService.AttachToolTip("Open the UmbraSync Settings");
ImGui.SameLine();
ImGui.SetCursorPos(originalPos);
Vector2 buttonSize = Vector2.Zero;
float spacingX = ImGui.GetStyle().ItemSpacing.X;
if (_apiController.ServerState is ServerState.Connected)
{
buttonSizeX += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Copy).X - ImGui.GetStyle().ItemSpacing.X * 2;
ImGui.SetCursorPosY(originalPos.Y + uidTextSize.Y / 2 - buttonSize.Y / 2);
buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Copy);
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X);
ImGui.SetCursorPosY(originalPos.Y + uidTextSize.Y / 2f - buttonSize.Y / 2f);
if (_uiSharedService.IconButton(FontAwesomeIcon.Copy))
{
ImGui.SetClipboardText(_apiController.DisplayName);
@@ -975,10 +1233,18 @@ public class CompactUi : WindowMediatorSubscriberBase
UiSharedService.AttachToolTip("Copy your UID to clipboard");
ImGui.SameLine();
}
ImGui.SetCursorPos(originalPos);
ImGui.SetWindowFontScale(1f);
ImGui.SetCursorPosY(originalPos.Y + buttonSize.Y / 2 - uidTextSize.Y / 2 - ImGui.GetStyle().ItemSpacing.Y / 2);
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMax().X + ImGui.GetWindowContentRegionMin().X) / 2 + buttonSizeX - uidTextSize.X / 2);
float referenceHeight = buttonSize.Y > 0f ? buttonSize.Y : ImGui.GetFrameHeight();
ImGui.SetCursorPosY(originalPos.Y + referenceHeight / 2f - uidTextSize.Y / 2f - spacingX / 2f);
float contentMin = ImGui.GetWindowContentRegionMin().X;
float contentMax = ImGui.GetWindowContentRegionMax().X;
float availableWidth = contentMax - contentMin;
float center = contentMin + availableWidth / 2f;
ImGui.SetCursorPosX(center - uidTextSize.X / 2f);
using (_uiSharedService.UidFont.Push())
ImGui.TextColored(GetUidColor(), uidText);

View File

@@ -45,6 +45,43 @@ public class DrawGroupPair : DrawPairBase
_serverConfigurationManager = serverConfigurationManager;
}
protected override float GetRightSideExtraWidth()
{
float width = 0f;
float spacing = ImGui.GetStyle().ItemSpacing.X;
var soundsDisabled = _fullInfoDto.GroupUserPermissions.IsDisableSounds();
var animDisabled = _fullInfoDto.GroupUserPermissions.IsDisableAnimations();
var vfxDisabled = _fullInfoDto.GroupUserPermissions.IsDisableVFX();
var individualSoundsDisabled = (_pair.UserPair?.OwnPermissions.IsDisableSounds() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableSounds() ?? false);
var individualAnimDisabled = (_pair.UserPair?.OwnPermissions.IsDisableAnimations() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableAnimations() ?? false);
var individualVFXDisabled = (_pair.UserPair?.OwnPermissions.IsDisableVFX() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableVFX() ?? false);
bool showInfo = individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled || animDisabled || soundsDisabled || vfxDisabled;
bool showShared = _charaDataManager.SharedWithYouData.TryGetValue(_pair.UserData, out var sharedData);
bool showPlus = _pair.UserPair == null && _pair.IsOnline;
if (showShared)
{
width += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X + spacing;
}
if (showInfo)
{
var icon = (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled)
? FontAwesomeIcon.ExclamationTriangle
: FontAwesomeIcon.InfoCircle;
width += UiSharedService.GetIconSize(icon).X + spacing;
}
if (showPlus)
{
width += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X + spacing;
}
return width;
}
protected override void DrawLeftSide(float textPosY, float originalY)
{
var entryUID = _pair.UserData.AliasOrUID;

View File

@@ -1,5 +1,8 @@
using Dalamud.Bindings.ImGui;
using System;
using System.Numerics;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using MareSynchronos.PlayerData.Pairs;
using MareSynchronos.UI.Handlers;
using MareSynchronos.WebAPI;
@@ -28,36 +31,75 @@ public abstract class DrawPairBase
public void DrawPairedClient()
{
var originalY = ImGui.GetCursorPosY();
var pauseIconSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Play);
var textSize = ImGui.CalcTextSize(_pair.UserData.AliasOrUID);
var style = ImGui.GetStyle();
var padding = style.FramePadding;
var spacing = style.ItemSpacing;
var rowStartCursor = ImGui.GetCursorPos();
var rowStartScreen = ImGui.GetCursorScreenPos();
var startPos = ImGui.GetCursorStartPos();
var pauseButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Pause);
var playButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Play);
var menuButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars);
var framePadding = ImGui.GetStyle().FramePadding;
var lineHeight = textSize.Y + framePadding.Y * 2;
float pauseClusterWidth = Math.Max(pauseButtonSize.X, playButtonSize.X);
float pauseClusterHeight = Math.Max(pauseButtonSize.Y, playButtonSize.Y);
float reservedSpacing = style.ItemSpacing.X * 2.4f;
float rightButtonWidth =
menuButtonSize.X +
pauseClusterWidth +
reservedSpacing +
GetRightSideExtraWidth();
var off = startPos.Y;
var height = UiSharedService.GetWindowContentRegionHeight();
float availableWidth = Math.Max(ImGui.GetContentRegionAvail().X - rightButtonWidth, 1f);
float textHeight = ImGui.GetFontSize();
var presenceIconSize = UiSharedService.GetIconSize(FontAwesomeIcon.Moon);
float iconHeight = presenceIconSize.Y;
float contentHeight = Math.Max(textHeight, Math.Max(iconHeight, pauseClusterHeight));
float rowHeight = contentHeight + padding.Y * 2f;
float totalHeight = rowHeight + spacing.Y;
if ((originalY + off) < -lineHeight || (originalY + off) > height)
var origin = ImGui.GetCursorStartPos();
var top = origin.Y + rowStartCursor.Y;
var bottom = top + totalHeight;
var visibleHeight = UiSharedService.GetWindowContentRegionHeight();
if (bottom < 0 || top > visibleHeight)
{
ImGui.Dummy(new System.Numerics.Vector2(0f, lineHeight));
ImGui.SetCursorPos(new Vector2(rowStartCursor.X, rowStartCursor.Y + totalHeight));
return;
}
var textPosY = originalY + pauseIconSize.Y / 2 - textSize.Y / 2;
DrawLeftSide(textPosY, originalY);
var drawList = ImGui.GetWindowDrawList();
var backgroundColor = new Vector4(0.10f, 0.10f, 0.14f, 0.95f);
var borderColor = new Vector4(0f, 0f, 0f, 0.9f);
float rounding = Math.Max(style.FrameRounding, 7f * ImGuiHelpers.GlobalScale);
var panelMin = rowStartScreen + new Vector2(0f, spacing.Y * 0.15f);
var panelMax = panelMin + new Vector2(availableWidth, rowHeight - spacing.Y * 0.3f);
drawList.AddRectFilled(panelMin, panelMax, ImGui.ColorConvertFloat4ToU32(backgroundColor), rounding);
drawList.AddRect(panelMin, panelMax, ImGui.ColorConvertFloat4ToU32(borderColor), rounding);
float iconTop = rowStartCursor.Y + (rowHeight - iconHeight) / 2f;
float textTop = rowStartCursor.Y + (rowHeight - textHeight) / 2f - padding.Y * 0.6f;
float buttonTop = rowStartCursor.Y + (rowHeight - pauseClusterHeight) / 2f;
ImGui.SetCursorPos(new Vector2(rowStartCursor.X + padding.X, iconTop));
DrawLeftSide(iconTop, iconTop);
ImGui.SameLine();
ImGui.SetCursorPosY(textTop);
var posX = ImGui.GetCursorPosX();
var rightSide = DrawRightSide(textPosY, originalY);
DrawName(originalY, posX, rightSide);
var rightSide = DrawRightSide(buttonTop, buttonTop);
DrawName(textTop + padding.Y * 0.15f, posX, rightSide);
ImGui.SetCursorPos(new Vector2(rowStartCursor.X, rowStartCursor.Y + totalHeight));
ImGui.SetCursorPosX(rowStartCursor.X);
}
protected abstract void DrawLeftSide(float textPosY, float originalY);
protected abstract float DrawRightSide(float textPosY, float originalY);
protected virtual float GetRightSideExtraWidth() => 0f;
private void DrawName(float originalY, float leftSide, float rightSide)
{
_displayHandler.DrawPairText(_id, _pair, leftSide, originalY, () => rightSide - leftSide);

View File

@@ -41,6 +41,28 @@ public class DrawUserPair : DrawPairBase
public bool IsVisible => _pair.IsVisible;
public UserPairDto UserPair => _pair.UserPair!;
protected override float GetRightSideExtraWidth()
{
float width = 0f;
var spacingX = ImGui.GetStyle().ItemSpacing.X;
var individualSoundsDisabled = (_pair.UserPair?.OwnPermissions.IsDisableSounds() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableSounds() ?? false);
var individualAnimDisabled = (_pair.UserPair?.OwnPermissions.IsDisableAnimations() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableAnimations() ?? false);
var individualVFXDisabled = (_pair.UserPair?.OwnPermissions.IsDisableVFX() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableVFX() ?? false);
if (individualSoundsDisabled || individualAnimDisabled || individualVFXDisabled)
{
width += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.ExclamationTriangle).X + spacingX * 0.5f;
}
if (_charaDataManager.SharedWithYouData.TryGetValue(_pair.UserData, out var sharedData))
{
width += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X + spacingX * 0.5f;
}
return width;
}
protected override void DrawLeftSide(float textPosY, float originalY)
{
var online = _pair.IsOnline;
@@ -110,7 +132,8 @@ public class DrawUserPair : DrawPairBase
var barButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars);
var entryUID = _pair.UserData.AliasOrUID;
var spacingX = ImGui.GetStyle().ItemSpacing.X;
var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth();
var edgePadding = ImGui.GetStyle().WindowPadding.X + 4f * ImGuiHelpers.GlobalScale;
var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - edgePadding;
var rightSidePos = windowEndX - barButtonSize.X;
// Flyout Menu

View File

@@ -313,19 +313,20 @@ internal sealed class GroupPanel
int shellNumber = _serverConfigurationManager.GetShellNumberForGid(groupDto.GID);
var name = groupDto.Group.Alias ?? groupDto.GID;
if (!_expandedGroupState.TryGetValue(groupDto.GID, out bool isExpanded))
if (!_expandedGroupState.ContainsKey(groupDto.GID))
{
isExpanded = false;
_expandedGroupState.Add(groupDto.GID, isExpanded);
_expandedGroupState[groupDto.GID] = false;
}
var icon = isExpanded ? FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight;
_uiShared.IconText(icon);
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
UiSharedService.DrawCard($"syncshell-card-{groupDto.GID}", () =>
{
_expandedGroupState[groupDto.GID] = !_expandedGroupState[groupDto.GID];
bool expandedState = _expandedGroupState[groupDto.GID];
UiSharedService.DrawArrowToggle(ref expandedState, $"##syncshell-toggle-{groupDto.GID}");
if (expandedState != _expandedGroupState[groupDto.GID])
{
_expandedGroupState[groupDto.GID] = expandedState;
}
ImGui.SameLine();
ImGui.SameLine(0f, 6f * ImGuiHelpers.GlobalScale);
var textIsGid = true;
string groupName = groupDto.GroupAliasOrGID;
@@ -547,7 +548,7 @@ internal sealed class GroupPanel
bool hideOfflineUsers = pairsInGroup.Count > 1000;
ImGui.Indent(20);
if (_expandedGroupState[groupDto.GID])
if (expandedState)
{
var sortedPairs = pairsInGroup
.OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal))
@@ -614,6 +615,9 @@ internal sealed class GroupPanel
ImGui.Separator();
}
ImGui.Unindent(20);
}, background: new Vector4(0.15f, 0.15f, 0.20f, 0.94f), border: new Vector4(0f, 0f, 0f, 0.78f), stretchWidth: true);
ImGuiHelpers.ScaledDummy(4f);
}
private void DrawSyncShellButtons(GroupFullInfoDto groupDto, List<Pair> groupPairs)
@@ -828,9 +832,22 @@ internal sealed class GroupPanel
private void DrawSyncshellList()
{
var ySize = _mainUi.TransferPartHeight == 0
? 1
: (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y) - _mainUi.TransferPartHeight - ImGui.GetCursorPosY();
float availableHeight = ImGui.GetContentRegionAvail().Y;
float ySize;
if (_mainUi.TransferPartHeight <= 0)
{
float reserve = ImGui.GetFrameHeightWithSpacing() * 2f;
ySize = availableHeight - reserve;
if (ySize <= 0)
{
ySize = System.Math.Max(availableHeight, 1f);
}
}
else
{
ySize = (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y) - _mainUi.TransferPartHeight - ImGui.GetCursorPosY();
}
ImGui.BeginChild("list", new Vector2(_mainUi.WindowContentWidth, ySize), border: false);
foreach (var entry in _pairManager.GroupPairs.OrderBy(g => g.Key.Group.AliasOrGID, StringComparer.OrdinalIgnoreCase).ToList())
{

View File

@@ -1,10 +1,14 @@
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using MareSynchronos.API.Data.Extensions;
using MareSynchronos.MareConfiguration;
using MareSynchronos.UI.Handlers;
using MareSynchronos.WebAPI;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MareSynchronos.UI.Components;
@@ -28,7 +32,7 @@ public class PairGroupsUi
_uiSharedService = uiSharedService;
}
public void Draw<T>(List<T> visibleUsers, List<T> onlineUsers, List<T> offlineUsers) where T : DrawPairBase
public void Draw<T>(List<T> visibleUsers, List<T> onlineUsers, List<T> offlineUsers, Action? drawVisibleExtras = null) where T : DrawPairBase
{
// Only render those tags that actually have pairs in them, otherwise
// we can end up with a bunch of useless pair groups
@@ -36,7 +40,7 @@ public class PairGroupsUi
var allUsers = onlineUsers.Concat(offlineUsers).ToList();
if (typeof(T) == typeof(DrawUserPair))
{
DrawUserPairs(tagsWithPairsInThem, allUsers.Cast<DrawUserPair>().ToList(), visibleUsers.Cast<DrawUserPair>(), onlineUsers.Cast<DrawUserPair>(), offlineUsers.Cast<DrawUserPair>());
DrawUserPairs(tagsWithPairsInThem, allUsers.Cast<DrawUserPair>().ToList(), visibleUsers.Cast<DrawUserPair>(), onlineUsers.Cast<DrawUserPair>(), offlineUsers.Cast<DrawUserPair>(), drawVisibleExtras);
}
}
@@ -44,14 +48,15 @@ public class PairGroupsUi
{
var allArePaused = availablePairsInThisTag.All(pair => pair.UserPair!.OwnPermissions.IsPaused());
var pauseButton = allArePaused ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
var flyoutMenuX = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars).X;
var pauseButtonX = _uiSharedService.GetIconButtonSize(pauseButton).X;
var windowX = ImGui.GetWindowContentRegionMin().X;
var windowWidth = UiSharedService.GetWindowContentRegionWidth();
var flyoutMenuSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars);
var pauseButtonSize = _uiSharedService.GetIconButtonSize(pauseButton);
var spacingX = ImGui.GetStyle().ItemSpacing.X;
var currentX = ImGui.GetCursorPosX();
var availableWidth = ImGui.GetContentRegionAvail().X;
var buttonsWidth = pauseButtonSize.X + flyoutMenuSize.X + spacingX;
var pauseStart = Math.Max(currentX, currentX + availableWidth - buttonsWidth);
var buttonPauseOffset = windowX + windowWidth - flyoutMenuX - spacingX - pauseButtonX;
ImGui.SameLine(buttonPauseOffset);
ImGui.SameLine(pauseStart);
if (_uiSharedService.IconButton(pauseButton))
{
if (allArePaused)
@@ -72,8 +77,8 @@ public class PairGroupsUi
UiSharedService.AttachToolTip($"Pause pairing with all pairs in {tag}");
}
var buttonDeleteOffset = windowX + windowWidth - flyoutMenuX;
ImGui.SameLine(buttonDeleteOffset);
var menuStart = Math.Max(pauseStart + pauseButtonSize.X + spacingX, currentX);
ImGui.SameLine(menuStart);
if (_uiSharedService.IconButton(FontAwesomeIcon.Bars))
{
ImGui.OpenPopup("Group Flyout Menu");
@@ -86,7 +91,7 @@ public class PairGroupsUi
}
}
private void DrawCategory(string tag, IEnumerable<DrawPairBase> onlineUsers, IEnumerable<DrawPairBase> allUsers, IEnumerable<DrawPairBase>? visibleUsers = null)
private void DrawCategory(string tag, IEnumerable<DrawPairBase> onlineUsers, IEnumerable<DrawPairBase> allUsers, IEnumerable<DrawPairBase>? visibleUsers = null, Action? drawExtraContent = null)
{
IEnumerable<DrawPairBase> usersInThisTag;
HashSet<string>? otherUidsTaggedWithTag = null;
@@ -108,26 +113,25 @@ public class PairGroupsUi
if (isSpecialTag && !usersInThisTag.Any()) return;
UiSharedService.DrawCard($"pair-group-{tag}", () =>
{
DrawName(tag, isSpecialTag, visibleInThisTag, usersInThisTag.Count(), otherUidsTaggedWithTag?.Count);
if (!isSpecialTag)
{
using (ImRaii.PushId($"group-{tag}-buttons")) DrawButtons(tag, allUsers.Cast<DrawUserPair>().Where(p => otherUidsTaggedWithTag!.Contains(p.UID)).ToList());
}
else
{
if (!_tagHandler.IsTagOpen(tag))
{
var size = ImGui.CalcTextSize("").Y + ImGui.GetStyle().FramePadding.Y * 2f;
ImGui.SameLine();
ImGui.Dummy(new(size, size));
}
}
if (!_tagHandler.IsTagOpen(tag)) return;
ImGui.Indent(20);
ImGuiHelpers.ScaledDummy(4f);
var indent = 18f * ImGuiHelpers.GlobalScale;
ImGui.Indent(indent);
DrawPairs(tag, usersInThisTag);
ImGui.Unindent(20);
drawExtraContent?.Invoke();
ImGui.Unindent(indent);
}, stretchWidth: true);
ImGuiHelpers.ScaledDummy(4f);
}
private void DrawGroupMenu(string tag)
@@ -157,17 +161,21 @@ public class PairGroupsUi
};
string resultFolderName = !isSpecialTag ? $"{displayedName} ({visible}/{online}/{total} Pairs)" : $"{displayedName} ({online} Pairs)";
var icon = _tagHandler.IsTagOpen(tag) ? FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight;
_uiSharedService.IconText(icon);
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
bool isOpen = _tagHandler.IsTagOpen(tag);
bool previousState = isOpen;
UiSharedService.DrawArrowToggle(ref isOpen, $"##group-toggle-{tag}");
if (isOpen != previousState)
{
ToggleTagOpen(tag);
_tagHandler.SetTagOpen(tag, isOpen);
}
ImGui.SameLine();
ImGui.SameLine(0f, 6f * ImGuiHelpers.GlobalScale);
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(resultFolderName);
if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
{
ToggleTagOpen(tag);
bool newState = !_tagHandler.IsTagOpen(tag);
_tagHandler.SetTagOpen(tag, newState);
isOpen = newState;
}
if (!isSpecialTag && ImGui.IsItemHovered())
@@ -186,14 +194,13 @@ public class PairGroupsUi
{
// These are all the OtherUIDs that are tagged with this tag
_uidDisplayHandler.RenderPairList(availablePairsInThisCategory);
ImGui.Separator();
}
private void DrawUserPairs(List<string> tagsWithPairsInThem, List<DrawUserPair> allUsers, IEnumerable<DrawUserPair> visibleUsers, IEnumerable<DrawUserPair> onlineUsers, IEnumerable<DrawUserPair> offlineUsers)
private void DrawUserPairs(List<string> tagsWithPairsInThem, List<DrawUserPair> allUsers, IEnumerable<DrawUserPair> visibleUsers, IEnumerable<DrawUserPair> onlineUsers, IEnumerable<DrawUserPair> offlineUsers, Action? drawVisibleExtras)
{
if (_mareConfig.Current.ShowVisibleUsersSeparately)
{
using (ImRaii.PushId("$group-VisibleCustomTag")) DrawCategory(TagHandler.CustomVisibleTag, visibleUsers, allUsers);
using (ImRaii.PushId("$group-VisibleCustomTag")) DrawCategory(TagHandler.CustomVisibleTag, visibleUsers, allUsers, drawExtraContent: drawVisibleExtras);
}
foreach (var tag in tagsWithPairsInThem)
{

View File

@@ -64,6 +64,16 @@ public class EditProfileUi : WindowMediatorSubscriberBase
}
protected override void DrawInternal()
{
DrawProfileContent();
}
public void DrawInline()
{
DrawProfileContent();
}
private void DrawProfileContent()
{
_uiSharedService.BigText("Current Profile (as saved on server)");
ImGuiHelpers.ScaledDummy(new Vector2(0f, ImGui.GetStyle().ItemSpacing.Y / 2));

View File

@@ -131,6 +131,11 @@ public class SettingsUi : WindowMediatorSubscriberBase
DrawSettingsContent();
}
public void DrawInline()
{
DrawSettingsContent();
}
public override void OnClose()
{
_uiShared.EditTrackerPosition = false;

View File

@@ -20,6 +20,7 @@ using MareSynchronos.Services.Mediator;
using MareSynchronos.Services.ServerConfiguration;
using MareSynchronos.WebAPI;
using Microsoft.Extensions.Logging;
using System;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
@@ -216,7 +217,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
public static bool CtrlPressed() => (GetKeyState(0xA2) & 0x8000) != 0 || (GetKeyState(0xA3) & 0x8000) != 0;
public static void DrawGrouped(Action imguiDrawAction, float rounding = 5f, float? expectedWidth = null)
public static void DrawGrouped(Action imguiDrawAction, float rounding = 5f, float? expectedWidth = null, bool drawBorder = true)
{
var cursorPos = ImGui.GetCursorPos();
using (ImRaii.Group())
@@ -230,11 +231,123 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
imguiDrawAction.Invoke();
}
if (drawBorder)
{
ImGui.GetWindowDrawList().AddRect(
ImGui.GetItemRectMin() - ImGui.GetStyle().ItemInnerSpacing,
ImGui.GetItemRectMax() + ImGui.GetStyle().ItemInnerSpacing,
Color(ImGuiColors.DalamudGrey2), rounding);
}
}
public static void DrawCard(string id, Action draw, Vector2? padding = null, Vector4? background = null,
Vector4? border = null, float? rounding = null, bool stretchWidth = false)
{
var style = ImGui.GetStyle();
var padBase = style.FramePadding;
var pad = padding ?? new Vector2(
padBase.X + 4f * ImGuiHelpers.GlobalScale,
padBase.Y + 3f * ImGuiHelpers.GlobalScale);
var cardBg = background ?? new Vector4(0.08f, 0.08f, 0.10f, 0.94f);
var cardBorder = border ?? new Vector4(0f, 0f, 0f, 0.85f);
float cardRounding = rounding ?? Math.Max(style.FrameRounding, 8f * ImGuiHelpers.GlobalScale);
float borderThickness = Math.Max(1f, Math.Max(style.FrameBorderSize, 1f) * ImGuiHelpers.GlobalScale);
float borderInset = borderThickness;
var originalCursor = ImGui.GetCursorPos();
if (stretchWidth)
{
ImGui.SetCursorPosX(ImGui.GetWindowContentRegionMin().X);
}
var startCursor = ImGui.GetCursorPos();
var drawList = ImGui.GetWindowDrawList();
drawList.ChannelsSplit(2);
drawList.ChannelsSetCurrent(1);
ImGui.PushID(id);
ImGui.SetCursorPos(new Vector2(startCursor.X + pad.X, startCursor.Y + pad.Y));
ImGui.BeginGroup();
draw();
ImGui.EndGroup();
ImGui.PopID();
var contentMin = ImGui.GetItemRectMin();
var contentMax = ImGui.GetItemRectMax();
var cardMin = contentMin - pad;
var cardMax = contentMax + pad;
var outerMin = cardMin;
var outerMax = cardMax;
if (stretchWidth)
{
var windowPos = ImGui.GetWindowPos();
var regionMin = ImGui.GetWindowContentRegionMin();
var regionMax = ImGui.GetWindowContentRegionMax();
var scrollX = ImGui.GetScrollX();
cardMin.X = windowPos.X + regionMin.X + scrollX;
cardMax.X = windowPos.X + regionMax.X + scrollX;
outerMin.X = cardMin.X;
outerMax.X = cardMax.X;
startCursor.X = ImGui.GetWindowContentRegionMin().X;
}
var drawMin = new Vector2(cardMin.X + borderInset, cardMin.Y + borderInset);
var drawMax = new Vector2(cardMax.X - borderInset, cardMax.Y - borderInset);
var clipMin = drawList.GetClipRectMin();
var clipMax = drawList.GetClipRectMax();
var clipInset = new Vector2(borderThickness * 0.5f + 0.5f, borderThickness * 0.5f + 0.5f);
drawMin = Vector2.Max(drawMin, clipMin + clipInset);
drawMax = Vector2.Min(drawMax, clipMax - clipInset);
if (drawMax.X <= drawMin.X)
{
drawMax.X = drawMin.X + borderThickness;
}
if (drawMax.Y <= drawMin.Y)
{
drawMax.Y = drawMin.Y + borderThickness;
}
drawList.ChannelsSetCurrent(0);
drawList.AddRectFilled(drawMin, drawMax, ImGui.ColorConvertFloat4ToU32(cardBg), cardRounding);
if (cardBorder.W > 0f && borderThickness > 0f)
{
drawList.AddRect(drawMin, drawMax, ImGui.ColorConvertFloat4ToU32(cardBorder), cardRounding, ImDrawFlags.None, borderThickness);
}
drawList.ChannelsMerge();
ImGui.SetCursorPos(startCursor);
var dummyWidth = outerMax.X - outerMin.X;
var dummyHeight = outerMax.Y - outerMin.Y;
ImGui.Dummy(new Vector2(dummyWidth, dummyHeight));
ImGui.SetCursorPos(new Vector2(startCursor.X, startCursor.Y + dummyHeight));
if (!stretchWidth)
{
ImGui.SetCursorPosX(originalCursor.X);
}
else
{
ImGui.SetCursorPosX(startCursor.X);
}
}
public static bool DrawArrowToggle(ref bool state, string id)
{
var framePadding = ImGui.GetStyle().FramePadding;
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(framePadding.X, framePadding.Y * 0.85f));
ImGui.PushStyleColor(ImGuiCol.Button, Vector4.Zero);
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(1f, 1f, 1f, 0.08f));
ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(1f, 1f, 1f, 0.16f));
bool clicked = ImGui.ArrowButton(id, state ? ImGuiDir.Down : ImGuiDir.Right);
ImGui.PopStyleColor(3);
ImGui.PopStyleVar();
if (clicked)
{
state = !state;
}
return state;
}
public static void DrawGroupedCenteredColorText(string text, Vector4 color, float? maxWidth = null)
{