diff --git a/CustomizePlus/Core/Helpers/Base64Helper.cs b/CustomizePlus/Core/Helpers/Base64Helper.cs index be360e8..8aa8268 100644 --- a/CustomizePlus/Core/Helpers/Base64Helper.cs +++ b/CustomizePlus/Core/Helpers/Base64Helper.cs @@ -1,5 +1,9 @@ using CustomizePlus.Core.Data; using CustomizePlus.Templates.Data; +using CustomizePlus.Api.Data; +using CustomizePlus.Profiles; +using CustomizePlus.Profiles.Data; +using CustomizePlus.Templates; using Newtonsoft.Json; using System; using System.Collections.Generic; @@ -50,6 +54,33 @@ public static string ExportTemplateToBase64(Template template) } } + public static string ExportProfileToBase64(Profile profile) + { + // Does the same thing as before above method but turns the profile into a template first via IPCCharacterProfile + // same as is done over in the PCP Service functionality + try + { + var ipcProfile = IPCCharacterProfile.FromFullProfile(profile); + var template = new Template(ipcProfile); + + var json = template.JsonSerialize(); + var bytes = Encoding.UTF8.GetBytes(json.ToString(Formatting.None)); + using var compressedStream = new MemoryStream(); + using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress)) + { + zipStream.WriteByte(Template.Version); + zipStream.Write(bytes, 0, bytes.Length); + } + + return Convert.ToBase64String(compressedStream.ToArray()); + } + + catch + { + return string.Empty; + } + } + // Decompress a base64 encoded string to the given type and a prepended version byte if possible. // On failure, data will be String error and version will be byte.MaxValue. // Original by Ottermandias: OtterGui <3 diff --git a/CustomizePlus/Templates/TemplateEditorManager.cs b/CustomizePlus/Templates/TemplateEditorManager.cs index 93888d7..fe13775 100644 --- a/CustomizePlus/Templates/TemplateEditorManager.cs +++ b/CustomizePlus/Templates/TemplateEditorManager.cs @@ -18,6 +18,7 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; +using System.Windows.Forms; namespace CustomizePlus.Templates; diff --git a/CustomizePlus/UI/Windows/MainWindow/Tabs/Profiles/ProfilePanel.cs b/CustomizePlus/UI/Windows/MainWindow/Tabs/Profiles/ProfilePanel.cs index 580ac3e..2f8c410 100644 --- a/CustomizePlus/UI/Windows/MainWindow/Tabs/Profiles/ProfilePanel.cs +++ b/CustomizePlus/UI/Windows/MainWindow/Tabs/Profiles/ProfilePanel.cs @@ -4,6 +4,8 @@ using OtterGui; using OtterGui.Raii; using OtterGui.Extensions; +using OtterGui.Log; +using OtterGui.Text; using System; using System.Linq; using System.Numerics; @@ -13,6 +15,7 @@ using CustomizePlus.UI.Windows.Controls; using CustomizePlus.Templates; using CustomizePlus.Core.Data; +using CustomizePlus.Core.Helpers; using CustomizePlus.Templates.Events; using Penumbra.GameData.Actors; using Penumbra.String; @@ -34,6 +37,8 @@ public class ProfilePanel private readonly ActorAssignmentUi _actorAssignmentUi; private readonly ActorManager _actorManager; private readonly TemplateEditorEvent _templateEditorEvent; + private readonly PopupSystem _popupSystem; + private readonly Logger _logger; private string? _newName; private int? _newPriority; @@ -54,7 +59,9 @@ public ProfilePanel( TemplateEditorManager templateEditorManager, ActorAssignmentUi actorAssignmentUi, ActorManager actorManager, - TemplateEditorEvent templateEditorEvent) + TemplateEditorEvent templateEditorEvent, + PopupSystem popupSystem, + Logger logger) { _selector = selector; _manager = manager; @@ -64,6 +71,8 @@ public ProfilePanel( _actorAssignmentUi = actorAssignmentUi; _actorManager = actorManager; _templateEditorEvent = templateEditorEvent; + _popupSystem = popupSystem; + _logger = logger; } public void Draw() @@ -97,9 +106,20 @@ private HeaderDrawer.Button LockButton() OnClick = () => _manager.SetWriteProtection(_selector.Selected!, true) }; + private HeaderDrawer.Button ExportToClipboardButton() + => _selector.Selected == null + ? HeaderDrawer.Button.Invisible + :new HeaderDrawer.Button { + Description = "Copy the current profile combined into one template to your clipboard.", + Icon = FontAwesomeIcon.Copy, + OnClick = ExportToClipboard, + Visible = _selector.Selected != null, + Disabled = false + }; + private void DrawHeader() => HeaderDrawer.Draw(SelectionName, 0, ImGui.GetColorU32(ImGuiCol.FrameBg), - 0, LockButton(), + 1, ExportToClipboardButton(), LockButton(), HeaderDrawer.Button.IncognitoButton(_selector.IncognitoMode, v => _selector.IncognitoMode = v)); private void DrawMultiSelection() @@ -248,6 +268,20 @@ private void DrawBasicSettings() } } + private void ExportToClipboard() + { + try + { + ImUtf8.SetClipboardText(Base64Helper.ExportProfileToBase64(_selector.Selected!)); + _popupSystem.ShowPopup(PopupSystem.Messages.ClipboardDataNotLongTerm); + } + catch (Exception ex) + { + _logger.Error($"Could not copy data from profile {_selector.Selected!.UniqueId} to clipboard: {ex}"); + _popupSystem.ShowPopup(PopupSystem.Messages.ActionError); + } + } + private void DrawAddCharactersArea() { using (var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0, 0.5f))) diff --git a/CustomizePlus/UI/Windows/MainWindow/Tabs/Templates/BoneEditorPanel.cs b/CustomizePlus/UI/Windows/MainWindow/Tabs/Templates/BoneEditorPanel.cs index 6be877e..2d65176 100644 --- a/CustomizePlus/UI/Windows/MainWindow/Tabs/Templates/BoneEditorPanel.cs +++ b/CustomizePlus/UI/Windows/MainWindow/Tabs/Templates/BoneEditorPanel.cs @@ -14,6 +14,7 @@ using OtterGui; using OtterGui.Log; using OtterGui.Raii; +using OtterGui.Text; using System; using System.Collections.Generic; using System.Linq; @@ -477,7 +478,7 @@ public void Draw() if (ImGui.MenuItem("Import Group")) { - var clipboardText = Clipboard.GetText(); + var clipboardText = ImUtf8.GetClipboardText(); if (!string.IsNullOrEmpty(clipboardText)) _pendingImportText = clipboardText; } @@ -504,7 +505,7 @@ public void Draw() { try { - Clipboard.SetText(_pendingClipboardText); + ImUtf8.SetClipboardText(_pendingClipboardText); _logger.Debug("copied to clipboard: " + _pendingClipboardText); } catch (Exception ex) @@ -525,7 +526,7 @@ private void DrawEditorConfirmationPopup() } var viewportSize = ImGui.GetWindowViewport().Size; - ImGui.SetNextWindowSize(new Vector2(viewportSize.X / 4, viewportSize.Y / 12)); + ImGui.SetNextWindowSize(new Vector2(viewportSize.X / 3, viewportSize.Y / 12)); ImGui.SetNextWindowPos(viewportSize / 2, ImGuiCond.Always, new Vector2(0.5f)); using var popup = ImRaii.Popup("SavePopup", ImGuiWindowFlags.Modal); if (!popup) diff --git a/CustomizePlus/UI/Windows/MainWindow/Tabs/Templates/TemplateFileSystemSelector.cs b/CustomizePlus/UI/Windows/MainWindow/Tabs/Templates/TemplateFileSystemSelector.cs index 17d94ce..b762e80 100644 --- a/CustomizePlus/UI/Windows/MainWindow/Tabs/Templates/TemplateFileSystemSelector.cs +++ b/CustomizePlus/UI/Windows/MainWindow/Tabs/Templates/TemplateFileSystemSelector.cs @@ -315,7 +315,7 @@ private void ClipboardImportButton(Vector2 size) try { - _clipboardText = ImGui.GetClipboardText(); + _clipboardText = ImUtf8.GetClipboardText(); ImGui.OpenPopup("##NewTemplate"); } catch diff --git a/CustomizePlus/UI/Windows/MainWindow/Tabs/Templates/TemplatePanel.cs b/CustomizePlus/UI/Windows/MainWindow/Tabs/Templates/TemplatePanel.cs index 76b80bf..7e1d8b1 100644 --- a/CustomizePlus/UI/Windows/MainWindow/Tabs/Templates/TemplatePanel.cs +++ b/CustomizePlus/UI/Windows/MainWindow/Tabs/Templates/TemplatePanel.cs @@ -3,10 +3,10 @@ using OtterGui; using OtterGui.Classes; using OtterGui.Raii; +using OtterGui.Text; using System; using System.Linq; using System.Numerics; -using System.Windows.Forms; using CustomizePlus.Core.Data; using CustomizePlus.Templates; using CustomizePlus.Configuration.Data; @@ -230,7 +230,7 @@ private void ExportToClipboard() { try { - Clipboard.SetText(Base64Helper.ExportTemplateToBase64(_selector.Selected!)); + ImUtf8.SetClipboardText(Base64Helper.ExportTemplateToBase64(_selector.Selected!)); _popupSystem.ShowPopup(PopupSystem.Messages.ClipboardDataNotLongTerm); } catch (Exception ex)