diff --git a/MareSynchronos/Services/CharaData/CharaDataManager.cs b/MareSynchronos/Services/CharaData/CharaDataManager.cs index da623a9..96b1a45 100644 --- a/MareSynchronos/Services/CharaData/CharaDataManager.cs +++ b/MareSynchronos/Services/CharaData/CharaDataManager.cs @@ -608,6 +608,18 @@ public sealed partial class CharaDataManager : DisposableMediatorSubscriberBase return _metaInfoCache.TryGetValue(key, out metaInfo); } + public void UploadAllCharaData() + { + UiBlockingComputation = Task.Run(async () => + { + foreach (var updateDto in _updateDtos.Values.Where(u => u.HasChanges)) + { + CharaUpdateTask = CharaUpdateAsync(updateDto); + await CharaUpdateTask.ConfigureAwait(false); + } + }); + } + public void UploadCharaData(string id) { var hasUpdateDto = _updateDtos.TryGetValue(id, out var updateDto); @@ -903,7 +915,6 @@ public sealed partial class CharaDataManager : DisposableMediatorSubscriberBase var res = await _apiController.CharaDataUpdate(baseUpdateDto).ConfigureAwait(false); await AddOrUpdateDto(res).ConfigureAwait(false); - CharaUpdateTask = null; } private async Task DownloadAndAplyDataAsync(string charaName, CharaDataDownloadDto charaDataDownloadDto, CharaDataMetaInfoDto metaInfo, bool autoRevert = true) diff --git a/MareSynchronos/UI/CharaDataHubUi.GposeTogether.cs b/MareSynchronos/UI/CharaDataHubUi.GposeTogether.cs index dab9e52..6a2c1cd 100644 --- a/MareSynchronos/UI/CharaDataHubUi.GposeTogether.cs +++ b/MareSynchronos/UI/CharaDataHubUi.GposeTogether.cs @@ -45,7 +45,7 @@ internal sealed partial class CharaDataHubUi _charaDataGposeTogetherManager.CreateNewLobby(); } ImGuiHelpers.ScaledDummy(5); - ImGui.SetNextItemWidth(250); + UiSharedService.ScaledNextItemWidth(250); ImGui.InputTextWithHint("##lobbyId", "GPose Lobby Id", ref _joinLobbyId, 30); if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowRight, "Join GPose Together Lobby")) { @@ -187,7 +187,7 @@ internal sealed partial class CharaDataHubUi using (ImRaii.Disabled(!_uiSharedService.IsInGpose)) { - ImGui.SetNextItemWidth(200); + UiSharedService.ScaledNextItemWidth(200); using (var combo = ImRaii.Combo("##character", string.IsNullOrEmpty(user.AssociatedCharaName) ? "No character assigned" : CharaName(user.AssociatedCharaName))) { if (combo) diff --git a/MareSynchronos/UI/CharaDataHubUi.McdOnline.cs b/MareSynchronos/UI/CharaDataHubUi.McdOnline.cs index e2daa2a..daa8143 100644 --- a/MareSynchronos/UI/CharaDataHubUi.McdOnline.cs +++ b/MareSynchronos/UI/CharaDataHubUi.McdOnline.cs @@ -11,6 +11,11 @@ namespace MareSynchronos.UI; internal sealed partial class CharaDataHubUi { + private string _createDescFilter = string.Empty; + private string _createCodeFilter = string.Empty; + private bool _createOnlyShowFav = false; + private bool _createOnlyShowNotDownloadable = false; + private void DrawEditCharaData(CharaDataFullExtendedDto? dataDto) { using var imguiid = ImRaii.PushId(dataDto?.Id ?? "NoData"); @@ -30,8 +35,17 @@ internal sealed partial class CharaDataHubUi return; } + int otherUpdates = 0; + foreach (var item in _charaDataManager.OwnCharaData.Values.Where(v => !string.Equals(v.Id, dataDto.Id, StringComparison.Ordinal))) + { + if (_charaDataManager.GetUpdateDto(item.Id)?.HasChanges ?? false) + { + otherUpdates++; + } + } + bool canUpdate = updateDto.HasChanges; - if (canUpdate || _charaDataManager.CharaUpdateTask != null) + if (canUpdate || otherUpdates > 0 || (!_charaDataManager.CharaUpdateTask?.IsCompleted ?? false)) { ImGuiHelpers.ScaledDummy(5); } @@ -91,9 +105,27 @@ internal sealed partial class CharaDataHubUi } }); } + + if (otherUpdates > 0) + { + ImGuiHelpers.ScaledDummy(5); + UiSharedService.DrawGrouped(() => + { + ImGui.AlignTextToFramePadding(); + UiSharedService.ColorTextWrapped($"You have {otherUpdates} other entries with unsaved changes.", ImGuiColors.DalamudYellow); + ImGui.SameLine(); + using (ImRaii.Disabled(_charaDataManager.CharaUpdateTask != null && !_charaDataManager.CharaUpdateTask.IsCompleted)) + { + if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowAltCircleUp, "Save all to server")) + { + _charaDataManager.UploadAllCharaData(); + } + } + }); + } indent.Dispose(); - if (canUpdate || _charaDataManager.CharaUpdateTask != null) + if (canUpdate || otherUpdates > 0 || (!_charaDataManager.CharaUpdateTask?.IsCompleted ?? false)) { ImGuiHelpers.ScaledDummy(5); } @@ -550,7 +582,7 @@ internal sealed partial class CharaDataHubUi } using (var table = ImRaii.Table("Own Character Data", 12, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.ScrollY, - new Vector2(ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X, 110 * ImGuiHelpers.GlobalScale))) + new Vector2(ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X, 140 * ImGuiHelpers.GlobalScale))) { if (table) { @@ -566,9 +598,64 @@ internal sealed partial class CharaDataHubUi ImGui.TableSetupColumn("Glamourer", ImGuiTableColumnFlags.WidthFixed, 18 * ImGuiHelpers.GlobalScale); ImGui.TableSetupColumn("Customize+", ImGuiTableColumnFlags.WidthFixed, 18 * ImGuiHelpers.GlobalScale); ImGui.TableSetupColumn("Expires", ImGuiTableColumnFlags.WidthFixed, 18 * ImGuiHelpers.GlobalScale); - ImGui.TableSetupScrollFreeze(0, 1); + ImGui.TableSetupScrollFreeze(0, 2); ImGui.TableHeadersRow(); - foreach (var entry in _charaDataManager.OwnCharaData.Values.OrderBy(b => b.CreatedDate)) + + ImGui.TableNextColumn(); + ImGui.Dummy(new(0, 0)); + ImGui.TableNextColumn(); + ImGui.Checkbox("###createOnlyShowfav", ref _createOnlyShowFav); + UiSharedService.AttachToolTip("Filter by favorites"); + ImGui.TableNextColumn(); + var x1 = ImGui.GetContentRegionAvail().X; + ImGui.SetNextItemWidth(x1); + ImGui.InputTextWithHint("###createFilterCode", "Filter by code", ref _createCodeFilter, 200); + ImGui.TableNextColumn(); + var x2 = ImGui.GetContentRegionAvail().X; + ImGui.SetNextItemWidth(x2); + ImGui.InputTextWithHint("###createFilterDesc", "Filter by description", ref _createDescFilter, 200); + ImGui.TableNextColumn(); + ImGui.Dummy(new(0, 0)); + ImGui.TableNextColumn(); + ImGui.Dummy(new(0, 0)); + ImGui.TableNextColumn(); + ImGui.Dummy(new(0, 0)); + ImGui.TableNextColumn(); + ImGui.Checkbox("###createShowNotDl", ref _createOnlyShowNotDownloadable); + UiSharedService.AttachToolTip("Filter by not downloadable"); + ImGui.TableNextColumn(); + ImGui.Dummy(new(0, 0)); + ImGui.TableNextColumn(); + ImGui.Dummy(new(0, 0)); + ImGui.TableNextColumn(); + ImGui.Dummy(new(0, 0)); + ImGui.TableNextColumn(); + ImGui.Dummy(new(0, 0)); + + + foreach (var entry in _charaDataManager.OwnCharaData.Values + .Where(v => + { + bool show = true; + if (!string.IsNullOrWhiteSpace(_createCodeFilter)) + { + show &= v.FullId.Contains(_createCodeFilter, StringComparison.OrdinalIgnoreCase); + } + if (!string.IsNullOrWhiteSpace(_createDescFilter)) + { + show &= v.Description.Contains(_createDescFilter, StringComparison.OrdinalIgnoreCase); + } + if (_createOnlyShowFav) + { + show &= _configService.Current.FavoriteCodes.ContainsKey(v.FullId); + } + if (_createOnlyShowNotDownloadable) + { + show &= !(!v.HasMissingFiles && !string.IsNullOrEmpty(v.GlamourerData)); + } + + return show; + }).OrderBy(b => b.CreatedDate)) { var uDto = _charaDataManager.GetUpdateDto(entry.Id); ImGui.TableNextColumn(); @@ -729,7 +816,7 @@ internal sealed partial class CharaDataHubUi _uiSharedService.DrawHelpText("Users added to this list will be able to access this character data regardless of your pause or pair state with them." + UiSharedService.TooltipSeparator + "Note: Mistyped entries will be automatically removed on updating data to server."); - using (var lb = ImRaii.ListBox("Allowed Individuals", new(200, 200))) + using (var lb = ImRaii.ListBox("Allowed Individuals", new(200 * ImGuiHelpers.GlobalScale, 200 * ImGuiHelpers.GlobalScale))) { foreach (var user in updateDto.UserList) { @@ -749,6 +836,28 @@ internal sealed partial class CharaDataHubUi _selectedSpecificUserIndividual = string.Empty; } } + + using (ImRaii.Disabled(!UiSharedService.CtrlPressed())) + { + if (_uiSharedService.IconTextButton(FontAwesomeIcon.ExclamationTriangle, "Apply current Allowed Individuals to all MCDO entries")) + { + foreach (var own in _charaDataManager.OwnCharaData.Values.Where(k => !string.Equals(k.Id, updateDto.Id, StringComparison.Ordinal))) + { + var otherUpdateDto = _charaDataManager.GetUpdateDto(own.Id); + if (otherUpdateDto == null) continue; + foreach (var user in otherUpdateDto.UserList.Select(k => k.UID).Concat(otherUpdateDto.AllowedUsers ?? []).Distinct(StringComparer.Ordinal).ToList()) + { + otherUpdateDto.RemoveUserFromList(user); + } + foreach (var user in updateDto.UserList.Select(k => k.UID).Concat(updateDto.AllowedUsers ?? []).Distinct(StringComparer.Ordinal).ToList()) + { + otherUpdateDto.AddUserToList(user); + } + } + } + } + UiSharedService.AttachToolTip("This will apply the current list of allowed specific individuals to ALL of your MCDO entries." + UiSharedService.TooltipSeparator + + "Hold CTRL to enable."); } } ImGui.SameLine(); @@ -776,7 +885,7 @@ internal sealed partial class CharaDataHubUi _uiSharedService.DrawHelpText("Users in Syncshells added to this list will be able to access this character data regardless of your pause or pair state with them." + UiSharedService.TooltipSeparator + "Note: Mistyped entries will be automatically removed on updating data to server."); - using (var lb = ImRaii.ListBox("Allowed Syncshells", new(200, 200))) + using (var lb = ImRaii.ListBox("Allowed Syncshells", new(200 * ImGuiHelpers.GlobalScale, 200 * ImGuiHelpers.GlobalScale))) { foreach (var group in updateDto.GroupList) { @@ -796,6 +905,28 @@ internal sealed partial class CharaDataHubUi _selectedSpecificGroupIndividual = string.Empty; } } + + using (ImRaii.Disabled(!UiSharedService.CtrlPressed())) + { + if (_uiSharedService.IconTextButton(FontAwesomeIcon.ExclamationTriangle, "Apply current Allowed Syncshells to all MCDO entries")) + { + foreach (var own in _charaDataManager.OwnCharaData.Values.Where(k => !string.Equals(k.Id, updateDto.Id, StringComparison.Ordinal))) + { + var otherUpdateDto = _charaDataManager.GetUpdateDto(own.Id); + if (otherUpdateDto == null) continue; + foreach (var group in otherUpdateDto.GroupList.Select(k => k.GID).Concat(otherUpdateDto.AllowedGroups ?? []).Distinct(StringComparer.Ordinal).ToList()) + { + otherUpdateDto.RemoveGroupFromList(group); + } + foreach (var group in updateDto.GroupList.Select(k => k.GID).Concat(updateDto.AllowedGroups ?? []).Distinct(StringComparer.Ordinal).ToList()) + { + otherUpdateDto.AddGroupToList(group); + } + } + } + } + UiSharedService.AttachToolTip("This will apply the current list of allowed specific syncshells to ALL of your MCDO entries." + UiSharedService.TooltipSeparator + + "Hold CTRL to enable."); } } diff --git a/MareSynchronos/UI/CharaDataHubUi.NearbyPoses.cs b/MareSynchronos/UI/CharaDataHubUi.NearbyPoses.cs index 0a78cc3..ea9b64e 100644 --- a/MareSynchronos/UI/CharaDataHubUi.NearbyPoses.cs +++ b/MareSynchronos/UI/CharaDataHubUi.NearbyPoses.cs @@ -58,7 +58,7 @@ internal partial class CharaDataHubUi } _uiSharedService.DrawHelpText("When enabled, Mare will draw floating wisps where other's poses are in the world."); int poseDetectionDistance = _configService.Current.NearbyDistanceFilter; - ImGui.SetNextItemWidth(100); + UiSharedService.ScaledNextItemWidth(100); if (ImGui.SliderInt("Detection Distance", ref poseDetectionDistance, 5, 1000)) { _configService.Current.NearbyDistanceFilter = poseDetectionDistance; diff --git a/MareSynchronos/UI/UISharedService.cs b/MareSynchronos/UI/UISharedService.cs index 5314c35..a08d879 100644 --- a/MareSynchronos/UI/UISharedService.cs +++ b/MareSynchronos/UI/UISharedService.cs @@ -34,58 +34,45 @@ namespace MareSynchronos.UI; public partial class UiSharedService : DisposableMediatorSubscriberBase { public const string TooltipSeparator = "--SEP--"; - public static string DoubleNewLine => Environment.NewLine + Environment.NewLine; - public static readonly ImGuiWindowFlags PopupWindowFlags = ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse; public readonly FileDialogManager FileDialogManager; - private const string _notesEnd = "##MARE_SYNCHRONOS_USER_NOTES_END##"; - private const string _notesStart = "##MARE_SYNCHRONOS_USER_NOTES_START##"; - private readonly ApiController _apiController; - private readonly CacheMonitor _cacheMonitor; - private readonly MareConfigService _configService; - private readonly DalamudUtilService _dalamudUtil; private readonly IpcManager _ipcManager; private readonly Dalamud.Localization _localization; private readonly IDalamudPluginInterface _pluginInterface; - private readonly ITextureProvider _textureProvider; private readonly Dictionary _selectedComboItems = new(StringComparer.Ordinal); private readonly ServerConfigurationManager _serverConfigurationManager; + private readonly ITextureProvider _textureProvider; private readonly TokenProvider _tokenProvider; + private bool _brioExists = false; private bool _cacheDirectoryHasOtherFilesThanCache = false; - private bool _cacheDirectoryIsValidPath = true; - private bool _customizePlusExists = false; - private string _customServerName = ""; - private string _customServerUri = ""; - + private Task? _discordOAuthCheck; + private Task? _discordOAuthGetCode; + private CancellationTokenSource _discordOAuthGetCts = new(); + private Task>? _discordOAuthUIDs; private bool _glamourerExists = false; - private bool _heelsExists = false; - private bool _honorificExists = false; private bool _isDirectoryWritable = false; private bool _isOneDrive = false; private bool _isPenumbraDirectory = false; private bool _moodlesExists = false; + private Dictionary _oauthTokenExpiry = new(); private bool _penumbraExists = false; private bool _petNamesExists = false; - private bool _brioExists = false; - private int _serverSelectionIndex = -1; - private Dictionary _oauthTokenExpiry = new(); - public UiSharedService(ILogger logger, IpcManager ipcManager, ApiController apiController, CacheMonitor cacheMonitor, FileDialogManager fileDialogManager, MareConfigService configService, DalamudUtilService dalamudUtil, IDalamudPluginInterface pluginInterface, @@ -131,6 +118,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase IconFont = _pluginInterface.UiBuilder.IconFontFixedWidthHandle; } + public static string DoubleNewLine => Environment.NewLine + Environment.NewLine; public ApiController ApiController => _apiController; public bool EditTrackerPosition { get; set; } @@ -141,12 +129,11 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase public IFontHandle IconFont { get; init; } public bool IsInGpose => _dalamudUtil.IsInGpose; + public Dictionary JobData => _dalamudUtil.JobData.Value; public string PlayerName => _dalamudUtil.GetPlayerName(); public IFontHandle UidFont { get; init; } public Dictionary WorldData => _dalamudUtil.WorldData.Value; - public Dictionary JobData => _dalamudUtil.JobData.Value; - public uint WorldId => _dalamudUtil.GetHomeWorldId(); public static void AttachToolTip(string text) @@ -221,6 +208,38 @@ 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) + { + var cursorPos = ImGui.GetCursorPos(); + using (ImRaii.Group()) + { + if (expectedWidth != null) + { + ImGui.Dummy(new(expectedWidth.Value, 0)); + ImGui.SetCursorPos(cursorPos); + } + + imguiDrawAction.Invoke(); + } + + ImGui.GetWindowDrawList().AddRect( + ImGui.GetItemRectMin() - ImGui.GetStyle().ItemInnerSpacing, + ImGui.GetItemRectMax() + ImGui.GetStyle().ItemInnerSpacing, + Color(ImGuiColors.DalamudGrey2), rounding); + } + + public static void DrawGroupedCenteredColorText(string text, Vector4 color, float? maxWidth = null) + { + var availWidth = ImGui.GetContentRegionAvail().X; + var textWidth = ImGui.CalcTextSize(text, availWidth).X; + if (maxWidth != null && textWidth > maxWidth * ImGuiHelpers.GlobalScale) textWidth = maxWidth.Value * ImGuiHelpers.GlobalScale; + ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (availWidth / 2f) - (textWidth / 2f)); + DrawGrouped(() => + { + ColorTextWrapped(text, color, ImGui.GetCursorPosX() + textWidth); + }, expectedWidth: maxWidth == null ? null : maxWidth * ImGuiHelpers.GlobalScale); + } + public static void DrawOutlinedFont(string text, Vector4 fontColor, Vector4 outlineColor, int thickness) { var original = ImGui.GetCursorPos(); @@ -277,19 +296,17 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase drawList.AddText(textPos, fontColor, text); } - public static Vector4 GetBoolColor(bool input) => input ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; - - public float GetIconTextButtonSize(FontAwesomeIcon icon, string text) + public static void DrawTree(string leafName, Action drawOnOpened, ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags.None) { - Vector2 vector; - using (IconFont.Push()) - vector = ImGui.CalcTextSize(icon.ToIconString()); - - Vector2 vector2 = ImGui.CalcTextSize(text); - float num = 3f * ImGuiHelpers.GlobalScale; - return vector.X + vector2.X + ImGui.GetStyle().FramePadding.X * 2f + num; + using var tree = ImRaii.TreeNode(leafName, flags); + if (tree) + { + drawOnOpened(); + } } + public static Vector4 GetBoolColor(bool input) => input ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed; + public static string GetNotes(List pairs) { StringBuilder sb = new(); @@ -311,69 +328,6 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase return ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X; } - public bool IconButton(FontAwesomeIcon icon, float? height = null) - { - string text = icon.ToIconString(); - - ImGui.PushID(text); - Vector2 vector; - using (IconFont.Push()) - vector = ImGui.CalcTextSize(text); - ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList(); - Vector2 cursorScreenPos = ImGui.GetCursorScreenPos(); - float x = vector.X + ImGui.GetStyle().FramePadding.X * 2f; - float frameHeight = height ?? ImGui.GetFrameHeight(); - bool result = ImGui.Button(string.Empty, new Vector2(x, frameHeight)); - Vector2 pos = new Vector2(cursorScreenPos.X + ImGui.GetStyle().FramePadding.X, - cursorScreenPos.Y + (height ?? ImGui.GetFrameHeight()) / 2f - (vector.Y / 2f)); - using (IconFont.Push()) - windowDrawList.AddText(pos, ImGui.GetColorU32(ImGuiCol.Text), text); - ImGui.PopID(); - - return result; - } - - private bool IconTextButtonInternal(FontAwesomeIcon icon, string text, Vector4? defaultColor = null, float? width = null) - { - int num = 0; - if (defaultColor.HasValue) - { - ImGui.PushStyleColor(ImGuiCol.Button, defaultColor.Value); - num++; - } - - ImGui.PushID(text); - Vector2 vector; - using (IconFont.Push()) - vector = ImGui.CalcTextSize(icon.ToIconString()); - Vector2 vector2 = ImGui.CalcTextSize(text); - ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList(); - Vector2 cursorScreenPos = ImGui.GetCursorScreenPos(); - float num2 = 3f * ImGuiHelpers.GlobalScale; - float x = width ?? vector.X + vector2.X + ImGui.GetStyle().FramePadding.X * 2f + num2; - float frameHeight = ImGui.GetFrameHeight(); - bool result = ImGui.Button(string.Empty, new Vector2(x, frameHeight)); - Vector2 pos = new Vector2(cursorScreenPos.X + ImGui.GetStyle().FramePadding.X, cursorScreenPos.Y + ImGui.GetStyle().FramePadding.Y); - using (IconFont.Push()) - windowDrawList.AddText(pos, ImGui.GetColorU32(ImGuiCol.Text), icon.ToIconString()); - Vector2 pos2 = new Vector2(pos.X + vector.X + num2, cursorScreenPos.Y + ImGui.GetStyle().FramePadding.Y); - windowDrawList.AddText(pos2, ImGui.GetColorU32(ImGuiCol.Text), text); - ImGui.PopID(); - if (num > 0) - { - ImGui.PopStyleColor(num); - } - - return result; - } - - public bool IconTextButton(FontAwesomeIcon icon, string text, float? width = null, bool isInPopup = false) - { - return IconTextButtonInternal(icon, text, - isInPopup ? ColorHelpers.RgbaUintToVector4(ImGui.GetColorU32(ImGuiCol.PopupBg)) : null, - width <= 0 ? null : width); - } - public static bool IsDirectoryWritable(string dirPath, bool throwIfFails = false) { try @@ -396,6 +350,16 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase } } + public static void ScaledNextItemWidth(float width) + { + ImGui.SetNextItemWidth(width * ImGuiHelpers.GlobalScale); + } + + public static void ScaledSameLine(float offset) + { + ImGui.SameLine(offset * ImGuiHelpers.GlobalScale); + } + public static void SetScaledWindowSize(float width, bool centerWindow = true) { var newLineHeight = ImGui.GetCursorPosY(); @@ -641,284 +605,6 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase AttachToolTip(helpText); } - public bool DrawOtherPluginState() - { - var check = FontAwesomeIcon.Check; - var cross = FontAwesomeIcon.SquareXmark; - ImGui.TextUnformatted("Mandatory Plugins:"); - - ImGui.SameLine(150); - ColorText("Penumbra", GetBoolColor(_penumbraExists)); - AttachToolTip($"Penumbra is " + (_penumbraExists ? "available and up to date." : "unavailable or not up to date.")); - - ImGui.SameLine(); - ColorText("Glamourer", GetBoolColor(_glamourerExists)); - AttachToolTip($"Glamourer is " + (_glamourerExists ? "available and up to date." : "unavailable or not up to date.")); - - ImGui.TextUnformatted("Optional Plugins:"); - ImGui.SameLine(150); - ColorText("SimpleHeels", GetBoolColor(_heelsExists)); - AttachToolTip($"SimpleHeels is " + (_heelsExists ? "available and up to date." : "unavailable or not up to date.")); - - ImGui.SameLine(); - ColorText("Customize+", GetBoolColor(_customizePlusExists)); - AttachToolTip($"Customize+ is " + (_customizePlusExists ? "available and up to date." : "unavailable or not up to date.")); - - ImGui.SameLine(); - ColorText("Honorific", GetBoolColor(_honorificExists)); - AttachToolTip($"Honorific is " + (_honorificExists ? "available and up to date." : "unavailable or not up to date.")); - - ImGui.SameLine(); - ColorText("Moodles", GetBoolColor(_moodlesExists)); - AttachToolTip($"Moodles is " + (_moodlesExists ? "available and up to date." : "unavailable or not up to date.")); - - ImGui.SameLine(); - ColorText("PetNicknames", GetBoolColor(_petNamesExists)); - AttachToolTip($"PetNicknames is " + (_petNamesExists ? "available and up to date." : "unavailable or not up to date.")); - - ImGui.SameLine(); - ColorText("Brio", GetBoolColor(_brioExists)); - AttachToolTip($"Brio is " + (_brioExists ? "available and up to date." : "unavailable or not up to date.")); - - if (!_penumbraExists || !_glamourerExists) - { - ImGui.TextColored(ImGuiColors.DalamudRed, "You need to install both Penumbra and Glamourer and keep them up to date to use Mare Synchronos."); - return false; - } - - return true; - } - - public int DrawServiceSelection(bool selectOnChange = false, bool showConnect = true) - { - string[] comboEntries = _serverConfigurationManager.GetServerNames(); - - if (_serverSelectionIndex == -1) - { - _serverSelectionIndex = Array.IndexOf(_serverConfigurationManager.GetServerApiUrls(), _serverConfigurationManager.CurrentApiUrl); - } - if (_serverSelectionIndex == -1 || _serverSelectionIndex >= comboEntries.Length) - { - _serverSelectionIndex = 0; - } - for (int i = 0; i < comboEntries.Length; i++) - { - if (string.Equals(_serverConfigurationManager.CurrentServer?.ServerName, comboEntries[i], StringComparison.OrdinalIgnoreCase)) - comboEntries[i] += " [Current]"; - } - if (ImGui.BeginCombo("Select Service", comboEntries[_serverSelectionIndex])) - { - for (int i = 0; i < comboEntries.Length; i++) - { - bool isSelected = _serverSelectionIndex == i; - if (ImGui.Selectable(comboEntries[i], isSelected)) - { - _serverSelectionIndex = i; - if (selectOnChange) - { - _serverConfigurationManager.SelectServer(i); - } - } - - if (isSelected) - { - ImGui.SetItemDefaultFocus(); - } - } - - ImGui.EndCombo(); - } - - if (showConnect) - { - ImGui.SameLine(); - var text = "Connect"; - if (_serverSelectionIndex == _serverConfigurationManager.CurrentServerIndex) text = "Reconnect"; - if (IconTextButton(FontAwesomeIcon.Link, text)) - { - _serverConfigurationManager.SelectServer(_serverSelectionIndex); - _ = _apiController.CreateConnectionsAsync(); - } - } - - if (ImGui.TreeNode("Add Custom Service")) - { - ImGui.SetNextItemWidth(250); - ImGui.InputText("Custom Service URI", ref _customServerUri, 255); - ImGui.SetNextItemWidth(250); - ImGui.InputText("Custom Service Name", ref _customServerName, 255); - if (IconTextButton(FontAwesomeIcon.Plus, "Add Custom Service") - && !string.IsNullOrEmpty(_customServerUri) - && !string.IsNullOrEmpty(_customServerName)) - { - _serverConfigurationManager.AddServer(new ServerStorage() - { - ServerName = _customServerName, - ServerUri = _customServerUri, - UseOAuth2 = true - }); - _customServerName = string.Empty; - _customServerUri = string.Empty; - _configService.Save(); - } - ImGui.TreePop(); - } - - return _serverSelectionIndex; - } - - public Vector2 GetIconButtonSize(FontAwesomeIcon icon) - { - using var font = IconFont.Push(); - return ImGuiHelpers.GetButtonSize(icon.ToIconString()); - } - - public Vector2 GetIconSize(FontAwesomeIcon icon) - { - using var font = IconFont.Push(); - return ImGui.CalcTextSize(icon.ToIconString()); - } - - public void IconText(FontAwesomeIcon icon, uint color) - { - FontText(icon.ToIconString(), IconFont, color); - } - - public void IconText(FontAwesomeIcon icon, Vector4? color = null) - { - IconText(icon, color == null ? ImGui.GetColorU32(ImGuiCol.Text) : ImGui.GetColorU32(color.Value)); - } - - public IDalamudTextureWrap LoadImage(byte[] imageData) - { - return _textureProvider.CreateFromImageAsync(imageData).Result; - } - - public void LoadLocalization(string languageCode) - { - _localization.SetupWithLangCode(languageCode); - Strings.ToS = new Strings.ToSStrings(); - } - - [LibraryImport("user32")] - internal static partial short GetKeyState(int nVirtKey); - - private static void CenterWindow(float width, float height, ImGuiCond cond = ImGuiCond.None) - { - var center = ImGui.GetMainViewport().GetCenter(); - ImGui.SetWindowPos(new Vector2(center.X - width / 2, center.Y - height / 2), cond); - } - - [GeneratedRegex(@"^(?:[a-zA-Z]:\\[\w\s\-\\]+?|\/(?:[\w\s\-\/])+?)$", RegexOptions.ECMAScript, 5000)] - private static partial Regex PathRegex(); - - private void FontText(string text, IFontHandle font, Vector4? color = null) - { - FontText(text, font, color == null ? ImGui.GetColorU32(ImGuiCol.Text) : ImGui.GetColorU32(color.Value)); - } - - private void FontText(string text, IFontHandle font, uint color) - { - using var pushedFont = font.Push(); - using var pushedColor = ImRaii.PushColor(ImGuiCol.Text, color); - ImGui.TextUnformatted(text); - } - - public sealed record IconScaleData(Vector2 IconSize, Vector2 NormalizedIconScale, float OffsetX, float IconScaling); - - protected override void Dispose(bool disposing) - { - if (!disposing) return; - - base.Dispose(disposing); - - UidFont.Dispose(); - GameFont.Dispose(); - } - - private Task? _discordOAuthCheck; - private CancellationTokenSource _discordOAuthGetCts = new(); - private Task? _discordOAuthGetCode; - private Task>? _discordOAuthUIDs; - - public void DrawUpdateOAuthUIDsButton(ServerStorage selectedServer) - { - if (!selectedServer.UseOAuth2) - return; - - using (ImRaii.Disabled(string.IsNullOrEmpty(selectedServer.OAuthToken))) - { - if ((_discordOAuthUIDs == null || _discordOAuthUIDs.IsCompleted) - && IconTextButton(FontAwesomeIcon.ArrowsSpin, "Update UIDs from Service") - && !string.IsNullOrEmpty(selectedServer.OAuthToken)) - { - _discordOAuthUIDs = _serverConfigurationManager.GetUIDsWithDiscordToken(selectedServer.ServerUri, selectedServer.OAuthToken); - } - } - DateTime tokenExpiry = DateTime.MinValue; - if (!string.IsNullOrEmpty(selectedServer.OAuthToken) && !_oauthTokenExpiry.TryGetValue(selectedServer.OAuthToken, out tokenExpiry)) - { - try - { - var handler = new JwtSecurityTokenHandler(); - var jwt = handler.ReadJwtToken(selectedServer.OAuthToken); - tokenExpiry = _oauthTokenExpiry[selectedServer.OAuthToken] = jwt.ValidTo; - } - catch (Exception ex) - { - Logger.LogWarning(ex, "Could not parse OAuth token, deleting"); - selectedServer.OAuthToken = null; - _serverConfigurationManager.Save(); - tokenExpiry = DateTime.MinValue; - } - } - if (string.IsNullOrEmpty(selectedServer.OAuthToken) || tokenExpiry < DateTime.UtcNow) - { - ColorTextWrapped("You have no OAuth token or the OAuth token is expired. Please use the Service Settings to (re)link your OAuth account.", ImGuiColors.DalamudRed); - } - } - - private record UIDAliasPair(string? UID, string? Alias); - - public void DrawUIDComboForAuthentication(int indexOffset, Authentication item, string serverUri, ILogger? logger = null) - { - using (ImRaii.Disabled(_discordOAuthUIDs == null)) - { - var aliasPairs = _discordOAuthUIDs?.Result?.Select(t => new UIDAliasPair(t.Key, t.Value)).ToList() ?? [new UIDAliasPair(item.UID ?? null, null)]; - var uidComboName = "UID###" + item.CharacterName + item.WorldId + serverUri + indexOffset + aliasPairs.Count; - DrawCombo(uidComboName, aliasPairs, - (v) => - { - if (v is null) - return "No UID set"; - - if (!string.IsNullOrEmpty(v.Alias)) - { - return $"{v.UID} ({v.Alias})"; - } - - if (string.IsNullOrEmpty(v.UID)) - return "No UID set"; - - return $"{v.UID}"; - }, - (v) => - { - if (!string.Equals(v?.UID ?? null, item.UID, StringComparison.Ordinal)) - { - item.UID = v?.UID ?? null; - _serverConfigurationManager.Save(); - } - }, - aliasPairs.Find(f => string.Equals(f.UID, item.UID, StringComparison.Ordinal)) ?? default); - } - - if (_discordOAuthUIDs == null) - { - AttachToolTip("Use the button above to update your UIDs from the service before you can assign UIDs to characters."); - } - } - public void DrawOAuth(ServerStorage selectedServer) { var oauthToken = selectedServer.OAuthToken; @@ -1069,6 +755,169 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase } } + public bool DrawOtherPluginState() + { + ImGui.TextUnformatted("Mandatory Plugins:"); + + ImGui.SameLine(150); + ColorText("Penumbra", GetBoolColor(_penumbraExists)); + AttachToolTip($"Penumbra is " + (_penumbraExists ? "available and up to date." : "unavailable or not up to date.")); + + ImGui.SameLine(); + ColorText("Glamourer", GetBoolColor(_glamourerExists)); + AttachToolTip($"Glamourer is " + (_glamourerExists ? "available and up to date." : "unavailable or not up to date.")); + + ImGui.TextUnformatted("Optional Plugins:"); + ImGui.SameLine(150); + ColorText("SimpleHeels", GetBoolColor(_heelsExists)); + AttachToolTip($"SimpleHeels is " + (_heelsExists ? "available and up to date." : "unavailable or not up to date.")); + + ImGui.SameLine(); + ColorText("Customize+", GetBoolColor(_customizePlusExists)); + AttachToolTip($"Customize+ is " + (_customizePlusExists ? "available and up to date." : "unavailable or not up to date.")); + + ImGui.SameLine(); + ColorText("Honorific", GetBoolColor(_honorificExists)); + AttachToolTip($"Honorific is " + (_honorificExists ? "available and up to date." : "unavailable or not up to date.")); + + ImGui.SameLine(); + ColorText("Moodles", GetBoolColor(_moodlesExists)); + AttachToolTip($"Moodles is " + (_moodlesExists ? "available and up to date." : "unavailable or not up to date.")); + + ImGui.SameLine(); + ColorText("PetNicknames", GetBoolColor(_petNamesExists)); + AttachToolTip($"PetNicknames is " + (_petNamesExists ? "available and up to date." : "unavailable or not up to date.")); + + ImGui.SameLine(); + ColorText("Brio", GetBoolColor(_brioExists)); + AttachToolTip($"Brio is " + (_brioExists ? "available and up to date." : "unavailable or not up to date.")); + + if (!_penumbraExists || !_glamourerExists) + { + ImGui.TextColored(ImGuiColors.DalamudRed, "You need to install both Penumbra and Glamourer and keep them up to date to use Mare Synchronos."); + return false; + } + + return true; + } + + public int DrawServiceSelection(bool selectOnChange = false, bool showConnect = true) + { + string[] comboEntries = _serverConfigurationManager.GetServerNames(); + + if (_serverSelectionIndex == -1) + { + _serverSelectionIndex = Array.IndexOf(_serverConfigurationManager.GetServerApiUrls(), _serverConfigurationManager.CurrentApiUrl); + } + if (_serverSelectionIndex == -1 || _serverSelectionIndex >= comboEntries.Length) + { + _serverSelectionIndex = 0; + } + for (int i = 0; i < comboEntries.Length; i++) + { + if (string.Equals(_serverConfigurationManager.CurrentServer?.ServerName, comboEntries[i], StringComparison.OrdinalIgnoreCase)) + comboEntries[i] += " [Current]"; + } + if (ImGui.BeginCombo("Select Service", comboEntries[_serverSelectionIndex])) + { + for (int i = 0; i < comboEntries.Length; i++) + { + bool isSelected = _serverSelectionIndex == i; + if (ImGui.Selectable(comboEntries[i], isSelected)) + { + _serverSelectionIndex = i; + if (selectOnChange) + { + _serverConfigurationManager.SelectServer(i); + } + } + + if (isSelected) + { + ImGui.SetItemDefaultFocus(); + } + } + + ImGui.EndCombo(); + } + + if (showConnect) + { + ImGui.SameLine(); + var text = "Connect"; + if (_serverSelectionIndex == _serverConfigurationManager.CurrentServerIndex) text = "Reconnect"; + if (IconTextButton(FontAwesomeIcon.Link, text)) + { + _serverConfigurationManager.SelectServer(_serverSelectionIndex); + _ = _apiController.CreateConnectionsAsync(); + } + } + + if (ImGui.TreeNode("Add Custom Service")) + { + ImGui.SetNextItemWidth(250); + ImGui.InputText("Custom Service URI", ref _customServerUri, 255); + ImGui.SetNextItemWidth(250); + ImGui.InputText("Custom Service Name", ref _customServerName, 255); + if (IconTextButton(FontAwesomeIcon.Plus, "Add Custom Service") + && !string.IsNullOrEmpty(_customServerUri) + && !string.IsNullOrEmpty(_customServerName)) + { + _serverConfigurationManager.AddServer(new ServerStorage() + { + ServerName = _customServerName, + ServerUri = _customServerUri, + UseOAuth2 = true + }); + _customServerName = string.Empty; + _customServerUri = string.Empty; + _configService.Save(); + } + ImGui.TreePop(); + } + + return _serverSelectionIndex; + } + + public void DrawUIDComboForAuthentication(int indexOffset, Authentication item, string serverUri, ILogger? logger = null) + { + using (ImRaii.Disabled(_discordOAuthUIDs == null)) + { + var aliasPairs = _discordOAuthUIDs?.Result?.Select(t => new UIDAliasPair(t.Key, t.Value)).ToList() ?? [new UIDAliasPair(item.UID ?? null, null)]; + var uidComboName = "UID###" + item.CharacterName + item.WorldId + serverUri + indexOffset + aliasPairs.Count; + DrawCombo(uidComboName, aliasPairs, + (v) => + { + if (v is null) + return "No UID set"; + + if (!string.IsNullOrEmpty(v.Alias)) + { + return $"{v.UID} ({v.Alias})"; + } + + if (string.IsNullOrEmpty(v.UID)) + return "No UID set"; + + return $"{v.UID}"; + }, + (v) => + { + if (!string.Equals(v?.UID ?? null, item.UID, StringComparison.Ordinal)) + { + item.UID = v?.UID ?? null; + _serverConfigurationManager.Save(); + } + }, + aliasPairs.Find(f => string.Equals(f.UID, item.UID, StringComparison.Ordinal)) ?? default); + } + + if (_discordOAuthUIDs == null) + { + AttachToolTip("Use the button above to update your UIDs from the service before you can assign UIDs to characters."); + } + } + public void DrawUnlinkOAuthButton(ServerStorage selectedServer) { using (ImRaii.Disabled(!CtrlPressed())) @@ -1083,54 +932,114 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase DrawHelpText("Hold CTRL to unlink the current OAuth2 connection."); } - internal void RestOAuthTasksState() + public void DrawUpdateOAuthUIDsButton(ServerStorage selectedServer) { - _discordOAuthCheck = null; - _discordOAuthGetCts = _discordOAuthGetCts.CancelRecreate(); - _discordOAuthGetCode = null; - _discordOAuthUIDs = null; - } + if (!selectedServer.UseOAuth2) + return; - public static void DrawGrouped(Action imguiDrawAction, float rounding = 5f, float? expectedWidth = null) - { - var cursorPos = ImGui.GetCursorPos(); - using (ImRaii.Group()) + using (ImRaii.Disabled(string.IsNullOrEmpty(selectedServer.OAuthToken))) { - if (expectedWidth != null) + if ((_discordOAuthUIDs == null || _discordOAuthUIDs.IsCompleted) + && IconTextButton(FontAwesomeIcon.ArrowsSpin, "Update UIDs from Service") + && !string.IsNullOrEmpty(selectedServer.OAuthToken)) { - ImGui.Dummy(new(expectedWidth.Value, 0)); - ImGui.SetCursorPos(cursorPos); + _discordOAuthUIDs = _serverConfigurationManager.GetUIDsWithDiscordToken(selectedServer.ServerUri, selectedServer.OAuthToken); } - - imguiDrawAction.Invoke(); } - - ImGui.GetWindowDrawList().AddRect( - ImGui.GetItemRectMin() - ImGui.GetStyle().ItemInnerSpacing, - ImGui.GetItemRectMax() + ImGui.GetStyle().ItemInnerSpacing, - Color(ImGuiColors.DalamudGrey2), rounding); - } - - public static void DrawGroupedCenteredColorText(string text, Vector4 color, float? maxWidth = null) - { - var availWidth = ImGui.GetContentRegionAvail().X; - var textWidth = ImGui.CalcTextSize(text, availWidth).X; - if (maxWidth != null && textWidth > maxWidth * ImGuiHelpers.GlobalScale) textWidth = maxWidth.Value * ImGuiHelpers.GlobalScale; - ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (availWidth / 2f) - (textWidth / 2f)); - DrawGrouped(() => + DateTime tokenExpiry = DateTime.MinValue; + if (!string.IsNullOrEmpty(selectedServer.OAuthToken) && !_oauthTokenExpiry.TryGetValue(selectedServer.OAuthToken, out tokenExpiry)) { - ColorTextWrapped(text, color, ImGui.GetCursorPosX() + textWidth); - }, expectedWidth: maxWidth == null ? null : maxWidth * ImGuiHelpers.GlobalScale); + try + { + var handler = new JwtSecurityTokenHandler(); + var jwt = handler.ReadJwtToken(selectedServer.OAuthToken); + tokenExpiry = _oauthTokenExpiry[selectedServer.OAuthToken] = jwt.ValidTo; + } + catch (Exception ex) + { + Logger.LogWarning(ex, "Could not parse OAuth token, deleting"); + selectedServer.OAuthToken = null; + _serverConfigurationManager.Save(); + tokenExpiry = DateTime.MinValue; + } + } + if (string.IsNullOrEmpty(selectedServer.OAuthToken) || tokenExpiry < DateTime.UtcNow) + { + ColorTextWrapped("You have no OAuth token or the OAuth token is expired. Please use the Service Settings to (re)link your OAuth account.", ImGuiColors.DalamudRed); + } } - public static void ScaledSameLine(float offset) + public Vector2 GetIconButtonSize(FontAwesomeIcon icon) { - ImGui.SameLine(offset * ImGuiHelpers.GlobalScale); + using var font = IconFont.Push(); + return ImGuiHelpers.GetButtonSize(icon.ToIconString()); } - public static void ScaledNextItemWidth(float width) + public Vector2 GetIconSize(FontAwesomeIcon icon) { - ImGui.SetNextItemWidth(width * ImGuiHelpers.GlobalScale); + using var font = IconFont.Push(); + return ImGui.CalcTextSize(icon.ToIconString()); + } + + public float GetIconTextButtonSize(FontAwesomeIcon icon, string text) + { + Vector2 vector; + using (IconFont.Push()) + vector = ImGui.CalcTextSize(icon.ToIconString()); + + Vector2 vector2 = ImGui.CalcTextSize(text); + float num = 3f * ImGuiHelpers.GlobalScale; + return vector.X + vector2.X + ImGui.GetStyle().FramePadding.X * 2f + num; + } + + public bool IconButton(FontAwesomeIcon icon, float? height = null) + { + string text = icon.ToIconString(); + + ImGui.PushID(text); + Vector2 vector; + using (IconFont.Push()) + vector = ImGui.CalcTextSize(text); + ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList(); + Vector2 cursorScreenPos = ImGui.GetCursorScreenPos(); + float x = vector.X + ImGui.GetStyle().FramePadding.X * 2f; + float frameHeight = height ?? ImGui.GetFrameHeight(); + bool result = ImGui.Button(string.Empty, new Vector2(x, frameHeight)); + Vector2 pos = new Vector2(cursorScreenPos.X + ImGui.GetStyle().FramePadding.X, + cursorScreenPos.Y + (height ?? ImGui.GetFrameHeight()) / 2f - (vector.Y / 2f)); + using (IconFont.Push()) + windowDrawList.AddText(pos, ImGui.GetColorU32(ImGuiCol.Text), text); + ImGui.PopID(); + + return result; + } + + public void IconText(FontAwesomeIcon icon, uint color) + { + FontText(icon.ToIconString(), IconFont, color); + } + + public void IconText(FontAwesomeIcon icon, Vector4? color = null) + { + IconText(icon, color == null ? ImGui.GetColorU32(ImGuiCol.Text) : ImGui.GetColorU32(color.Value)); + } + + public bool IconTextButton(FontAwesomeIcon icon, string text, float? width = null, bool isInPopup = false) + { + return IconTextButtonInternal(icon, text, + isInPopup ? ColorHelpers.RgbaUintToVector4(ImGui.GetColorU32(ImGuiCol.PopupBg)) : null, + width <= 0 ? null : width); + } + + public IDalamudTextureWrap LoadImage(byte[] imageData) + { + return _textureProvider.CreateFromImageAsync(imageData).Result; + } + + public void LoadLocalization(string languageCode) + { + _localization.SetupWithLangCode(languageCode); + Strings.ToS = new Strings.ToSStrings(); } internal static void DistanceSeparator() @@ -1140,12 +1049,81 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase ImGuiHelpers.ScaledDummy(5); } - public static void DrawTree(string leafName, Action drawOnOpened, ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags.None) + [LibraryImport("user32")] + internal static partial short GetKeyState(int nVirtKey); + + internal void RestOAuthTasksState() { - using var tree = ImRaii.TreeNode(leafName, flags); - if (tree) - { - drawOnOpened(); - } + _discordOAuthCheck = null; + _discordOAuthGetCts = _discordOAuthGetCts.CancelRecreate(); + _discordOAuthGetCode = null; + _discordOAuthUIDs = null; } + + protected override void Dispose(bool disposing) + { + if (!disposing) return; + + base.Dispose(disposing); + + UidFont.Dispose(); + GameFont.Dispose(); + } + + private static void CenterWindow(float width, float height, ImGuiCond cond = ImGuiCond.None) + { + var center = ImGui.GetMainViewport().GetCenter(); + ImGui.SetWindowPos(new Vector2(center.X - width / 2, center.Y - height / 2), cond); + } + + [GeneratedRegex(@"^(?:[a-zA-Z]:\\[\w\s\-\\]+?|\/(?:[\w\s\-\/])+?)$", RegexOptions.ECMAScript, 5000)] + private static partial Regex PathRegex(); + + private static void FontText(string text, IFontHandle font, Vector4? color = null) + { + FontText(text, font, color == null ? ImGui.GetColorU32(ImGuiCol.Text) : ImGui.GetColorU32(color.Value)); + } + + private static void FontText(string text, IFontHandle font, uint color) + { + using var pushedFont = font.Push(); + using var pushedColor = ImRaii.PushColor(ImGuiCol.Text, color); + ImGui.TextUnformatted(text); + } + + private bool IconTextButtonInternal(FontAwesomeIcon icon, string text, Vector4? defaultColor = null, float? width = null) + { + int num = 0; + if (defaultColor.HasValue) + { + ImGui.PushStyleColor(ImGuiCol.Button, defaultColor.Value); + num++; + } + + ImGui.PushID(text); + Vector2 vector; + using (IconFont.Push()) + vector = ImGui.CalcTextSize(icon.ToIconString()); + Vector2 vector2 = ImGui.CalcTextSize(text); + ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList(); + Vector2 cursorScreenPos = ImGui.GetCursorScreenPos(); + float num2 = 3f * ImGuiHelpers.GlobalScale; + float x = width ?? vector.X + vector2.X + ImGui.GetStyle().FramePadding.X * 2f + num2; + float frameHeight = ImGui.GetFrameHeight(); + bool result = ImGui.Button(string.Empty, new Vector2(x, frameHeight)); + Vector2 pos = new Vector2(cursorScreenPos.X + ImGui.GetStyle().FramePadding.X, cursorScreenPos.Y + ImGui.GetStyle().FramePadding.Y); + using (IconFont.Push()) + windowDrawList.AddText(pos, ImGui.GetColorU32(ImGuiCol.Text), icon.ToIconString()); + Vector2 pos2 = new Vector2(pos.X + vector.X + num2, cursorScreenPos.Y + ImGui.GetStyle().FramePadding.Y); + windowDrawList.AddText(pos2, ImGui.GetColorU32(ImGuiCol.Text), text); + ImGui.PopID(); + if (num > 0) + { + ImGui.PopStyleColor(num); + } + + return result; + } + public sealed record IconScaleData(Vector2 IconSize, Vector2 NormalizedIconScale, float OffsetX, float IconScaling); + private record UIDAliasPair(string? UID, string? Alias); } \ No newline at end of file