Current design state.

This commit is contained in:
Ottermandias 2026-02-16 14:50:25 +01:00
parent 4646fd57ab
commit 6f219b0929
7 changed files with 524 additions and 507 deletions

View file

@ -18,7 +18,7 @@ using Luna;
namespace Glamourer.Gui.Tabs.DesignTab;
public sealed class DesignFileSystemSelector : FileSystemSelector<Design, DesignFileSystemSelector.DesignState>
public sealed class DesignFileSystemSelector : FileSystemSelector<Design, DesignFileSystemSelector.DesignState>, IPanel
{
private readonly DesignManager _designManager;
private readonly DesignChanged _event;
@ -399,4 +399,7 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
}
#endregion
public ReadOnlySpan<byte> Id
=> "DesignSelector"u8;
}

View file

@ -0,0 +1,21 @@
using Luna;
namespace Glamourer.Gui.Tabs.DesignTab;
public sealed class DesignHeader : SplitButtonHeader
{
public DesignHeader(DesignSelection selection, IncognitoButton incognito)
{
RightButtons.AddButton(incognito, 50);
RightButtons.AddButton(new LockedButton(selection), 100);
}
private sealed class LockedButton(DesignSelection selection) : BaseIconButton<AwesomeIcon>
{
public override bool IsVisible
=> selection.Design is not null;
public override AwesomeIcon Icon
=> selection.Design!.WriteProtected() ? LunaStyle.LockedIcon : LunaStyle.UnlockedIcon;
}
}

View file

@ -24,10 +24,10 @@ using static Glamourer.Gui.Tabs.HeaderDrawer;
namespace Glamourer.Gui.Tabs.DesignTab;
public class DesignPanel
public class DesignPanel : IPanel
{
private readonly FileDialogManager _fileDialog = new();
private readonly DesignFileSystemSelector _selector;
private readonly DesignSelection _selection;
private readonly CustomizationDrawer _customizationDrawer;
private readonly DesignManager _manager;
private readonly ActorObjectManager _objects;
@ -47,8 +47,7 @@ public class DesignPanel
private readonly Button[] _rightButtons;
public DesignPanel(DesignFileSystemSelector selector,
CustomizationDrawer customizationDrawer,
public DesignPanel(CustomizationDrawer customizationDrawer,
DesignManager manager,
ActorObjectManager objects,
StateManager state,
@ -62,9 +61,8 @@ public class DesignPanel
CustomizeParameterDrawer parameterDrawer,
DesignLinkDrawer designLinkDrawer,
MaterialDrawer materials,
EditorHistory history)
EditorHistory history, DesignSelection selection)
{
_selector = selector;
_customizationDrawer = customizationDrawer;
_manager = manager;
_objects = objects;
@ -80,6 +78,7 @@ public class DesignPanel
_designLinkDrawer = designLinkDrawer;
_materials = materials;
_history = history;
_selection = selection;
_leftButtons =
[
new SetFromClipboardButton(this),
@ -99,7 +98,7 @@ public class DesignPanel
=> HeaderDrawer.Draw(SelectionName, 0, ImGuiColor.FrameBackground.Get().Color, _leftButtons, _rightButtons);
private string SelectionName
=> _selector.Selected == null ? "No Selection" : _config.Ephemeral.IncognitoMode ? _selector.Selected.Incognito : _selector.Selected.Name.Text;
=> _selection.Design == null ? "No Selection" : _config.Ephemeral.IncognitoMode ? _selection.Design.Incognito : _selection.Design.Name.Text;
private void DrawEquipment()
{
@ -109,22 +108,22 @@ public class DesignPanel
_equipmentDrawer.Prepare();
var usedAllStain = _equipmentDrawer.DrawAllStain(out var newAllStain, _selector.Selected!.WriteProtected());
var usedAllStain = _equipmentDrawer.DrawAllStain(out var newAllStain, _selection.Design!.WriteProtected());
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
var data = EquipDrawData.FromDesign(_manager, _selector.Selected!, slot);
var data = EquipDrawData.FromDesign(_manager, _selection.Design!, slot);
_equipmentDrawer.DrawEquip(data);
if (usedAllStain)
_manager.ChangeStains(_selector.Selected, slot, newAllStain);
_manager.ChangeStains(_selection.Design, slot, newAllStain);
}
var mainhand = EquipDrawData.FromDesign(_manager, _selector.Selected!, EquipSlot.MainHand);
var offhand = EquipDrawData.FromDesign(_manager, _selector.Selected!, EquipSlot.OffHand);
var mainhand = EquipDrawData.FromDesign(_manager, _selection.Design!, EquipSlot.MainHand);
var offhand = EquipDrawData.FromDesign(_manager, _selection.Design!, EquipSlot.OffHand);
_equipmentDrawer.DrawWeapons(mainhand, offhand, true);
foreach (var slot in BonusExtensions.AllFlags)
{
var data = BonusDrawData.FromDesign(_manager, _selector.Selected!, slot);
var data = BonusDrawData.FromDesign(_manager, _selection.Design!, slot);
_equipmentDrawer.DrawBonusItem(data);
}
@ -138,28 +137,28 @@ public class DesignPanel
{
using (var _ = ImRaii.Group())
{
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.HatState, _manager, _selector.Selected!));
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Head, _manager, _selector.Selected!));
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.HatState, _manager, _selection.Design!));
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Head, _manager, _selection.Design!));
}
Im.Line.Same();
using (var _ = ImRaii.Group())
{
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.VisorState, _manager, _selector.Selected!));
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Body, _manager, _selector.Selected!));
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.VisorState, _manager, _selection.Design!));
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Body, _manager, _selection.Design!));
}
Im.Line.Same();
using (var _ = ImRaii.Group())
{
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.WeaponState, _manager, _selector.Selected!));
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.OffHand, _manager, _selector.Selected!));
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.WeaponState, _manager, _selection.Design!));
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.OffHand, _manager, _selection.Design!));
}
Im.Line.Same();
using (var _ = ImRaii.Group())
{
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.EarState, _manager, _selector.Selected!));
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.EarState, _manager, _selection.Design!));
}
}
@ -169,25 +168,25 @@ public class DesignPanel
return;
var expand = _config.AutoExpandDesignPanel.HasFlag(DesignPanelFlag.Customization);
using var h = Im.Tree.HeaderId(_selector.Selected!.DesignData.ModelId is 0
using var h = Im.Tree.HeaderId(_selection.Design!.DesignData.ModelId is 0
? "Customization"
: $"Customization (Model Id #{_selector.Selected!.DesignData.ModelId})###Customization",
: $"Customization (Model Id #{_selection.Design!.DesignData.ModelId})###Customization",
expand ? TreeNodeFlags.DefaultOpen : TreeNodeFlags.None);
if (!h)
return;
if (_customizationDrawer.Draw(_selector.Selected!.DesignData.Customize, _selector.Selected.Application.Customize,
_selector.Selected!.WriteProtected(), false))
if (_customizationDrawer.Draw(_selection.Design!.DesignData.Customize, _selection.Design.Application.Customize,
_selection.Design!.WriteProtected(), false))
foreach (var idx in CustomizeIndex.Values)
{
var flag = idx.ToFlag();
var newValue = _customizationDrawer.ChangeApply.HasFlag(flag);
_manager.ChangeApplyCustomize(_selector.Selected, idx, newValue);
_manager.ChangeApplyCustomize(_selection.Design, idx, newValue);
if (_customizationDrawer.Changed.HasFlag(flag))
_manager.ChangeCustomize(_selector.Selected, idx, _customizationDrawer.Customize[idx]);
_manager.ChangeCustomize(_selection.Design, idx, _customizationDrawer.Customize[idx]);
}
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.Wetness, _manager, _selector.Selected!));
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.Wetness, _manager, _selection.Design!));
Im.Dummy(new Vector2(Im.Style.TextHeight / 2));
}
@ -197,7 +196,7 @@ public class DesignPanel
if (!h)
return;
_parameterDrawer.Draw(_manager, _selector.Selected!);
_parameterDrawer.Draw(_manager, _selection.Design!);
}
private void DrawMaterialValues()
@ -206,52 +205,52 @@ public class DesignPanel
if (!h)
return;
_materials.Draw(_selector.Selected!);
_materials.Draw(_selection.Design!);
}
private void DrawCustomizeApplication()
{
using var id = ImUtf8.PushId("Customizations"u8);
var set = _selector.Selected!.CustomizeSet;
var set = _selection.Design!.CustomizeSet;
var available = set.SettingAvailable | CustomizeFlag.Clan | CustomizeFlag.Gender | CustomizeFlag.BodyType;
var flags = _selector.Selected!.ApplyCustomizeExcludingBodyType == 0 ? 0 :
(_selector.Selected!.ApplyCustomize & available) == available ? 3 : 1;
var flags = _selection.Design!.ApplyCustomizeExcludingBodyType == 0 ? 0 :
(_selection.Design!.ApplyCustomize & available) == available ? 3 : 1;
if (ImGui.CheckboxFlags("Apply All Customizations", ref flags, 3))
{
var newFlags = flags == 3;
_manager.ChangeApplyCustomize(_selector.Selected!, CustomizeIndex.Clan, newFlags);
_manager.ChangeApplyCustomize(_selector.Selected!, CustomizeIndex.Gender, newFlags);
_manager.ChangeApplyCustomize(_selection.Design!, CustomizeIndex.Clan, newFlags);
_manager.ChangeApplyCustomize(_selection.Design!, CustomizeIndex.Gender, newFlags);
foreach (var index in CustomizationExtensions.AllBasic)
_manager.ChangeApplyCustomize(_selector.Selected!, index, newFlags);
_manager.ChangeApplyCustomize(_selection.Design!, index, newFlags);
}
var applyClan = _selector.Selected!.DoApplyCustomize(CustomizeIndex.Clan);
var applyClan = _selection.Design!.DoApplyCustomize(CustomizeIndex.Clan);
if (ImUtf8.Checkbox($"Apply {CustomizeIndex.Clan.ToNameU8()}", ref applyClan))
_manager.ChangeApplyCustomize(_selector.Selected!, CustomizeIndex.Clan, applyClan);
_manager.ChangeApplyCustomize(_selection.Design!, CustomizeIndex.Clan, applyClan);
var applyGender = _selector.Selected!.DoApplyCustomize(CustomizeIndex.Gender);
var applyGender = _selection.Design!.DoApplyCustomize(CustomizeIndex.Gender);
if (ImUtf8.Checkbox($"Apply {CustomizeIndex.Gender.ToNameU8()}", ref applyGender))
_manager.ChangeApplyCustomize(_selector.Selected!, CustomizeIndex.Gender, applyGender);
_manager.ChangeApplyCustomize(_selection.Design!, CustomizeIndex.Gender, applyGender);
foreach (var index in CustomizationExtensions.All.Where(set.IsAvailable))
{
var apply = _selector.Selected!.DoApplyCustomize(index);
var apply = _selection.Design!.DoApplyCustomize(index);
if (ImUtf8.Checkbox($"Apply {set.Option(index)}", ref apply))
_manager.ChangeApplyCustomize(_selector.Selected!, index, apply);
_manager.ChangeApplyCustomize(_selection.Design!, index, apply);
}
}
private void DrawCrestApplication()
{
using var id = ImUtf8.PushId("Crests"u8);
var flags = (uint)_selector.Selected!.Application.Crest;
var flags = (uint)_selection.Design!.Application.Crest;
var bigChange = ImGui.CheckboxFlags("Apply All Crests", ref flags, (uint)CrestExtensions.AllRelevant);
foreach (var flag in CrestExtensions.AllRelevantSet)
{
var apply = bigChange ? ((CrestFlag)flags & flag) == flag : _selector.Selected!.DoApplyCrest(flag);
var apply = bigChange ? ((CrestFlag)flags & flag) == flag : _selection.Design!.DoApplyCrest(flag);
if (ImUtf8.Checkbox($"Apply {flag.ToLabel()} Crest", ref apply) || bigChange)
_manager.ChangeApplyCrest(_selector.Selected!, flag, apply);
_manager.ChangeApplyCrest(_selection.Design!, flag, apply);
}
}
@ -261,7 +260,7 @@ public class DesignPanel
if (!h)
return;
using var disabled = Im.Disabled(_selector.Selected!.WriteProtected());
using var disabled = Im.Disabled(_selection.Design!.WriteProtected());
DrawAllButtons();
@ -279,22 +278,22 @@ public class DesignPanel
{
void ApplyEquip(string label, EquipFlag allFlags, bool stain, IEnumerable<EquipSlot> slots)
{
var flags = (uint)(allFlags & _selector.Selected!.Application.Equip);
var flags = (uint)(allFlags & _selection.Design!.Application.Equip);
using var id = ImUtf8.PushId(label);
var bigChange = ImGui.CheckboxFlags($"Apply All {label}", ref flags, (uint)allFlags);
if (stain)
foreach (var slot in slots)
{
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToStainFlag()) : _selector.Selected!.DoApplyStain(slot);
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToStainFlag()) : _selection.Design!.DoApplyStain(slot);
if (ImUtf8.Checkbox($"Apply {slot.ToName()} Dye", ref apply) || bigChange)
_manager.ChangeApplyStains(_selector.Selected!, slot, apply);
_manager.ChangeApplyStains(_selection.Design!, slot, apply);
}
else
foreach (var slot in slots)
{
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToFlag()) : _selector.Selected!.DoApplyEquip(slot);
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToFlag()) : _selection.Design!.DoApplyEquip(slot);
if (ImUtf8.Checkbox($"Apply {slot.ToName()}", ref apply) || bigChange)
_manager.ChangeApplyItem(_selector.Selected!, slot, apply);
_manager.ChangeApplyItem(_selection.Design!, slot, apply);
}
}
@ -379,8 +378,8 @@ public class DesignPanel
size,
!enabled))
{
_manager.ChangeApplyMulti(_selector.Selected!, true, true, true, false, true, true, false, true);
_manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.Wetness, false);
_manager.ChangeApplyMulti(_selection.Design!, true, true, true, false, true, true, false, true);
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.Wetness, false);
}
if (!enabled)
@ -390,7 +389,7 @@ public class DesignPanel
if (ImUtf8.ButtonEx("Disable Advanced"u8, "Disable all advanced dyes and customizations but keep everything else as is."u8,
size,
!enabled))
_manager.ChangeApplyMulti(_selector.Selected!, null, null, null, false, null, null, false, null);
_manager.ChangeApplyMulti(_selection.Design!, null, null, null, false, null, null, false, null);
if (!enabled)
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
@ -398,18 +397,18 @@ public class DesignPanel
if (equip is null && customize is null)
return;
_manager.ChangeApplyMulti(_selector.Selected!, equip, customize, equip, customize.HasValue && !customize.Value ? false : null, null,
_manager.ChangeApplyMulti(_selection.Design!, equip, customize, equip, customize.HasValue && !customize.Value ? false : null, null,
equip, equip, equip);
if (equip.HasValue)
{
_manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.HatState, equip.Value);
_manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.VisorState, equip.Value);
_manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.WeaponState, equip.Value);
_manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.EarState, equip.Value);
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.HatState, equip.Value);
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.VisorState, equip.Value);
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.WeaponState, equip.Value);
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.EarState, equip.Value);
}
if (customize.HasValue)
_manager.ChangeApplyMeta(_selector.Selected!, MetaIndex.Wetness, customize.Value);
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.Wetness, customize.Value);
}
private static readonly IReadOnlyList<string> MetaLabels =
@ -425,14 +424,14 @@ public class DesignPanel
{
using var id = ImUtf8.PushId("Meta");
const uint all = (uint)MetaExtensions.All;
var flags = (uint)_selector.Selected!.Application.Meta;
var flags = (uint)_selection.Design!.Application.Meta;
var bigChange = ImGui.CheckboxFlags("Apply All Meta Changes", ref flags, all);
foreach (var (index, label) in MetaExtensions.AllRelevant.Zip(MetaLabels))
{
var apply = bigChange ? ((MetaFlag)flags).HasFlag(index.ToFlag()) : _selector.Selected!.DoApplyMeta(index);
var apply = bigChange ? ((MetaFlag)flags).HasFlag(index.ToFlag()) : _selection.Design!.DoApplyMeta(index);
if (ImUtf8.Checkbox(label, ref apply) || bigChange)
_manager.ChangeApplyMeta(_selector.Selected!, index, apply);
_manager.ChangeApplyMeta(_selection.Design!, index, apply);
}
}
@ -444,13 +443,13 @@ public class DesignPanel
private void DrawBonusSlotApplication()
{
using var id = ImUtf8.PushId("Bonus"u8);
var flags = _selector.Selected!.Application.BonusItem;
var flags = _selection.Design!.Application.BonusItem;
var bigChange = BonusExtensions.AllFlags.Count > 1 && ImUtf8.Checkbox("Apply All Bonus Slots"u8, ref flags, BonusExtensions.All);
foreach (var (index, label) in BonusExtensions.AllFlags.Zip(BonusSlotLabels))
{
var apply = bigChange ? flags.HasFlag(index) : _selector.Selected!.DoApplyBonusItem(index);
var apply = bigChange ? flags.HasFlag(index) : _selection.Design!.DoApplyBonusItem(index);
if (ImUtf8.Checkbox(label, ref apply) || bigChange)
_manager.ChangeApplyBonusItem(_selector.Selected!, index, apply);
_manager.ChangeApplyBonusItem(_selection.Design!, index, apply);
}
}
@ -458,20 +457,23 @@ public class DesignPanel
private void DrawParameterApplication()
{
using var id = Im.Id.Push("Parameter"u8);
var flags = (ulong)_selector.Selected!.Application.Parameters;
var flags = (ulong)_selection.Design!.Application.Parameters;
var bigChange = Im.Checkbox("Apply All Customize Parameters"u8, ref flags, (ulong)CustomizeParameterExtensions.All);
foreach (var flag in CustomizeParameterExtensions.AllFlags)
{
var apply = bigChange ? ((CustomizeParameterFlag)flags).HasFlag(flag) : _selector.Selected!.DoApplyParameter(flag);
var apply = bigChange ? ((CustomizeParameterFlag)flags).HasFlag(flag) : _selection.Design!.DoApplyParameter(flag);
if (Im.Checkbox($"Apply {flag.ToNameU8()}", ref apply) || bigChange)
_manager.ChangeApplyParameter(_selector.Selected!, flag, apply);
_manager.ChangeApplyParameter(_selection.Design!, flag, apply);
}
}
public ReadOnlySpan<byte> Id
=> "Designs"u8;
public void Draw()
{
using var group = ImUtf8.Group();
if (_selector.SelectedPaths.Count > 1)
if (_selection.DesignPaths.Count > 1)
{
_multiDesignPanel.Draw();
}
@ -480,22 +482,22 @@ public class DesignPanel
DrawHeader();
DrawPanel();
if (_selector.Selected == null || _selector.Selected.WriteProtected())
if (_selection.Design == null || _selection.Design.WriteProtected())
return;
if (_importService.CreateDatTarget(out var dat))
{
_manager.ChangeCustomize(_selector.Selected!, CustomizeIndex.Clan, dat.Customize[CustomizeIndex.Clan]);
_manager.ChangeCustomize(_selector.Selected!, CustomizeIndex.Gender, dat.Customize[CustomizeIndex.Gender]);
_manager.ChangeCustomize(_selection.Design!, CustomizeIndex.Clan, dat.Customize[CustomizeIndex.Clan]);
_manager.ChangeCustomize(_selection.Design!, CustomizeIndex.Gender, dat.Customize[CustomizeIndex.Gender]);
foreach (var idx in CustomizationExtensions.AllBasic)
_manager.ChangeCustomize(_selector.Selected!, idx, dat.Customize[idx]);
_manager.ChangeCustomize(_selection.Design!, idx, dat.Customize[idx]);
Glamourer.Messager.NotificationMessage(
$"Applied games .dat file {dat.Description} customizations to {_selector.Selected.Name}.", NotificationType.Success, false);
$"Applied games .dat file {dat.Description} customizations to {_selection.Design.Name}.", NotificationType.Success, false);
}
else if (_importService.CreateCharaTarget(out var designBase, out var name))
{
_manager.ApplyDesign(_selector.Selected!, designBase);
Glamourer.Messager.NotificationMessage($"Applied Anamnesis .chara file {name} to {_selector.Selected.Name}.",
_manager.ApplyDesign(_selection.Design!, designBase);
Glamourer.Messager.NotificationMessage($"Applied Anamnesis .chara file {name} to {_selection.Design.Name}.",
NotificationType.Success, false);
}
}
@ -506,12 +508,12 @@ public class DesignPanel
private void DrawPanel()
{
using var table = Im.Table.Begin("##Panel"u8, 1, TableFlags.BordersOuter | TableFlags.ScrollY, Im.ContentRegion.Available);
if (!table || _selector.Selected is null)
if (!table || _selection.Design is null)
return;
ImGui.TableSetupScrollFreeze(0, 1);
ImGui.TableNextColumn();
if (_selector.Selected is null)
if (_selection.Design is null)
return;
Im.Dummy(Vector2.Zero);
@ -550,8 +552,8 @@ public class DesignPanel
if (_state.GetOrCreate(id, data.Objects[0], out var state))
{
using var _ = _selector.Selected!.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
_state.ApplyDesign(state, _selector.Selected!, ApplySettings.ManualWithLinks with { IsFinal = true });
using var _ = _selection.Design!.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
_state.ApplyDesign(state, _selection.Design!, ApplySettings.ManualWithLinks with { IsFinal = true });
}
}
@ -568,14 +570,14 @@ public class DesignPanel
if (_state.GetOrCreate(id, data.Objects[0], out var state))
{
using var _ = _selector.Selected!.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
_state.ApplyDesign(state, _selector.Selected!, ApplySettings.ManualWithLinks with { IsFinal = true });
using var _ = _selection.Design!.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
_state.ApplyDesign(state, _selection.Design!, ApplySettings.ManualWithLinks with { IsFinal = true });
}
}
private void DrawSaveToDat()
{
var verified = _importService.Verify(_selector.Selected!.DesignData.Customize, out _);
var verified = _importService.Verify(_selection.Design!.DesignData.Customize, out _);
var tt = verified
? "Export the currently configured customizations of this design to a character creation data file."
: "The current design contains customizations that can not be applied during character creation.";
@ -585,8 +587,8 @@ public class DesignPanel
if (ImGuiUtil.DrawDisabledButton("Export to Dat", Vector2.Zero, tt, !verified))
_fileDialog.SaveFileDialog("Save File...", ".dat", "FFXIV_CHARA_01.dat", ".dat", (v, path) =>
{
if (v && _selector.Selected != null)
_importService.SaveDesignAsDat(path, _selector.Selected!.DesignData.Customize, _selector.Selected!.Name);
if (v && _selection.Design != null)
_importService.SaveDesignAsDat(path, _selection.Design!.DesignData.Customize, _selection.Design!.Name);
}, startPath);
_fileDialog.Draw();
@ -595,163 +597,163 @@ public class DesignPanel
private static unsafe string GetUserPath()
=> Framework.Instance()->UserPathString;
}
private sealed class LockButton(DesignPanel panel) : Button
private sealed class LockButton(DesignPanel panel) : Button
{
public override bool Visible
=> panel._selection.Design != null;
protected override string Description
=> panel._selection.Design!.WriteProtected()
? "Make this design editable."
: "Write-protect this design.";
protected override FontAwesomeIcon Icon
=> panel._selection.Design!.WriteProtected()
? FontAwesomeIcon.Lock
: FontAwesomeIcon.LockOpen;
protected override void OnClick()
=> panel._manager.SetWriteProtection(panel._selection.Design!, !panel._selection.Design!.WriteProtected());
}
private sealed class SetFromClipboardButton(DesignPanel panel) : Button
{
public override bool Visible
=> panel._selection.Design != null;
protected override bool Disabled
=> panel._selection.Design?.WriteProtected() ?? true;
protected override string Description
=> "Try to apply a design from your clipboard over this design.\nHold Control to only apply gear.\nHold Shift to only apply customizations.";
protected override FontAwesomeIcon Icon
=> FontAwesomeIcon.Clipboard;
protected override void OnClick()
{
public override bool Visible
=> panel._selector.Selected != null;
protected override string Description
=> panel._selector.Selected!.WriteProtected()
? "Make this design editable."
: "Write-protect this design.";
protected override FontAwesomeIcon Icon
=> panel._selector.Selected!.WriteProtected()
? FontAwesomeIcon.Lock
: FontAwesomeIcon.LockOpen;
protected override void OnClick()
=> panel._manager.SetWriteProtection(panel._selector.Selected!, !panel._selector.Selected!.WriteProtected());
}
private sealed class SetFromClipboardButton(DesignPanel panel) : Button
{
public override bool Visible
=> panel._selector.Selected != null;
protected override bool Disabled
=> panel._selector.Selected?.WriteProtected() ?? true;
protected override string Description
=> "Try to apply a design from your clipboard over this design.\nHold Control to only apply gear.\nHold Shift to only apply customizations.";
protected override FontAwesomeIcon Icon
=> FontAwesomeIcon.Clipboard;
protected override void OnClick()
try
{
try
{
var text = ImGui.GetClipboardText();
var (applyEquip, applyCustomize) = UiHelpers.ConvertKeysToBool();
var design = panel._converter.FromBase64(text, applyCustomize, applyEquip, out _)
?? throw new Exception("The clipboard did not contain valid data.");
panel._manager.ApplyDesign(panel._selector.Selected!, design);
}
catch (Exception ex)
{
Glamourer.Messager.NotificationMessage(ex, $"Could not apply clipboard to {panel._selector.Selected!.Name}.",
$"Could not apply clipboard to design {panel._selector.Selected!.Identifier}", NotificationType.Error, false);
}
var text = ImGui.GetClipboardText();
var (applyEquip, applyCustomize) = UiHelpers.ConvertKeysToBool();
var design = panel._converter.FromBase64(text, applyCustomize, applyEquip, out _)
?? throw new Exception("The clipboard did not contain valid data.");
panel._manager.ApplyDesign(panel._selection.Design!, design);
}
}
private sealed class DesignUndoButton(DesignPanel panel) : Button
{
public override bool Visible
=> panel._selector.Selected != null;
protected override bool Disabled
=> !panel._manager.CanUndo(panel._selector.Selected) || (panel._selector.Selected?.WriteProtected() ?? true);
protected override string Description
=> "Undo the last time you applied an entire design onto this design, if you accidentally overwrote your design with a different one.";
protected override FontAwesomeIcon Icon
=> FontAwesomeIcon.SyncAlt;
protected override void OnClick()
catch (Exception ex)
{
try
{
panel._manager.UndoDesignChange(panel._selector.Selected!);
}
catch (Exception ex)
{
Glamourer.Messager.NotificationMessage(ex, $"Could not undo last changes to {panel._selector.Selected!.Name}.",
NotificationType.Error,
false);
}
Glamourer.Messager.NotificationMessage(ex, $"Could not apply clipboard to {panel._selection.Design!.Name}.",
$"Could not apply clipboard to design {panel._selection.Design!.Identifier}", NotificationType.Error, false);
}
}
private sealed class ExportToClipboardButton(DesignPanel panel) : Button
{
public override bool Visible
=> panel._selector.Selected != null;
protected override string Description
=> "Copy the current design to your clipboard.";
protected override FontAwesomeIcon Icon
=> FontAwesomeIcon.Copy;
protected override void OnClick()
{
try
{
var text = panel._converter.ShareBase64(panel._selector.Selected!);
ImGui.SetClipboardText(text);
}
catch (Exception ex)
{
Glamourer.Messager.NotificationMessage(ex, $"Could not copy {panel._selector.Selected!.Name} data to clipboard.",
$"Could not copy data from design {panel._selector.Selected!.Identifier} to clipboard", NotificationType.Error, false);
}
}
}
private sealed class ApplyCharacterButton(DesignPanel panel) : Button
{
public override bool Visible
=> panel._selector.Selected != null && panel._objects.Player.Valid;
protected override string Description
=> "Overwrite this design with your character's current state.";
protected override bool Disabled
=> panel._selector.Selected?.WriteProtected() ?? true;
protected override FontAwesomeIcon Icon
=> FontAwesomeIcon.UserEdit;
protected override void OnClick()
{
try
{
var (player, actor) = panel._objects.PlayerData;
if (!player.IsValid || !actor.Valid || !panel._state.GetOrCreate(player, actor.Objects[0], out var state))
throw new Exception("No player state available.");
var design = panel._converter.Convert(state, ApplicationRules.FromModifiers(state))
?? throw new Exception("The clipboard did not contain valid data.");
panel._selector.Selected!.GetMaterialDataRef().Clear();
panel._manager.ApplyDesign(panel._selector.Selected!, design);
}
catch (Exception ex)
{
Glamourer.Messager.NotificationMessage(ex, $"Could not apply player state to {panel._selector.Selected!.Name}.",
$"Could not apply player state to design {panel._selector.Selected!.Identifier}", NotificationType.Error, false);
}
}
}
private sealed class UndoButton(DesignPanel panel) : Button
{
protected override string Description
=> "Undo the last change.";
protected override FontAwesomeIcon Icon
=> FontAwesomeIcon.Undo;
public override bool Visible
=> panel._selector.Selected != null;
protected override bool Disabled
=> (panel._selector.Selected?.WriteProtected() ?? true) || !panel._history.CanUndo(panel._selector.Selected);
protected override void OnClick()
=> panel._history.Undo(panel._selector.Selected!);
}
}
private sealed class DesignUndoButton(DesignPanel panel) : Button
{
public override bool Visible
=> panel._selection.Design != null;
protected override bool Disabled
=> !panel._manager.CanUndo(panel._selection.Design) || (panel._selection.Design?.WriteProtected() ?? true);
protected override string Description
=> "Undo the last time you applied an entire design onto this design, if you accidentally overwrote your design with a different one.";
protected override FontAwesomeIcon Icon
=> FontAwesomeIcon.SyncAlt;
protected override void OnClick()
{
try
{
panel._manager.UndoDesignChange(panel._selection.Design!);
}
catch (Exception ex)
{
Glamourer.Messager.NotificationMessage(ex, $"Could not undo last changes to {panel._selection.Design!.Name}.",
NotificationType.Error,
false);
}
}
}
private sealed class ExportToClipboardButton(DesignPanel panel) : Button
{
public override bool Visible
=> panel._selection.Design != null;
protected override string Description
=> "Copy the current design to your clipboard.";
protected override FontAwesomeIcon Icon
=> FontAwesomeIcon.Copy;
protected override void OnClick()
{
try
{
var text = panel._converter.ShareBase64(panel._selection.Design!);
ImGui.SetClipboardText(text);
}
catch (Exception ex)
{
Glamourer.Messager.NotificationMessage(ex, $"Could not copy {panel._selection.Design!.Name} data to clipboard.",
$"Could not copy data from design {panel._selection.Design!.Identifier} to clipboard", NotificationType.Error, false);
}
}
}
private sealed class ApplyCharacterButton(DesignPanel panel) : Button
{
public override bool Visible
=> panel._selection.Design != null && panel._objects.Player.Valid;
protected override string Description
=> "Overwrite this design with your character's current state.";
protected override bool Disabled
=> panel._selection.Design?.WriteProtected() ?? true;
protected override FontAwesomeIcon Icon
=> FontAwesomeIcon.UserEdit;
protected override void OnClick()
{
try
{
var (player, actor) = panel._objects.PlayerData;
if (!player.IsValid || !actor.Valid || !panel._state.GetOrCreate(player, actor.Objects[0], out var state))
throw new Exception("No player state available.");
var design = panel._converter.Convert(state, ApplicationRules.FromModifiers(state))
?? throw new Exception("The clipboard did not contain valid data.");
panel._selection.Design!.GetMaterialDataRef().Clear();
panel._manager.ApplyDesign(panel._selection.Design!, design);
}
catch (Exception ex)
{
Glamourer.Messager.NotificationMessage(ex, $"Could not apply player state to {panel._selection.Design!.Name}.",
$"Could not apply player state to design {panel._selection.Design!.Identifier}", NotificationType.Error, false);
}
}
}
private sealed class UndoButton(DesignPanel panel) : Button
{
protected override string Description
=> "Undo the last change.";
protected override FontAwesomeIcon Icon
=> FontAwesomeIcon.Undo;
public override bool Visible
=> panel._selection.Design != null;
protected override bool Disabled
=> (panel._selection.Design?.WriteProtected() ?? true) || !panel._history.CanUndo(panel._selection.Design);
protected override void OnClick()
=> panel._history.Undo(panel._selection.Design!);
}

View file

@ -0,0 +1,12 @@
using Glamourer.Designs;
using Luna;
namespace Glamourer.Gui.Tabs.DesignTab;
public sealed class DesignSelection : IUiService, IDisposable
{
public Design? Design { get; private set; }
public void Dispose()
{ }
}

View file

@ -1,95 +1,107 @@
using Dalamud.Interface.Utility;
using Glamourer.Interop.Penumbra;
using Dalamud.Bindings.ImGui;
using Glamourer.Interop.Penumbra;
using ImSharp;
using OtterGui.Classes;
using OtterGui.Log;
using OtterGui.Raii;
using OtterGui.Text;
using OtterGui.Widgets;
using MouseWheelType = OtterGui.Widgets.MouseWheelType;
namespace Glamourer.Gui.Tabs.DesignTab;
public sealed class ModCombo : FilterComboCache<(Mod Mod, ModSettings Settings, int Count)>
public sealed class ModCombo(PenumbraService penumbra, DesignSelection selection) : ImSharp.FilterComboBase<ModCombo.CacheItem>(new ModFilter())
{
public ModCombo(PenumbraService penumbra, Logger log, DesignFileSystemSelector selector)
: base(() => penumbra.GetMods(selector.Selected?.FilteredItemNames.ToArray() ?? []), MouseWheelType.None, log)
=> SearchByParts = false;
protected override string ToString((Mod Mod, ModSettings Settings, int Count) obj)
=> obj.Mod.Name;
protected override bool IsVisible(int globalIndex, LowerString filter)
=> filter.IsContained(Items[globalIndex].Mod.Name) || filter.IsContained(Items[globalIndex].Mod.DirectoryName);
protected override bool DrawSelectable(int globalIdx, bool selected)
public readonly struct CacheItem(in Mod mod, in ModSettings settings, int count)
{
using var id = ImUtf8.PushId(globalIdx);
var (mod, settings, count) = Items[globalIdx];
bool ret;
var color = settings.Enabled
public readonly StringPair Name = new(mod.Name);
public readonly StringPair Directory = new(mod.DirectoryName);
public readonly ModSettings Settings = settings;
public readonly int Count = count;
public readonly Vector4 Color = settings.Enabled
? count > 0
? ColorId.ContainsItemsEnabled.Value()
: ImGuiColor.Text.Get()
? ColorId.ContainsItemsEnabled.Value().ToVector()
: Im.Style[ImGuiColor.Text]
: count > 0
? ColorId.ContainsItemsDisabled.Value()
: ImGuiColor.TextDisabled.Get();
using (ImGuiColor.Text.Push(color))
? ColorId.ContainsItemsDisabled.Value().ToVector()
: Im.Style[ImGuiColor.TextDisabled];
public readonly bool DifferingNames = string.Equals(mod.Name, mod.DirectoryName, StringComparison.CurrentCultureIgnoreCase);
}
protected override float ItemHeight
=> Im.Style.TextHeightWithSpacing;
protected override IEnumerable<CacheItem> GetItems()
=> penumbra.GetMods(selection.Design?.FilteredItemNames.ToArray() ?? []).Select(t => new CacheItem(t.Mod, t.Settings, t.Count));
protected override bool DrawItem(in CacheItem item, int globalIndex, bool selected)
{
bool ret;
using (ImGuiColor.Text.Push(item.Color))
{
ret = ImUtf8.Selectable(mod.Name, selected);
ret = Im.Selectable(item.Name.Utf8, selected);
}
if (ImGui.IsItemHovered())
{
using var style = ImRaii.PushStyle(ImGuiStyleVar.PopupBorderSize, 2 * Im.Style.GlobalScale);
using var tt = ImUtf8.Tooltip();
var namesDifferent = mod.Name != mod.DirectoryName;
Im.Dummy(new Vector2(300 * Im.Style.GlobalScale, 0));
using (ImUtf8.Group())
{
if (namesDifferent)
ImUtf8.Text("Directory Name"u8);
ImUtf8.Text("Enabled"u8);
ImUtf8.Text("Priority"u8);
ImUtf8.Text("Affected Design Items"u8);
DrawSettingsLeft(settings);
}
ImGui.SameLine(Math.Max(ImGui.GetItemRectSize().X + 3 * Im.Style.ItemSpacing.X, 150 * Im.Style.GlobalScale));
using (ImUtf8.Group())
{
if (namesDifferent)
ImUtf8.Text(mod.DirectoryName);
ImUtf8.Text($"{settings.Enabled}");
ImUtf8.Text($"{settings.Priority}");
ImUtf8.Text($"{count}");
DrawSettingsRight(settings);
}
}
if (Im.Item.Hovered())
DrawTooltip(item);
return ret;
}
public static void DrawSettingsLeft(ModSettings settings)
private static void DrawTooltip(in CacheItem item)
{
using var style = ImStyleSingle.PopupBorderThickness.Push(2 * Im.Style.GlobalScale);
using var tt = Im.Tooltip.Begin();
Im.Dummy(new Vector2(300 * Im.Style.GlobalScale, 0));
using (Im.Group())
{
if (item.DifferingNames)
Im.Text("Directory Name"u8);
Im.Text("Enabled"u8);
Im.Text("Priority"u8);
Im.Text("Affected Design Items"u8);
DrawSettingsLeft(item.Settings);
}
Im.Line.Same(Math.Max(Im.Item.Size.X + 3 * Im.Style.ItemSpacing.X, 150 * Im.Style.GlobalScale));
using (Im.Group())
{
if (item.DifferingNames)
Im.Text(item.Directory.Utf8);
Im.Text($"{item.Settings.Enabled}");
Im.Text($"{item.Settings.Priority}");
Im.Text($"{item.Count}");
DrawSettingsRight(item.Settings);
}
}
private static void DrawSettingsLeft(in ModSettings settings)
{
foreach (var setting in settings.Settings)
{
ImUtf8.Text(setting.Key);
Im.Text(setting.Key);
for (var i = 1; i < setting.Value.Count; ++i)
Im.Line.New();
}
}
public static void DrawSettingsRight(ModSettings settings)
private static void DrawSettingsRight(in ModSettings settings)
{
foreach (var setting in settings.Settings)
{
if (setting.Value.Count == 0)
ImUtf8.Text("<None Enabled>"u8);
Im.Text("<None Enabled>"u8);
else
foreach (var option in setting.Value)
ImUtf8.Text(option);
Im.Text(option);
}
}
protected override bool IsSelected(CacheItem item, int globalIndex)
=> throw new NotImplementedException();
private sealed class ModFilter : TextFilterBase<CacheItem>
{
public override bool WouldBeVisible(in CacheItem item, int globalIndex)
=> base.WouldBeVisible(in item, globalIndex) || WouldBeVisible(item.Directory.Utf16);
protected override string ToFilterString(in CacheItem item, int globalIndex)
=> item.Name.Utf16;
}
}

View file

@ -1,13 +1,7 @@
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Glamourer.Designs;
using Glamourer.Designs;
using Glamourer.Interop.Material;
using Dalamud.Bindings.ImGui;
using ImSharp;
using OtterGui.Extensions;
using OtterGui.Raii;
using OtterGui.Text;
using static Glamourer.Gui.Tabs.HeaderDrawer;
using Luna;
namespace Glamourer.Gui.Tabs.DesignTab;
@ -17,9 +11,6 @@ public class MultiDesignPanel(
DesignColors colors,
Configuration config)
{
private readonly Button[] _leftButtons = [];
private readonly Button[] _rightButtons = []; //[new IncognitoButton(config)];
private readonly DesignColorCombo _colorCombo = new(colors, true);
public void Draw()
@ -27,13 +18,8 @@ public class MultiDesignPanel(
if (selector.SelectedPaths.Count == 0)
return;
HeaderDrawer.Draw(string.Empty, 0, ImGuiColor.FrameBackground.Get().Color, _leftButtons, _rightButtons);
using var child = ImUtf8.Child("##MultiPanel"u8, default, true);
if (!child)
return;
var width = ImGuiHelpers.ScaledVector2(145, 0);
var treeNodePos = ImGui.GetCursorPos();
var width = ImEx.ScaledVectorX(145);
var treeNodePos = Im.Cursor.Position;
_numDesigns = DrawDesignList();
DrawCounts(treeNodePos);
var offset = DrawMultiTagger(width);
@ -49,18 +35,17 @@ public class MultiDesignPanel(
private void DrawCounts(Vector2 treeNodePos)
{
var startPos = ImGui.GetCursorPos();
var startPos = Im.Cursor.Position;
var numFolders = selector.SelectedPaths.Count - _numDesigns;
var text = (_numDesigns, numFolders) switch
Im.Cursor.Position = treeNodePos;
ImEx.TextRightAligned((_numDesigns, numFolders) switch
{
(0, 0) => string.Empty, // should not happen
(> 0, 0) => $"{_numDesigns} Designs",
(0, > 0) => $"{numFolders} Folders",
_ => $"{_numDesigns} Designs, {numFolders} Folders",
};
ImGui.SetCursorPos(treeNodePos);
ImUtf8.TextRightAligned(text);
ImGui.SetCursorPos(startPos);
(0, 0) => StringU8.Empty, // should not happen
( > 0, 0) => $"{_numDesigns} Designs",
(0, > 0) => $"{numFolders} Folders",
_ => $"{_numDesigns} Designs, {numFolders} Folders",
});
Im.Cursor.Position = startPos;
}
private void ResetCounts()
@ -127,14 +112,14 @@ public class MultiDesignPanel(
{
using var id = Im.Id.Push(i++);
var (icon, text) = path is DesignFileSystem.Leaf l
? (FontAwesomeIcon.FileCircleMinus, l.Value.Name.Text)
: (FontAwesomeIcon.FolderMinus, string.Empty);
ImGui.TableNextColumn();
if (ImUtf8.IconButton(icon, "Remove from selection."u8, sizeType))
? (LunaStyle.RemoveFileIcon, l.Value.Name.Text)
: (LunaStyle.RemoveFolderIcon, string.Empty);
table.NextColumn();
if (ImEx.Icon.Button(icon, "Remove from selection."u8, sizeType))
selector.RemovePathFromMultiSelection(path);
ImUtf8.DrawFrameColumn(text);
ImUtf8.DrawFrameColumn(fullName);
table.DrawFrameColumn(text);
table.DrawFrameColumn(fullName);
if (CountLeaves(path))
++numDesigns;
@ -159,36 +144,32 @@ public class MultiDesignPanel(
private float DrawMultiTagger(Vector2 width)
{
ImUtf8.TextFrameAligned("Multi Tagger:"u8);
ImEx.TextFrameAligned("Multi Tagger:"u8);
Im.Line.Same();
var offset = ImGui.GetItemRectSize().X + Im.Style.WindowPadding.X;
ImGui.SetNextItemWidth(Im.ContentRegion.Available.X - 2 * (width.X + Im.Style.ItemSpacing.X));
ImUtf8.InputText("##tag"u8, ref _tag, "Tag Name..."u8);
var offset = Im.Item.Size.X + Im.Style.WindowPadding.X;
Im.Item.SetNextWidth(Im.ContentRegion.Available.X - 2 * (width.X + Im.Style.ItemSpacing.X));
Im.Input.Text("##tag"u8, ref _tag, "Tag Name..."u8);
UpdateTagCache();
var label = _addDesigns.Count > 0
? $"Add to {_addDesigns.Count} Designs"
: "Add";
var tooltip = _addDesigns.Count == 0
? _tag.Length == 0
? "No tag specified."
: $"All designs selected already contain the tag \"{_tag}\"."
: $"Add the tag \"{_tag}\" to {_addDesigns.Count} designs as a local tag:\n\n\t{string.Join("\n\t", _addDesigns.Select(m => m.Name.Text))}";
Im.Line.Same();
if (ImUtf8.ButtonEx(label, tooltip, width, _addDesigns.Count == 0))
if (ImEx.Button(_addDesigns.Count > 0
? $"Add to {_addDesigns.Count} Designs"
: "Add"u8, width, _addDesigns.Count is 0
? _tag.Length is 0
? "No tag specified."u8
: $"All designs selected already contain the tag \"{_tag}\"."
: $"Add the tag \"{_tag}\" to {_addDesigns.Count} designs as a local tag:\n\n\t{StringU8.Join("\n\t"u8, _addDesigns.Select(m => m.Name.Text))}", _addDesigns.Count is 0))
foreach (var design in _addDesigns)
editor.AddTag(design, _tag);
label = _removeDesigns.Count > 0
? $"Remove from {_removeDesigns.Count} Designs"
: "Remove";
tooltip = _removeDesigns.Count == 0
? _tag.Length == 0
? "No tag specified."
: $"No selected design contains the tag \"{_tag}\" locally."
: $"Remove the local tag \"{_tag}\" from {_removeDesigns.Count} designs:\n\n\t{string.Join("\n\t", _removeDesigns.Select(m => m.Item1.Name.Text))}";
Im.Line.Same();
if (ImUtf8.ButtonEx(label, tooltip, width, _removeDesigns.Count == 0))
if (ImEx.Button(_removeDesigns.Count > 0
? $"Remove from {_removeDesigns.Count} Designs"
: "Remove", width, _removeDesigns.Count is 0
? _tag.Length is 0
? "No tag specified."u8
: $"No selected design contains the tag \"{_tag}\" locally."
: $"Remove the local tag \"{_tag}\" from {_removeDesigns.Count} designs:\n\n\t{string.Join("\n\t", _removeDesigns.Select(m => m.Item1.Name.Text))}", _removeDesigns.Count is 0))
foreach (var (design, index) in _removeDesigns)
editor.RemoveTag(design, index);
Im.Separator();
@ -197,24 +178,22 @@ public class MultiDesignPanel(
private void DrawMultiQuickDesignBar(float offset)
{
ImUtf8.TextFrameAligned("Multi QDB:"u8);
ImGui.SameLine(offset, Im.Style.ItemSpacing.X);
ImEx.TextFrameAligned("Multi QDB:"u8);
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
var diff = _numDesigns - _numQuickDesignEnabled;
var tt = diff == 0
? $"All {_numDesigns} selected designs are already displayed in the quick design bar."
: $"Display all {_numDesigns} selected designs in the quick design bar. Changes {diff} designs.";
if (ImUtf8.ButtonEx("Display Selected Designs in QDB"u8, tt, buttonWidth, diff == 0))
if (ImEx.Button("Display Selected Designs in QDB"u8, buttonWidth, diff is 0
? $"All {_numDesigns} selected designs are already displayed in the quick design bar."
: $"Display all {_numDesigns} selected designs in the quick design bar. Changes {diff} designs.", diff is 0))
{
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
editor.SetQuickDesign(design.Value, true);
}
Im.Line.Same();
tt = _numQuickDesignEnabled == 0
? $"All {_numDesigns} selected designs are already hidden in the quick design bar."
: $"Hide all {_numDesigns} selected designs in the quick design bar. Changes {_numQuickDesignEnabled} designs.";
if (ImUtf8.ButtonEx("Hide Selected Designs in QDB"u8, tt, buttonWidth, _numQuickDesignEnabled == 0))
if (ImEx.Button("Hide Selected Designs in QDB"u8, buttonWidth, _numQuickDesignEnabled is 0
? $"All {_numDesigns} selected designs are already hidden in the quick design bar."
: $"Hide all {_numDesigns} selected designs in the quick design bar. Changes {_numQuickDesignEnabled} designs.", _numQuickDesignEnabled is 0))
{
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
editor.SetQuickDesign(design.Value, false);
@ -225,22 +204,20 @@ public class MultiDesignPanel(
private void DrawMultiLock(float offset)
{
ImUtf8.TextFrameAligned("Multi Lock:"u8);
ImGui.SameLine(offset, Im.Style.ItemSpacing.X);
ImEx.TextFrameAligned("Multi Lock:"u8);
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
var diff = _numDesigns - _numDesignsLocked;
var tt = diff == 0
? $"All {_numDesigns} selected designs are already write protected."
: $"Write-protect all {_numDesigns} designs. Changes {diff} designs.";
if (ImUtf8.ButtonEx("Turn Write-Protected"u8, tt, buttonWidth, diff == 0))
if (ImEx.Button("Turn Write-Protected"u8, buttonWidth, diff is 0
? $"All {_numDesigns} selected designs are already write protected."
: $"Write-protect all {_numDesigns} designs. Changes {diff} designs.", diff is 0))
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
editor.SetWriteProtection(design.Value, true);
Im.Line.Same();
tt = _numDesignsLocked == 0
? $"None of the {_numDesigns} selected designs are write-protected."
: $"Remove the write protection of the {_numDesigns} selected designs. Changes {_numDesignsLocked} designs.";
if (ImUtf8.ButtonEx("Remove Write-Protection"u8, tt, buttonWidth, _numDesignsLocked == 0))
if (ImEx.Button("Remove Write-Protection"u8, buttonWidth, _numDesignsLocked is 0
? $"None of the {_numDesigns} selected designs are write-protected."
: $"Remove the write protection of the {_numDesigns} selected designs. Changes {_numDesignsLocked} designs.", _numDesignsLocked is 0))
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
editor.SetWriteProtection(design.Value, false);
Im.Separator();
@ -248,22 +225,20 @@ public class MultiDesignPanel(
private void DrawMultiResetSettings(float offset)
{
ImUtf8.TextFrameAligned("Settings:"u8);
ImGui.SameLine(offset, Im.Style.ItemSpacing.X);
ImEx.TextFrameAligned("Settings:"u8);
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
var diff = _numDesigns - _numDesignsResetSettings;
var tt = diff == 0
? $"All {_numDesigns} selected designs already reset temporary settings."
: $"Make all {_numDesigns} selected designs reset temporary settings. Changes {diff} designs.";
if (ImUtf8.ButtonEx("Set Reset Temp. Settings"u8, tt, buttonWidth, diff == 0))
if (ImEx.Button("Set Reset Temp. Settings"u8, buttonWidth, diff is 0
? $"All {_numDesigns} selected designs already reset temporary settings."
: $"Make all {_numDesigns} selected designs reset temporary settings. Changes {diff} designs.", diff is 0))
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
editor.ChangeResetTemporarySettings(design.Value, true);
Im.Line.Same();
tt = _numDesignsResetSettings == 0
? $"None of the {_numDesigns} selected designs reset temporary settings."
: $"Stop all {_numDesigns} selected designs from resetting temporary settings. Changes {_numDesignsResetSettings} designs.";
if (ImUtf8.ButtonEx("Remove Reset Temp. Settings"u8, tt, buttonWidth, _numDesignsResetSettings == 0))
if (ImEx.Button("Remove Reset Temp. Settings"u8, buttonWidth, _numDesignsResetSettings is 0
? $"None of the {_numDesigns} selected designs reset temporary settings."
: $"Stop all {_numDesigns} selected designs from resetting temporary settings. Changes {_numDesignsResetSettings} designs.", _numDesignsResetSettings is 0))
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
editor.ChangeResetTemporarySettings(design.Value, false);
Im.Separator();
@ -271,22 +246,20 @@ public class MultiDesignPanel(
private void DrawMultiResetDyes(float offset)
{
ImUtf8.TextFrameAligned("Adv. Dyes:"u8);
ImGui.SameLine(offset, Im.Style.ItemSpacing.X);
ImEx.TextFrameAligned("Adv. Dyes:"u8);
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
var diff = _numDesigns - _numDesignsResetDyes;
var tt = diff == 0
? $"All {_numDesigns} selected designs already reset advanced dyes."
: $"Make all {_numDesigns} selected designs reset advanced dyes. Changes {diff} designs.";
if (ImUtf8.ButtonEx("Set Reset Dyes"u8, tt, buttonWidth, diff == 0))
if (ImEx.Button("Set Reset Dyes"u8, buttonWidth, diff is 0
? $"All {_numDesigns} selected designs already reset advanced dyes."
: $"Make all {_numDesigns} selected designs reset advanced dyes. Changes {diff} designs.", diff is 0))
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
editor.ChangeResetAdvancedDyes(design.Value, true);
Im.Line.Same();
tt = _numDesignsLocked == 0
? $"None of the {_numDesigns} selected designs reset advanced dyes."
: $"Stop all {_numDesigns} selected designs from resetting advanced dyes. Changes {_numDesignsResetDyes} designs.";
if (ImUtf8.ButtonEx("Remove Reset Dyes"u8, tt, buttonWidth, _numDesignsResetDyes == 0))
if (ImEx.Button("Remove Reset Dyes"u8, buttonWidth, _numDesignsLocked is 0
? $"None of the {_numDesigns} selected designs reset advanced dyes."
: $"Stop all {_numDesigns} selected designs from resetting advanced dyes. Changes {_numDesignsResetDyes} designs.", _numDesignsResetDyes is 0))
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
editor.ChangeResetAdvancedDyes(design.Value, false);
Im.Separator();
@ -294,22 +267,20 @@ public class MultiDesignPanel(
private void DrawMultiForceRedraw(float offset)
{
ImUtf8.TextFrameAligned("Redrawing:"u8);
ImGui.SameLine(offset, Im.Style.ItemSpacing.X);
ImEx.TextFrameAligned("Redrawing:"u8);
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
var diff = _numDesigns - _numDesignsForcedRedraw;
var tt = diff == 0
? $"All {_numDesigns} selected designs already force redraws."
: $"Make all {_numDesigns} designs force redraws. Changes {diff} designs.";
if (ImUtf8.ButtonEx("Force Redraws"u8, tt, buttonWidth, diff == 0))
if (ImEx.Button("Force Redraws"u8, buttonWidth, diff is 0
? $"All {_numDesigns} selected designs already force redraws."
: $"Make all {_numDesigns} designs force redraws. Changes {diff} designs.", diff is 0))
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
editor.ChangeForcedRedraw(design.Value, true);
Im.Line.Same();
tt = _numDesignsLocked == 0
? $"None of the {_numDesigns} selected designs force redraws."
: $"Stop all {_numDesigns} selected designs from forcing redraws. Changes {_numDesignsForcedRedraw} designs.";
if (ImUtf8.ButtonEx("Remove Forced Redraws"u8, tt, buttonWidth, _numDesignsForcedRedraw == 0))
if (ImEx.Button("Remove Forced Redraws"u8, buttonWidth, _numDesignsLocked is 0
? $"None of the {_numDesigns} selected designs force redraws."
: $"Stop all {_numDesigns} selected designs from forcing redraws. Changes {_numDesignsForcedRedraw} designs.", _numDesignsForcedRedraw is 0))
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
editor.ChangeForcedRedraw(design.Value, false);
Im.Separator();
@ -319,39 +290,35 @@ public class MultiDesignPanel(
private void DrawMultiColor(Vector2 width, float offset)
{
ImUtf8.TextFrameAligned("Multi Colors:"u8);
ImGui.SameLine(offset, Im.Style.ItemSpacing.X);
ImEx.TextFrameAligned("Multi Colors:"u8);
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
if (_colorCombo.Draw("##color"u8, _colorComboSelection, "Select a design color."u8,
Im.ContentRegion.Available.X - 2 * (width.X + Im.Style.ItemSpacing.X), out var newSelection))
_colorComboSelection = newSelection;
UpdateColorCache();
var label = _addDesigns.Count > 0
? $"Set for {_addDesigns.Count} Designs"
: "Set";
var tooltip = _addDesigns.Count is 0
? _colorComboSelection switch
{
null => "No color specified.",
DesignColors.AutomaticName => "Use the other button to set to automatic.",
_ => $"All designs selected are already set to the color \"{_colorComboSelection}\".",
}
: $"Set the color of {_addDesigns.Count} designs to \"{_colorComboSelection}\"\n\n\t{string.Join("\n\t", _addDesigns.Select(m => m.Name.Text))}";
Im.Line.Same();
if (ImEx.Button(label, width, tooltip, _addDesigns.Count is 0))
if (ImEx.Button(_addDesigns.Count > 0
? $"Set for {_addDesigns.Count} Designs"
: "Set"u8, width, _addDesigns.Count is 0
? _colorComboSelection switch
{
null => "No color specified."u8,
DesignColors.AutomaticName => "Use the other button to set to automatic."u8,
_ => $"All designs selected are already set to the color \"{_colorComboSelection}\".",
}
: $"Set the color of {_addDesigns.Count} designs to \"{_colorComboSelection}\"\n\n\t{StringU8.Join("\n\t"u8, _addDesigns.Select(m => m.Name.Text))}", _addDesigns.Count is 0))
{
foreach (var design in _addDesigns)
editor.ChangeColor(design, _colorComboSelection!);
}
label = _removeDesigns.Count > 0
? $"Unset {_removeDesigns.Count} Designs"
: "Unset";
tooltip = _removeDesigns.Count == 0
? "No selected design is set to a non-automatic color."
: $"Set {_removeDesigns.Count} designs to use automatic color again:\n\n\t{string.Join("\n\t", _removeDesigns.Select(m => m.Item1.Name.Text))}";
Im.Line.Same();
if (ImEx.Button(label, width, tooltip, _removeDesigns.Count is 0))
if (ImEx.Button(_removeDesigns.Count > 0
? $"Unset {_removeDesigns.Count} Designs"
: "Unset"u8, width, _removeDesigns.Count is 0
? "No selected design is set to a non-automatic color."u8
: $"Set {_removeDesigns.Count} designs to use automatic color again:\n\n\t{StringU8.Join("\n\t"u8, _removeDesigns.Select(m => m.Item1.Name.Text))}", _removeDesigns.Count is 0))
{
foreach (var (design, _) in _removeDesigns)
editor.ChangeColor(design, string.Empty);
@ -362,13 +329,12 @@ public class MultiDesignPanel(
private void DrawAdvancedButtons(float offset)
{
ImUtf8.TextFrameAligned("Delete Adv."u8);
ImGui.SameLine(offset, Im.Style.ItemSpacing.X);
ImEx.TextFrameAligned("Delete Adv."u8);
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
var enabled = config.DeleteDesignModifier.IsActive();
var tt = _numDesignsWithAdvancedDyes is 0
? "No selected designs contain any advanced dyes."
: $"Delete {_numAdvancedDyes} advanced dyes from {_numDesignsWithAdvancedDyes} of the selected designs.";
if (ImUtf8.ButtonEx("Delete All Advanced Dyes"u8, tt, new Vector2(Im.ContentRegion.Available.X, 0),
if (ImEx.Button("Delete All Advanced Dyes"u8, Im.ContentRegion.Available with { Y = 0 }, _numDesignsWithAdvancedDyes is 0
? "No selected designs contain any advanced dyes."u8
: $"Delete {_numAdvancedDyes} advanced dyes from {_numDesignsWithAdvancedDyes} of the selected designs.",
!enabled || _numDesignsWithAdvancedDyes is 0))
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
@ -378,93 +344,94 @@ public class MultiDesignPanel(
}
if (!enabled && _numDesignsWithAdvancedDyes is not 0)
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking to delete.");
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking to delete.");
Im.Separator();
}
private void DrawApplicationButtons(float offset)
{
ImUtf8.TextFrameAligned("Application"u8);
ImGui.SameLine(offset, Im.Style.ItemSpacing.X);
ImEx.TextFrameAligned("Application"u8);
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
var width = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
var enabled = config.DeleteDesignModifier.IsActive();
bool? equip = null;
bool? customize = null;
var group = ImUtf8.Group();
if (ImUtf8.ButtonEx("Disable Everything"u8,
_numDesigns > 0
? $"Disable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness for all {_numDesigns} designs."
: "No designs selected.", width, !enabled))
using (Im.Group())
{
equip = false;
customize = false;
}
if (!enabled)
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
Im.Line.Same();
if (ImUtf8.ButtonEx("Enable Everything"u8,
_numDesigns > 0
? $"Enable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness for all {_numDesigns} designs."
: "No designs selected.", width, !enabled))
{
equip = true;
customize = true;
}
if (!enabled)
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
if (ImUtf8.ButtonEx("Equipment Only"u8,
_numDesigns > 0
? $"Enable application of anything related to gear, disable anything that is not related to gear for all {_numDesigns} designs."
: "No designs selected.", width, !enabled))
{
equip = true;
customize = false;
}
if (!enabled)
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
Im.Line.Same();
if (ImUtf8.ButtonEx("Customization Only"u8,
_numDesigns > 0
? $"Enable application of anything related to customization, disable anything that is not related to customization for all {_numDesigns} designs."
: "No designs selected.", width, !enabled))
{
equip = false;
customize = true;
}
if (!enabled)
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
if (ImUtf8.ButtonEx("Default Application"u8,
_numDesigns > 0
? $"Set the application rules to the default values as if the {_numDesigns} were newly created,without any advanced features or wetness."
: "No designs selected.", width, !enabled))
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>().Select(l => l.Value))
if (ImEx.Button("Disable Everything"u8, width,
_numDesigns > 0
? $"Disable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness for all {_numDesigns} designs."
: "No designs selected."u8, !enabled))
{
editor.ChangeApplyMulti(design, true, true, true, false, true, true, false, true);
editor.ChangeApplyMeta(design, MetaIndex.Wetness, false);
equip = false;
customize = false;
}
if (!enabled)
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
if (!enabled)
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
Im.Line.Same();
if (ImUtf8.ButtonEx("Disable Advanced"u8, _numDesigns > 0
? $"Disable all advanced dyes and customizations but keep everything else as is for all {_numDesigns} designs."
: "No designs selected.", width, !enabled))
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>().Select(l => l.Value))
editor.ChangeApplyMulti(design, null, null, null, false, null, null, false, null);
Im.Line.Same();
if (ImEx.Button("Enable Everything"u8, width,
_numDesigns > 0
? $"Enable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness for all {_numDesigns} designs."
: "No designs selected."u8, !enabled))
{
equip = true;
customize = true;
}
if (!enabled)
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
if (!enabled)
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
if (ImEx.Button("Equipment Only"u8, width,
_numDesigns > 0
? $"Enable application of anything related to gear, disable anything that is not related to gear for all {_numDesigns} designs."
: "No designs selected."u8, !enabled))
{
equip = true;
customize = false;
}
if (!enabled)
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
Im.Line.Same();
if (ImEx.Button("Customization Only"u8, width,
_numDesigns > 0
? $"Enable application of anything related to customization, disable anything that is not related to customization for all {_numDesigns} designs."
: "No designs selected."u8, !enabled))
{
equip = false;
customize = true;
}
if (!enabled)
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
if (ImEx.Button("Default Application"u8, width,
_numDesigns > 0
? $"Set the application rules to the default values as if the {_numDesigns} were newly created,without any advanced features or wetness."
: "No designs selected."u8, !enabled))
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>().Select(l => l.Value))
{
editor.ChangeApplyMulti(design, true, true, true, false, true, true, false, true);
editor.ChangeApplyMeta(design, MetaIndex.Wetness, false);
}
if (!enabled)
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
Im.Line.Same();
if (ImEx.Button("Disable Advanced"u8, width, _numDesigns > 0
? $"Disable all advanced dyes and customizations but keep everything else as is for all {_numDesigns} designs."
: "No designs selected."u8, !enabled))
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>().Select(l => l.Value))
editor.ChangeApplyMulti(design, null, null, null, false, null, null, false, null);
if (!enabled)
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
}
group.Dispose();
Im.Separator();
if (equip is null && customize is null)
return;
@ -489,7 +456,7 @@ public class MultiDesignPanel(
{
_addDesigns.Clear();
_removeDesigns.Clear();
if (_tag.Length == 0)
if (_tag.Length is 0)
return;
foreach (var leaf in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())

2
Luna

@ -1 +1 @@
Subproject commit e80bdf5c10c6c30efccdff7d1adcb4a638eba4df
Subproject commit 0ee15af5c45b6c72df25b972e48b9a57347c25a5