mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-02-23 16:07:44 +01:00
Finalize unlockstable, update design combos, add events for favorites, minor fixes.
This commit is contained in:
parent
a04042d6e8
commit
f54ac8b0e5
15 changed files with 817 additions and 837 deletions
|
|
@ -1,6 +1,5 @@
|
||||||
using Luna.Generators;
|
using Luna.Generators;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
|
||||||
|
|
||||||
namespace Glamourer;
|
namespace Glamourer;
|
||||||
|
|
||||||
|
|
@ -41,8 +40,8 @@ public enum DesignPanelFlag : uint
|
||||||
|
|
||||||
public static partial class DesignPanelFlagExtensions
|
public static partial class DesignPanelFlagExtensions
|
||||||
{
|
{
|
||||||
private static readonly SizedString Expand = new("Expand"u8);
|
private static readonly StringU8 Expand = new("Expand"u8);
|
||||||
private static readonly SizedString AdvancedCustomization = new(DesignPanelFlag.AdvancedCustomizations.ToNameU8());
|
private static readonly StringU8 AdvancedCustomization = DesignPanelFlag.AdvancedCustomizations.ToNameU8();
|
||||||
|
|
||||||
public static Im.HeaderDisposable Header(this DesignPanelFlag flag, Configuration config)
|
public static Im.HeaderDisposable Header(this DesignPanelFlag flag, Configuration config)
|
||||||
{
|
{
|
||||||
|
|
@ -56,8 +55,8 @@ public static partial class DesignPanelFlagExtensions
|
||||||
public static void DrawTable(ReadOnlySpan<byte> label, DesignPanelFlag hidden, DesignPanelFlag expanded, Action<DesignPanelFlag> setterHide,
|
public static void DrawTable(ReadOnlySpan<byte> label, DesignPanelFlag hidden, DesignPanelFlag expanded, Action<DesignPanelFlag> setterHide,
|
||||||
Action<DesignPanelFlag> setterExpand)
|
Action<DesignPanelFlag> setterExpand)
|
||||||
{
|
{
|
||||||
var checkBoxWidth = Math.Max(Im.Style.FrameHeight, Expand.Size.X);
|
var checkBoxWidth = Math.Max(Im.Style.FrameHeight, Expand.CalculateSize().X);
|
||||||
var textWidth = AdvancedCustomization.Size.X;
|
var textWidth = AdvancedCustomization.CalculateSize().X;
|
||||||
var tableSize = 2 * (textWidth + 2 * checkBoxWidth)
|
var tableSize = 2 * (textWidth + 2 * checkBoxWidth)
|
||||||
+ 10 * Im.Style.CellPadding.X
|
+ 10 * Im.Style.CellPadding.X
|
||||||
+ 2 * Im.Style.WindowPadding.X
|
+ 2 * Im.Style.WindowPadding.X
|
||||||
|
|
|
||||||
|
|
@ -20,18 +20,18 @@ public class QuickSelectedDesign(QuickDesignCombo combo) : IDesignStandIn, IServ
|
||||||
=> ResolvedName;
|
=> ResolvedName;
|
||||||
|
|
||||||
public Design? CurrentDesign
|
public Design? CurrentDesign
|
||||||
=> combo.Design as Design;
|
=> combo.QuickDesign as Design;
|
||||||
|
|
||||||
public ref readonly DesignData GetDesignData(in DesignData baseRef)
|
public ref readonly DesignData GetDesignData(in DesignData baseRef)
|
||||||
{
|
{
|
||||||
if (combo.Design != null)
|
if (combo.QuickDesign is not null)
|
||||||
return ref combo.Design.GetDesignData(baseRef);
|
return ref combo.QuickDesign.GetDesignData(baseRef);
|
||||||
|
|
||||||
return ref baseRef;
|
return ref baseRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<(uint, MaterialValueDesign)> GetMaterialData()
|
public IReadOnlyList<(uint, MaterialValueDesign)> GetMaterialData()
|
||||||
=> combo.Design?.GetMaterialData() ?? [];
|
=> combo.QuickDesign?.GetMaterialData() ?? [];
|
||||||
|
|
||||||
public string SerializeName()
|
public string SerializeName()
|
||||||
=> SerializedName;
|
=> SerializedName;
|
||||||
|
|
@ -40,7 +40,7 @@ public class QuickSelectedDesign(QuickDesignCombo combo) : IDesignStandIn, IServ
|
||||||
=> StateSource.Manual;
|
=> StateSource.Manual;
|
||||||
|
|
||||||
public IEnumerable<(IDesignStandIn Design, ApplicationType Flags, JobFlag Jobs)> AllLinks(bool newApplication)
|
public IEnumerable<(IDesignStandIn Design, ApplicationType Flags, JobFlag Jobs)> AllLinks(bool newApplication)
|
||||||
=> combo.Design?.AllLinks(newApplication) ?? [];
|
=> combo.QuickDesign?.AllLinks(newApplication) ?? [];
|
||||||
|
|
||||||
public void AddData(JObject jObj)
|
public void AddData(JObject jObj)
|
||||||
{ }
|
{ }
|
||||||
|
|
@ -52,11 +52,11 @@ public class QuickSelectedDesign(QuickDesignCombo combo) : IDesignStandIn, IServ
|
||||||
=> false;
|
=> false;
|
||||||
|
|
||||||
public bool ForcedRedraw
|
public bool ForcedRedraw
|
||||||
=> combo.Design?.ForcedRedraw ?? false;
|
=> combo.QuickDesign?.ForcedRedraw ?? false;
|
||||||
|
|
||||||
public bool ResetAdvancedDyes
|
public bool ResetAdvancedDyes
|
||||||
=> combo.Design?.ResetAdvancedDyes ?? false;
|
=> combo.QuickDesign?.ResetAdvancedDyes ?? false;
|
||||||
|
|
||||||
public bool ResetTemporarySettings
|
public bool ResetTemporarySettings
|
||||||
=> combo.Design?.ResetTemporarySettings ?? false;
|
=> combo.QuickDesign?.ResetTemporarySettings ?? false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,427 +1,383 @@
|
||||||
using Dalamud.Interface.Utility.Raii;
|
using Glamourer.Automation;
|
||||||
using Glamourer.Automation;
|
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Designs.History;
|
using Glamourer.Designs.History;
|
||||||
using Glamourer.Designs.Special;
|
using Glamourer.Designs.Special;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using Dalamud.Bindings.ImGui;
|
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using OtterGui;
|
using Luna;
|
||||||
using OtterGui.Classes;
|
|
||||||
using OtterGui.Extensions;
|
|
||||||
using OtterGui.Log;
|
|
||||||
using OtterGui.Widgets;
|
|
||||||
using MouseWheelType = OtterGui.Widgets.MouseWheelType;
|
|
||||||
|
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
//public abstract class DesignComboBase2 : ImSharp.FilterComboBase<DesignComboBase2.CacheItem>, IDisposable
|
public abstract class DesignComboBase(
|
||||||
//{
|
EphemeralConfig config,
|
||||||
// protected readonly EphemeralConfig Config;
|
DesignManager designs,
|
||||||
// protected readonly DesignChanged DesignChanged;
|
DesignChanged designChanged,
|
||||||
// protected readonly DesignColors DesignColors;
|
DesignColors designColors,
|
||||||
// protected readonly TabSelected TabSelected;
|
TabSelected tabSelected,
|
||||||
// protected IDesignStandIn? _currentDesign;
|
DesignFileSystem designFileSystem)
|
||||||
//
|
: FilterComboBase<DesignComboBase.CacheItem>(new DesignFilter(), ConfigData.Default with { ComputeWidth = true })
|
||||||
// private CacheItem CreateItem(IDesignStandIn design)
|
|
||||||
// {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public readonly struct CacheItem(IDesignStandIn design, Vector4 color)
|
|
||||||
// {
|
|
||||||
// public readonly IDesignStandIn Design = design;
|
|
||||||
// public readonly StringPair Name = new(design.ResolveName(false));
|
|
||||||
// public readonly StringPair Incognito = new(design.ResolveName(true));
|
|
||||||
// public readonly StringPair FullPath = StringPair.Empty;
|
|
||||||
// public readonly Vector4 Color = color;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public DesignComboBase2(EphemeralConfig config, DesignChanged designChanged, DesignColors designColors, TabSelected tabSelected)
|
|
||||||
// {
|
|
||||||
// Config = config;
|
|
||||||
// DesignChanged = designChanged;
|
|
||||||
// DesignColors = designColors;
|
|
||||||
// TabSelected = tabSelected;
|
|
||||||
//
|
|
||||||
// DesignChanged.Subscribe(OnDesignChanged, DesignChanged.Priority.DesignCombo);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private void OnDesignChanged(DesignChanged.Type type, Design? _1, ITransaction? _2 = null)
|
|
||||||
// {
|
|
||||||
// _isCurrentSelectionDirty = type switch
|
|
||||||
// {
|
|
||||||
// DesignChanged.Type.Created => true,
|
|
||||||
// DesignChanged.Type.Renamed => true,
|
|
||||||
// DesignChanged.Type.ChangedColor => true,
|
|
||||||
// DesignChanged.Type.Deleted => true,
|
|
||||||
// DesignChanged.Type.QuickDesignBar => true,
|
|
||||||
// _ => _isCurrentSelectionDirty,
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// protected override bool DrawItem(in CacheItem item, int globalIndex, bool selected)
|
|
||||||
// {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void Dispose()
|
|
||||||
// {
|
|
||||||
// DesignChanged.Unsubscribe(OnDesignChanged);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
public abstract class DesignComboBase : FilterComboCache<Tuple<IDesignStandIn, string>>, IDisposable
|
|
||||||
{
|
{
|
||||||
protected readonly EphemeralConfig Config;
|
protected readonly EphemeralConfig Config = config;
|
||||||
protected readonly DesignChanged DesignChanged;
|
protected readonly DesignChanged DesignChanged = designChanged;
|
||||||
protected readonly DesignColors DesignColors;
|
protected readonly DesignColors DesignColors = designColors;
|
||||||
protected readonly TabSelected TabSelected;
|
protected readonly DesignFileSystem DesignFileSystem = designFileSystem;
|
||||||
protected float InnerWidth;
|
protected readonly TabSelected TabSelected = tabSelected;
|
||||||
private IDesignStandIn? _currentDesign;
|
protected readonly DesignManager Designs = designs;
|
||||||
private bool _isCurrentSelectionDirty;
|
protected IDesignStandIn? CurrentDesign;
|
||||||
|
|
||||||
protected DesignComboBase(Func<IReadOnlyList<Tuple<IDesignStandIn, string>>> generator, Logger log, DesignChanged designChanged,
|
protected CacheItem CreateItem(IDesignStandIn design)
|
||||||
TabSelected tabSelected, EphemeralConfig config, DesignColors designColors)
|
|
||||||
: base(generator, MouseWheelType.Control, log)
|
|
||||||
{
|
{
|
||||||
DesignChanged = designChanged;
|
var color = design is Design d1 ? DesignColors.GetColor(d1).ToVector() : ColorId.NormalDesign.Value().ToVector();
|
||||||
TabSelected = tabSelected;
|
var path = design is Design d2 && DesignFileSystem.TryGetValue(d2, out var leaf) ? leaf.FullName() : string.Empty;
|
||||||
Config = config;
|
var name = design.ResolveName(false);
|
||||||
DesignColors = designColors;
|
if (path == name)
|
||||||
DesignChanged.Subscribe(OnDesignChanged, DesignChanged.Priority.DesignCombo);
|
path = string.Empty;
|
||||||
|
return new CacheItem(design, color, path, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IDisposable.Dispose()
|
protected override bool IsSelected(CacheItem item, int globalIndex)
|
||||||
{
|
=> item.Design == CurrentDesign;
|
||||||
DesignChanged.Unsubscribe(OnDesignChanged);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool DrawSelectable(int globalIdx, bool selected)
|
public virtual bool Draw(Utf8StringHandler<LabelStringHandlerBuffer> label, IDesignStandIn? currentDesign, out IDesignStandIn? newSelection,
|
||||||
|
float width)
|
||||||
{
|
{
|
||||||
var (design, path) = Items[globalIdx];
|
CurrentDesign = currentDesign;
|
||||||
bool ret;
|
bool ret;
|
||||||
switch (design)
|
using (ImGuiColor.Text.Push(DesignColors.GetColor(CurrentDesign as Design)))
|
||||||
{
|
{
|
||||||
case Design realDesign:
|
ret = currentDesign is null
|
||||||
{
|
? base.Draw(label, "Select Design Here..."u8, StringU8.Empty, width, out var result)
|
||||||
using var color = ImGuiColor.Text.Push(DesignColors.GetColor(realDesign));
|
: base.Draw(label, currentDesign.ResolveName(Config.IncognitoMode), StringU8.Empty, width, out result);
|
||||||
ret = base.DrawSelectable(globalIdx, selected);
|
newSelection = ret ? result.Design : currentDesign;
|
||||||
DrawPath(path, realDesign);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
case QuickSelectedDesign quickDesign:
|
|
||||||
{
|
|
||||||
using var color = ImGuiColor.Text.Push(ColorId.NormalDesign.Value());
|
|
||||||
ret = base.DrawSelectable(globalIdx, selected);
|
|
||||||
DrawResolvedDesign(quickDesign);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
default: return base.DrawSelectable(globalIdx, selected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void DrawPath(string path, Design realDesign)
|
|
||||||
{
|
|
||||||
if (path.Length <= 0 || realDesign.Name == path)
|
|
||||||
return;
|
|
||||||
|
|
||||||
DrawRightAligned(realDesign.Name, path, ImGuiColor.TextDisabled.Get().Color);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawResolvedDesign(QuickSelectedDesign quickDesign)
|
|
||||||
{
|
|
||||||
var linkedDesign = quickDesign.CurrentDesign;
|
|
||||||
if (linkedDesign != null)
|
|
||||||
DrawRightAligned(quickDesign.ResolveName(false), linkedDesign.Name.Text, DesignColors.GetColor(linkedDesign));
|
|
||||||
else
|
|
||||||
DrawRightAligned(quickDesign.ResolveName(false), "[Nothing]", DesignColors.MissingColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected bool Draw(IDesignStandIn? currentDesign, string? label, float width)
|
|
||||||
{
|
|
||||||
_currentDesign = currentDesign;
|
|
||||||
UpdateCurrentSelection();
|
|
||||||
InnerWidth = 400 * Im.Style.GlobalScale;
|
|
||||||
var name = label ?? "Select Design Here...";
|
|
||||||
bool ret;
|
|
||||||
using (currentDesign is not null ? ImGuiColor.Text.Push(DesignColors.GetColor(currentDesign as Design)) : null)
|
|
||||||
{
|
|
||||||
ret = Draw("##design", name, string.Empty, width, Im.Style.TextHeightWithSpacing) && CurrentSelection is not null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentDesign is Design design)
|
if (CurrentDesign is Design design)
|
||||||
{
|
{
|
||||||
if (Im.Item.RightClicked() && Im.Io.KeyControl)
|
if (Im.Item.RightClicked() && Im.Io.KeyControl)
|
||||||
TabSelected.Invoke(MainTabType.Designs, design);
|
TabSelected.Invoke(MainTabType.Designs, design);
|
||||||
ImGuiUtil.HoverTooltip("Control + Right-Click to move to design.");
|
Im.Tooltip.OnHover("Control + Right-Click to move to design."u8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QuickSelectedDesignTooltip(CurrentDesign as QuickSelectedDesign);
|
||||||
}
|
}
|
||||||
|
|
||||||
QuickSelectedDesignTooltip(currentDesign);
|
CurrentDesign = null;
|
||||||
|
|
||||||
_currentDesign = null;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string ToString(Tuple<IDesignStandIn, string> obj)
|
private void QuickSelectedDesignTooltip(QuickSelectedDesign? design)
|
||||||
=> obj.Item1.ResolveName(Config.IncognitoMode);
|
|
||||||
|
|
||||||
protected override float GetFilterWidth()
|
|
||||||
=> InnerWidth - 2 * Im.Style.FramePadding.X;
|
|
||||||
|
|
||||||
protected override bool IsVisible(int globalIndex, LowerString filter)
|
|
||||||
{
|
{
|
||||||
var (design, path) = Items[globalIndex];
|
if (design is null)
|
||||||
return filter.IsContained(path) || filter.IsContained(design.ResolveName(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnMouseWheel(string preview, ref int _2, int steps)
|
|
||||||
{
|
|
||||||
if (!ReferenceEquals(_currentDesign, CurrentSelection?.Item1))
|
|
||||||
CurrentSelectionIdx = -1;
|
|
||||||
|
|
||||||
base.OnMouseWheel(preview, ref _2, steps);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateCurrentSelection()
|
|
||||||
{
|
|
||||||
if (!_isCurrentSelectionDirty)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var priorState = IsInitialized;
|
if (!Im.Item.Hovered())
|
||||||
if (priorState)
|
|
||||||
Cleanup();
|
|
||||||
CurrentSelectionIdx = Items.IndexOf(s => ReferenceEquals(s.Item1, CurrentSelection?.Item1));
|
|
||||||
if (CurrentSelectionIdx >= 0)
|
|
||||||
{
|
|
||||||
UpdateSelection(Items[CurrentSelectionIdx]);
|
|
||||||
}
|
|
||||||
else if (Items.Count > 0)
|
|
||||||
{
|
|
||||||
CurrentSelectionIdx = 0;
|
|
||||||
UpdateSelection(Items[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UpdateSelection(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!priorState)
|
|
||||||
Cleanup();
|
|
||||||
_isCurrentSelectionDirty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override int UpdateCurrentSelected(int currentSelected)
|
|
||||||
{
|
|
||||||
CurrentSelectionIdx = Items.IndexOf(p => _currentDesign == p.Item1);
|
|
||||||
UpdateSelection(CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : null);
|
|
||||||
return CurrentSelectionIdx;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDesignChanged(DesignChanged.Type type, Design? _1, ITransaction? _2 = null)
|
|
||||||
{
|
|
||||||
_isCurrentSelectionDirty = type switch
|
|
||||||
{
|
|
||||||
DesignChanged.Type.Created => true,
|
|
||||||
DesignChanged.Type.Renamed => true,
|
|
||||||
DesignChanged.Type.ChangedColor => true,
|
|
||||||
DesignChanged.Type.Deleted => true,
|
|
||||||
DesignChanged.Type.QuickDesignBar => true,
|
|
||||||
_ => _isCurrentSelectionDirty,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void QuickSelectedDesignTooltip(IDesignStandIn? design)
|
|
||||||
{
|
|
||||||
if (!ImGui.IsItemHovered())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (design is not QuickSelectedDesign q)
|
using var tt = Im.Tooltip.Begin();
|
||||||
return;
|
var linkedDesign = design.CurrentDesign;
|
||||||
|
if (linkedDesign is not null)
|
||||||
using var tt = ImRaii.Tooltip();
|
|
||||||
var linkedDesign = q.CurrentDesign;
|
|
||||||
if (linkedDesign != null)
|
|
||||||
{
|
{
|
||||||
ImGui.TextUnformatted("Currently resolving to ");
|
Im.Text("Currently resolving to "u8);
|
||||||
using var color = ImGuiColor.Text.Push(DesignColors.GetColor(linkedDesign));
|
using var color = ImGuiColor.Text.Push(DesignColors.GetColor(linkedDesign));
|
||||||
ImGui.SameLine(0, 0);
|
Im.Line.NoSpacing();
|
||||||
ImGui.TextUnformatted(linkedDesign.Name.Text);
|
Im.Text(linkedDesign.Name.Text);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ImGui.TextUnformatted("No design selected in the Quick Design Bar.");
|
Im.Text("No design selected in the Quick Design Bar."u8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawRightAligned(string leftText, string text, Rgba32 color)
|
protected sealed class DesignFilter : Utf8FilterBase<CacheItem>
|
||||||
{
|
{
|
||||||
var start = ImGui.GetItemRectMin();
|
public override bool DrawFilter(ReadOnlySpan<byte> label, Vector2 availableRegion)
|
||||||
var pos = start.X + ImGui.CalcTextSize(leftText).X;
|
|
||||||
var maxSize = ImGui.GetWindowPos().X + ImGui.GetWindowContentRegionMax().X;
|
|
||||||
var remainingSpace = maxSize - pos;
|
|
||||||
var requiredSize = ImGui.CalcTextSize(text).X + Im.Style.ItemInnerSpacing.X;
|
|
||||||
var offset = remainingSpace - requiredSize;
|
|
||||||
if (ImGui.GetScrollMaxY() == 0)
|
|
||||||
offset -= Im.Style.ItemInnerSpacing.X;
|
|
||||||
|
|
||||||
if (offset < Im.Style.ItemSpacing.X)
|
|
||||||
ImGuiUtil.HoverTooltip(text);
|
|
||||||
else
|
|
||||||
Im.Window.DrawList.Text(start with { X = pos + offset }, color, text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class DesignCombo : DesignComboBase
|
|
||||||
{
|
|
||||||
protected DesignCombo(Logger log, DesignChanged designChanged, TabSelected tabSelected,
|
|
||||||
EphemeralConfig config, DesignColors designColors, Func<IReadOnlyList<Tuple<IDesignStandIn, string>>> generator)
|
|
||||||
: base(generator, log, designChanged, tabSelected, config, designColors)
|
|
||||||
{
|
|
||||||
if (Items.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CurrentSelection = Items[0];
|
|
||||||
CurrentSelectionIdx = 0;
|
|
||||||
base.Cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDesignStandIn? Design
|
|
||||||
=> CurrentSelection?.Item1;
|
|
||||||
|
|
||||||
public void Draw(float width)
|
|
||||||
=> Draw(Design, Design?.ResolveName(Config.IncognitoMode) ?? string.Empty, width);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class QuickDesignCombo : DesignCombo
|
|
||||||
{
|
|
||||||
public QuickDesignCombo(DesignFileSystem fileSystem,
|
|
||||||
Logger log,
|
|
||||||
DesignChanged designChanged,
|
|
||||||
TabSelected tabSelected,
|
|
||||||
EphemeralConfig config,
|
|
||||||
DesignColors designColors)
|
|
||||||
: base(log, designChanged, tabSelected, config, designColors, () =>
|
|
||||||
[
|
|
||||||
.. fileSystem
|
|
||||||
.Where(kvp => kvp.Key.QuickDesign)
|
|
||||||
.Select(kvp => new Tuple<IDesignStandIn, string>(kvp.Key, kvp.Value.FullName()))
|
|
||||||
.OrderBy(d => d.Item2),
|
|
||||||
])
|
|
||||||
{
|
|
||||||
if (config.SelectedQuickDesign != Guid.Empty)
|
|
||||||
{
|
{
|
||||||
CurrentSelectionIdx = Items.IndexOf(t => t.Item1 is Design d && d.Identifier == config.SelectedQuickDesign);
|
using var _ = ImGuiColor.Text.PushDefault();
|
||||||
if (CurrentSelectionIdx >= 0)
|
return base.DrawFilter(label, availableRegion);
|
||||||
CurrentSelection = Items[CurrentSelectionIdx];
|
|
||||||
else if (Items.Count > 0)
|
|
||||||
CurrentSelectionIdx = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AllowMouseWheel = MouseWheelType.Unmodified;
|
public override bool WouldBeVisible(in CacheItem item, int globalIndex)
|
||||||
SelectionChanged += OnSelectionChange;
|
=> WouldBeVisible(item.Name.Utf8) || WouldBeVisible(item.Incognito.Utf8) || WouldBeVisible(item.FullPath.Utf8);
|
||||||
|
|
||||||
|
protected override ReadOnlySpan<byte> ToFilterString(in CacheItem item, int globalIndex)
|
||||||
|
=> item.Name.Utf8;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSelectionChange(Tuple<IDesignStandIn, string>? old, Tuple<IDesignStandIn, string>? @new)
|
protected sealed class Cache : FilterComboBaseCache<CacheItem>
|
||||||
{
|
{
|
||||||
if (old == null)
|
private new DesignComboBase Parent
|
||||||
|
=> (DesignComboBase)base.Parent;
|
||||||
|
|
||||||
|
public Cache(DesignComboBase parent)
|
||||||
|
: base(parent)
|
||||||
{
|
{
|
||||||
if (@new?.Item1 is not Design d)
|
Parent.DesignColors.ColorChanged += OnDesignColorChanged;
|
||||||
|
Parent.DesignChanged.Subscribe(OnDesignChanged, DesignChanged.Priority.DesignCombo);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ComputeWidth()
|
||||||
|
=> ComboWidth = UnfilteredItems.Max(d
|
||||||
|
=> d.Name.Utf8.CalculateSize(false).X + d.FullPath.Utf8.CalculateSize(false).X + 2 * Im.Style.ItemSpacing.X + Im.Style.ScrollbarSize);
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
Parent.DesignColors.ColorChanged -= OnDesignColorChanged;
|
||||||
|
Parent.DesignChanged.Unsubscribe(OnDesignChanged);
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDesignColorChanged()
|
||||||
|
=> Dirty |= IManagedCache.DirtyFlags.Custom;
|
||||||
|
|
||||||
|
private void OnDesignChanged(DesignChanged.Type type, Design? _1, ITransaction? _2 = null)
|
||||||
|
{
|
||||||
|
if (type switch
|
||||||
|
{
|
||||||
|
DesignChanged.Type.Created => true,
|
||||||
|
DesignChanged.Type.Renamed => true,
|
||||||
|
DesignChanged.Type.ChangedColor => true,
|
||||||
|
DesignChanged.Type.Deleted => true,
|
||||||
|
DesignChanged.Type.QuickDesignBar => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
Dirty |= IManagedCache.DirtyFlags.Custom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override FilterComboBaseCache<CacheItem> CreateCache()
|
||||||
|
=> new Cache(this);
|
||||||
|
|
||||||
|
public readonly struct CacheItem(IDesignStandIn design, Vector4 color, string path, string name)
|
||||||
|
{
|
||||||
|
public readonly IDesignStandIn Design = design;
|
||||||
|
public readonly StringPair Name = new(name);
|
||||||
|
public readonly StringPair Incognito = new(design.ResolveName(true));
|
||||||
|
public readonly StringPair FullPath = new(path);
|
||||||
|
public readonly Vector4 Color = color;
|
||||||
|
|
||||||
|
public static string Ordering(CacheItem item)
|
||||||
|
=> item.FullPath.Utf16.Length > 0 ? item.FullPath.Utf16 : item.Name.Utf16;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected override bool DrawItem(in CacheItem item, int globalIndex, bool selected)
|
||||||
|
{
|
||||||
|
using var color = ImGuiColor.Text.Push(item.Color);
|
||||||
|
var name = Config.IncognitoMode ? item.Incognito.Utf8 : item.Name.Utf8;
|
||||||
|
var ret = Im.Selectable(name, selected);
|
||||||
|
if (!item.FullPath.IsEmpty && !Config.IncognitoMode)
|
||||||
|
{
|
||||||
|
Im.Line.Same();
|
||||||
|
color.Push(ImGuiColor.Text, Im.Style[ImGuiColor.TextDisabled]);
|
||||||
|
ImEx.TextRightAligned(item.FullPath.Utf8);
|
||||||
|
}
|
||||||
|
else if (item.Design is QuickSelectedDesign { CurrentDesign: { } d })
|
||||||
|
{
|
||||||
|
Im.Line.Same();
|
||||||
|
color.Push(ImGuiColor.Text, DesignColors.GetColor(d));
|
||||||
|
ImEx.TextRightAligned(d.ResolveName(Config.IncognitoMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override float ItemHeight
|
||||||
|
=> Im.Style.TextHeightWithSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class QuickDesignCombo : DesignComboBase, IDisposable, IUiService
|
||||||
|
{
|
||||||
|
public Design? QuickDesign
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if (field == value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Config.SelectedQuickDesign = d.Identifier;
|
field = value;
|
||||||
Config.Save();
|
Config.SelectedQuickDesign = field?.Identifier ?? Guid.Empty;
|
||||||
}
|
|
||||||
else if (@new?.Item1 is not Design d)
|
|
||||||
{
|
|
||||||
Config.SelectedQuickDesign = Guid.Empty;
|
|
||||||
Config.Save();
|
|
||||||
}
|
|
||||||
else if (!old.Item1.Equals(@new.Item1))
|
|
||||||
{
|
|
||||||
Config.SelectedQuickDesign = d.Identifier;
|
|
||||||
Config.Save();
|
Config.Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public QuickDesignCombo(EphemeralConfig config, DesignChanged designChanged, DesignColors designColors, TabSelected tabSelected,
|
||||||
|
DesignFileSystem designFileSystem, DesignManager designs)
|
||||||
|
: base(config, designs, designChanged, designColors, tabSelected, designFileSystem)
|
||||||
|
{
|
||||||
|
if (Designs.Designs.TryGetValue(config.SelectedQuickDesign, out var design) && design.QuickDesign)
|
||||||
|
QuickDesign = design;
|
||||||
|
DesignChanged.Subscribe(OnDesignChanged, DesignChanged.Priority.DesignCombo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDesignChanged(DesignChanged.Type type, Design changedDesign, ITransaction? _)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case DesignChanged.Type.Created:
|
||||||
|
// If the quick design bar has no selection, select the new design if it supports the bar.
|
||||||
|
if (QuickDesign is null && changedDesign.QuickDesign)
|
||||||
|
QuickDesign = changedDesign;
|
||||||
|
break;
|
||||||
|
case DesignChanged.Type.Deleted:
|
||||||
|
// If the deleted design was selected, select the first design that supports the bar, if any.
|
||||||
|
if (QuickDesign == changedDesign)
|
||||||
|
QuickDesign = Designs.Designs.FirstOrDefault(d => d.QuickDesign);
|
||||||
|
break;
|
||||||
|
case DesignChanged.Type.ReloadedAll:
|
||||||
|
// If all designs were reloaded, update the selection.
|
||||||
|
QuickDesign = Designs.Designs.TryGetValue(Config.SelectedQuickDesign, out var design) && design.QuickDesign ? design : null;
|
||||||
|
break;
|
||||||
|
case DesignChanged.Type.QuickDesignBar:
|
||||||
|
// If the quick design support of a design was changed, select the new design if the bar has no selection and the design now supports it,
|
||||||
|
if (QuickDesign is null && changedDesign.QuickDesign)
|
||||||
|
QuickDesign = changedDesign;
|
||||||
|
// or select the first design that supports the bar, if any, if the support was removed from the currently selected design.
|
||||||
|
else if (QuickDesign == changedDesign && !changedDesign.QuickDesign)
|
||||||
|
QuickDesign = Designs.Designs.FirstOrDefault(d => d.QuickDesign);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Draw(Utf8StringHandler<LabelStringHandlerBuffer> label, float width)
|
||||||
|
{
|
||||||
|
if (!base.Draw(label, QuickDesign, out var newDesign, width))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QuickDesign = newDesign as Design;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<CacheItem> GetItems()
|
||||||
|
=> Designs.Designs
|
||||||
|
.Where(design => design.QuickDesign)
|
||||||
|
.Select(CreateItem)
|
||||||
|
.OrderBy(CacheItem.Ordering);
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
=> DesignChanged.Unsubscribe(OnDesignChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class LinkDesignCombo(
|
public sealed class LinkDesignCombo : DesignComboBase, IUiService, IDisposable
|
||||||
DesignFileSystem fileSystem,
|
{
|
||||||
Logger log,
|
public Design? NewSelection { get; private set; }
|
||||||
DesignChanged designChanged,
|
|
||||||
TabSelected tabSelected,
|
public LinkDesignCombo(EphemeralConfig config, DesignChanged designChanged, DesignColors designColors, TabSelected tabSelected,
|
||||||
EphemeralConfig config,
|
DesignFileSystem designFileSystem, DesignManager designs)
|
||||||
DesignColors designColors)
|
: base(config, designs, designChanged, designColors, tabSelected, designFileSystem)
|
||||||
: DesignCombo(log, designChanged, tabSelected, config, designColors, () =>
|
{
|
||||||
[
|
DesignChanged.Subscribe(OnDesignChanged, DesignChanged.Priority.DesignCombo);
|
||||||
.. fileSystem
|
}
|
||||||
.Select(kvp => new Tuple<IDesignStandIn, string>(kvp.Key, kvp.Value.FullName()))
|
|
||||||
.OrderBy(d => d.Item2),
|
public bool Draw(Utf8StringHandler<LabelStringHandlerBuffer> label, float width)
|
||||||
]);
|
{
|
||||||
|
if (!base.Draw(label, NewSelection, out var newSelection, width))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
NewSelection = newSelection as Design;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<CacheItem> GetItems()
|
||||||
|
=> Designs.Designs.Select(CreateItem)
|
||||||
|
.OrderBy(CacheItem.Ordering);
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
=> DesignChanged.Unsubscribe(OnDesignChanged);
|
||||||
|
|
||||||
|
private void OnDesignChanged(DesignChanged.Type type, Design design, ITransaction? _)
|
||||||
|
{
|
||||||
|
if (type is DesignChanged.Type.Deleted && design == NewSelection || type is DesignChanged.Type.ReloadedAll)
|
||||||
|
NewSelection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class RandomDesignCombo(
|
public sealed class RandomDesignCombo(
|
||||||
DesignManager designs,
|
|
||||||
DesignFileSystem fileSystem,
|
|
||||||
Logger log,
|
|
||||||
DesignChanged designChanged,
|
|
||||||
TabSelected tabSelected,
|
|
||||||
EphemeralConfig config,
|
EphemeralConfig config,
|
||||||
DesignColors designColors)
|
DesignManager designs,
|
||||||
: DesignCombo(log, designChanged, tabSelected, config, designColors, () =>
|
DesignChanged designChanged,
|
||||||
[
|
DesignColors designColors,
|
||||||
.. fileSystem
|
TabSelected tabSelected,
|
||||||
.Select(kvp => new Tuple<IDesignStandIn, string>(kvp.Key, kvp.Value.FullName()))
|
DesignFileSystem designFileSystem) : DesignComboBase(config, designs, designChanged, designColors, tabSelected, designFileSystem),
|
||||||
.OrderBy(d => d.Item2),
|
IUiService
|
||||||
])
|
|
||||||
{
|
{
|
||||||
private Design? GetDesign(RandomPredicate.Exact exact)
|
private Design? GetDesign(RandomPredicate.Exact exact)
|
||||||
{
|
{
|
||||||
return exact.Which switch
|
return exact.Which switch
|
||||||
{
|
{
|
||||||
RandomPredicate.Exact.Type.Name => designs.Designs.FirstOrDefault(d => d.Name == exact.Value),
|
RandomPredicate.Exact.Type.Name => Designs.Designs.FirstOrDefault(d => d.Name == exact.Value),
|
||||||
RandomPredicate.Exact.Type.Path => fileSystem.Find(exact.Value.Text, out var c) && c is DesignFileSystem.Leaf l ? l.Value : null,
|
RandomPredicate.Exact.Type.Path => DesignFileSystem.Find(exact.Value.Text, out var c) && c is DesignFileSystem.Leaf l
|
||||||
RandomPredicate.Exact.Type.Identifier => designs.Designs.ByIdentifier(Guid.TryParse(exact.Value.Text, out var g) ? g : Guid.Empty),
|
? l.Value
|
||||||
|
: null,
|
||||||
|
RandomPredicate.Exact.Type.Identifier => Designs.Designs.ByIdentifier(Guid.TryParse(exact.Value.Text, out var g)
|
||||||
|
? g
|
||||||
|
: Guid.Empty),
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Draw(RandomPredicate.Exact exact, float width)
|
public bool Draw(RandomPredicate.Exact exact, [NotNullWhen(true)] out Design? newDesign, float width)
|
||||||
{
|
{
|
||||||
var design = GetDesign(exact);
|
var design = GetDesign(exact);
|
||||||
return Draw(design, design?.ResolveName(Config.IncognitoMode) ?? $"Not Found [{exact.Value.Text}]", width);
|
if (Draw(StringU8.Empty, design?.ResolveName(Config.IncognitoMode) ?? $"Not Found [{exact.Value.Text}]", StringU8.Empty, width,
|
||||||
|
out var newItem)
|
||||||
|
&& newItem.Design is Design d)
|
||||||
|
{
|
||||||
|
newDesign = d;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
newDesign = null;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Draw(IDesignStandIn? design, float width)
|
protected override IEnumerable<CacheItem> GetItems()
|
||||||
=> Draw(design, design?.ResolveName(Config.IncognitoMode) ?? string.Empty, width);
|
=> Designs.Designs.Select(CreateItem)
|
||||||
|
.OrderBy(CacheItem.Ordering);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class SpecialDesignCombo(
|
public sealed class SpecialDesignCombo : DesignComboBase, IUiService
|
||||||
DesignFileSystem fileSystem,
|
|
||||||
TabSelected tabSelected,
|
|
||||||
DesignColors designColors,
|
|
||||||
Logger log,
|
|
||||||
DesignChanged designChanged,
|
|
||||||
AutoDesignManager autoDesignManager,
|
|
||||||
EphemeralConfig config,
|
|
||||||
RandomDesignGenerator rng,
|
|
||||||
QuickSelectedDesign quickSelectedDesign)
|
|
||||||
: DesignComboBase(() => fileSystem
|
|
||||||
.Select(kvp => new Tuple<IDesignStandIn, string>(kvp.Key, kvp.Value.FullName()))
|
|
||||||
.OrderBy(d => d.Item2)
|
|
||||||
.Prepend(new Tuple<IDesignStandIn, string>(new RandomDesign(rng), string.Empty))
|
|
||||||
.Prepend(new Tuple<IDesignStandIn, string>(quickSelectedDesign, string.Empty))
|
|
||||||
.Prepend(new Tuple<IDesignStandIn, string>(new RevertDesign(), string.Empty))
|
|
||||||
.ToList(), log, designChanged, tabSelected, config, designColors)
|
|
||||||
{
|
{
|
||||||
|
private readonly AutoDesignManager _autoDesigns;
|
||||||
|
|
||||||
|
private readonly CacheItem _random;
|
||||||
|
private readonly CacheItem _revert;
|
||||||
|
private readonly CacheItem _quick;
|
||||||
|
|
||||||
|
public SpecialDesignCombo(EphemeralConfig config,
|
||||||
|
DesignManager designs,
|
||||||
|
DesignChanged designChanged,
|
||||||
|
DesignColors designColors,
|
||||||
|
TabSelected tabSelected,
|
||||||
|
DesignFileSystem designFileSystem,
|
||||||
|
AutoDesignManager autoDesigns,
|
||||||
|
RandomDesignGenerator rng, QuickSelectedDesign quickSelectedDesign)
|
||||||
|
: base(config, designs, designChanged, designColors, tabSelected, designFileSystem)
|
||||||
|
{
|
||||||
|
_autoDesigns = autoDesigns;
|
||||||
|
_random = CreateItem(new RandomDesign(rng));
|
||||||
|
_revert = CreateItem(new RevertDesign());
|
||||||
|
_quick = CreateItem(quickSelectedDesign);
|
||||||
|
}
|
||||||
|
|
||||||
public void Draw(AutoDesignSet set, AutoDesign? design, int autoDesignIndex)
|
public void Draw(AutoDesignSet set, AutoDesign? design, int autoDesignIndex)
|
||||||
{
|
{
|
||||||
if (!Draw(design?.Design, design?.Design.ResolveName(Config.IncognitoMode), Im.ContentRegion.Available.X))
|
if (!Draw(StringU8.Empty, design?.Design, out var newSelection, Im.ContentRegion.Available.X) || newSelection is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (autoDesignIndex >= 0)
|
if (autoDesignIndex >= 0)
|
||||||
autoDesignManager.ChangeDesign(set, autoDesignIndex, CurrentSelection!.Item1);
|
_autoDesigns.ChangeDesign(set, autoDesignIndex, newSelection);
|
||||||
else
|
else
|
||||||
autoDesignManager.AddDesign(set, CurrentSelection!.Item1);
|
_autoDesigns.AddDesign(set, newSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<CacheItem> GetItems()
|
||||||
|
=> Designs.Designs
|
||||||
|
.Select(CreateItem)
|
||||||
|
.OrderBy(CacheItem.Ordering)
|
||||||
|
.Prepend(_random)
|
||||||
|
.Prepend(_quick)
|
||||||
|
.Prepend(_revert);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ public sealed class DesignQuickBar : Window, IDisposable
|
||||||
if (_config.QdbButtons.HasFlag(QdbButtons.ApplyDesign))
|
if (_config.QdbButtons.HasFlag(QdbButtons.ApplyDesign))
|
||||||
{
|
{
|
||||||
var comboSize = width - _numButtons * (buttonSize.X + spacing.X);
|
var comboSize = width - _numButtons * (buttonSize.X + spacing.X);
|
||||||
_designCombo.Draw(comboSize);
|
_designCombo.Draw(StringU8.Empty, comboSize);
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
DrawApplyButton(buttonSize);
|
DrawApplyButton(buttonSize);
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +142,7 @@ public sealed class DesignQuickBar : Window, IDisposable
|
||||||
|
|
||||||
private void DrawApplyButton(Vector2 size)
|
private void DrawApplyButton(Vector2 size)
|
||||||
{
|
{
|
||||||
var design = _designCombo.Design as Design;
|
var design = _designCombo.QuickDesign;
|
||||||
var available = 0;
|
var available = 0;
|
||||||
_tooltipBuilder.Clear();
|
_tooltipBuilder.Clear();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,14 +34,11 @@ public abstract class BaseItemCombo(FavoriteManager favorites, ItemManager items
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly struct CacheItem(EquipItem item) : IDisposable
|
public readonly struct CacheItem(EquipItem item)
|
||||||
{
|
{
|
||||||
public readonly EquipItem Item = item;
|
public readonly EquipItem Item = item;
|
||||||
public readonly StringPair Name = new(item.Name);
|
public readonly StringPair Name = new(item.Name);
|
||||||
public readonly SizedStringPair Model = new($"({item.PrimaryId.Id}-{item.Variant.Id})");
|
public readonly StringPair Model = new($"({item.PrimaryId.Id}-{item.Variant.Id})");
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
=> Model.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected sealed class ItemFilter : PartwiseFilterBase<CacheItem>
|
protected sealed class ItemFilter : PartwiseFilterBase<CacheItem>
|
||||||
|
|
@ -85,7 +82,7 @@ public abstract class BaseItemCombo(FavoriteManager favorites, ItemManager items
|
||||||
var ret = Im.Selectable(item.Name.Utf8, selected);
|
var ret = Im.Selectable(item.Name.Utf8, selected);
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
using var color = ImGuiColor.Text.Push(Rgba32.Gray);
|
using var color = ImGuiColor.Text.Push(Rgba32.Gray);
|
||||||
ImEx.TextRightAligned(item.Model);
|
ImEx.TextRightAligned(item.Model.Utf8);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -236,9 +236,9 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
||||||
{
|
{
|
||||||
ImEx.TextFrameAligned("that are exactly"u8);
|
ImEx.TextFrameAligned("that are exactly"u8);
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
if (_randomDesignCombo.Draw(exact, Im.ContentRegion.Available.X) && _randomDesignCombo.Design is Design d)
|
if (_randomDesignCombo.Draw(exact, out var newDesign, Im.ContentRegion.Available.X))
|
||||||
{
|
{
|
||||||
list[i] = new RandomPredicate.Exact(RandomPredicate.Exact.Type.Identifier, d.Identifier.ToString());
|
list[i] = new RandomPredicate.Exact(RandomPredicate.Exact.Type.Identifier, newDesign.Identifier.ToString());
|
||||||
_autoDesignManager.ChangeData(_set!, _designIndex, list);
|
_autoDesignManager.ChangeData(_set!, _designIndex, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -314,8 +314,8 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
||||||
"Add a new condition that the design must be assigned to the given color."u8, invalid)
|
"Add a new condition that the design must be assigned to the given color."u8, invalid)
|
||||||
&& Add(new RandomPredicate.Exact(RandomPredicate.Exact.Type.Color, _newText));
|
&& Add(new RandomPredicate.Exact(RandomPredicate.Exact.Type.Color, _newText));
|
||||||
|
|
||||||
if (_randomDesignCombo.Draw(_newDesign, Im.ContentRegion.Available.X - Im.Style.ItemInnerSpacing.X - buttonSize.X))
|
if (_randomDesignCombo.Draw(StringU8.Empty, _newDesign, out var newDesign, Im.ContentRegion.Available.X - Im.Style.ItemInnerSpacing.X - buttonSize.X))
|
||||||
_newDesign = _randomDesignCombo.CurrentSelection?.Item1 as Design;
|
_newDesign = newDesign as Design;
|
||||||
Im.Line.SameInner();
|
Im.Line.SameInner();
|
||||||
if (ImEx.Button("Exact Design"u8, buttonSize, "Add a single, specific design."u8, _newDesign is null))
|
if (ImEx.Button("Exact Design"u8, buttonSize, "Add a single, specific design."u8, _newDesign is null))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -151,12 +151,12 @@ public class DesignLinkDrawer(
|
||||||
{
|
{
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
combo.Draw(Im.ContentRegion.Available.X);
|
combo.Draw(StringU8.Empty, Im.ContentRegion.Available.X);
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
string ttBefore, ttAfter;
|
string ttBefore, ttAfter;
|
||||||
bool canAddBefore, canAddAfter;
|
bool canAddBefore, canAddAfter;
|
||||||
var design = combo.Design as Design;
|
var design = combo.NewSelection;
|
||||||
if (design == null)
|
if (design is null)
|
||||||
{
|
{
|
||||||
ttAfter = ttBefore = "Select a design first.";
|
ttAfter = ttBefore = "Select a design first.";
|
||||||
canAddBefore = canAddAfter = false;
|
canAddBefore = canAddAfter = false;
|
||||||
|
|
@ -180,7 +180,7 @@ public class DesignLinkDrawer(
|
||||||
}
|
}
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImEx.Icon.Button(FontAwesomeIcon.ArrowCircleUp.Icon(), ttAfter, !canAddAfter))
|
if (ImEx.Icon.Button(FontAwesomeIcon.ArrowCircleDown.Icon(), ttAfter, !canAddAfter))
|
||||||
linkManager.AddDesignLink(selector.Selected!, design!, LinkOrder.After);
|
linkManager.AddDesignLink(selector.Selected!, design!, LinkOrder.After);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
51
Glamourer/Gui/Tabs/UnlocksTab/UnlockCacheItem.cs
Normal file
51
Glamourer/Gui/Tabs/UnlocksTab/UnlockCacheItem.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
using ImSharp;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
|
namespace Glamourer.Gui.Tabs.UnlocksTab;
|
||||||
|
|
||||||
|
public readonly struct UnlockCacheItem(in EquipItem item, in EquipItem offhand, in EquipItem gauntlets, in JobGroup jobs)
|
||||||
|
{
|
||||||
|
private static readonly StringU8 Always = new("Always"u8);
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum Dyability : byte
|
||||||
|
{
|
||||||
|
No = 1,
|
||||||
|
Yes = 2,
|
||||||
|
Two = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly EquipItem Item = item;
|
||||||
|
public readonly StringPair Name = new(item.Name);
|
||||||
|
public readonly EquipFlag Slot = item.Type.ToSlot().ToFlag();
|
||||||
|
|
||||||
|
public required DateTimeOffset UnlockTimestamp
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
init
|
||||||
|
{
|
||||||
|
field = value;
|
||||||
|
UnlockText = value == DateTimeOffset.MinValue ? Always :
|
||||||
|
value == DateTimeOffset.MaxValue ? StringU8.Empty : new StringU8($"{value.LocalDateTime:g}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly StringU8 UnlockText;
|
||||||
|
|
||||||
|
public readonly StringPair ItemId = new($"{item.ItemId.Id}");
|
||||||
|
public readonly StringPair ModelString = new(item.ModelString);
|
||||||
|
public readonly StringPair OffhandModelString = offhand.Valid ? new StringPair(offhand.ModelString) : StringPair.Empty;
|
||||||
|
public readonly StringPair GauntletModelString = gauntlets.Valid ? new StringPair(gauntlets.ModelString) : StringPair.Empty;
|
||||||
|
public readonly StringPair RequiredLevel = new($"{item.Level.Value}");
|
||||||
|
public required (string, string)[] Mods { get; init; }
|
||||||
|
public readonly JobFlag Jobs = jobs.Flags;
|
||||||
|
public readonly StringU8 JobText = jobs.Name.IsEmpty ? new StringU8($"Unknown {jobs.Id.Id}") : jobs.Name;
|
||||||
|
public required bool Favorite { get; init; }
|
||||||
|
public readonly bool Tradable = item.Flags.HasFlag(ItemFlags.IsTradable);
|
||||||
|
public readonly bool Crest = item.Flags.HasFlag(ItemFlags.IsCrestWorthy);
|
||||||
|
|
||||||
|
public readonly Dyability Dyable = item.Flags.HasFlag(ItemFlags.IsDyable1)
|
||||||
|
? item.Flags.HasFlag(ItemFlags.IsDyable2) ? Dyability.Two : Dyability.Yes
|
||||||
|
: Dyability.No;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,4 @@
|
||||||
using Dalamud.Bindings.ImGui;
|
using ImSharp;
|
||||||
using ImSharp;
|
|
||||||
using Luna;
|
using Luna;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.UnlocksTab;
|
namespace Glamourer.Gui.Tabs.UnlocksTab;
|
||||||
|
|
@ -46,10 +45,10 @@ public sealed class UnlocksTab : Window, ITab<MainTabType>
|
||||||
{
|
{
|
||||||
DrawTypeSelection();
|
DrawTypeSelection();
|
||||||
if (DetailMode)
|
if (DetailMode)
|
||||||
_table.Draw(Im.Style.FrameHeightWithSpacing);
|
_table.Draw();
|
||||||
else
|
else
|
||||||
_overview.Draw();
|
_overview.Draw();
|
||||||
_table.Flags |= ImGuiTableFlags.Resizable;
|
_table.Flags |= TableFlags.Resizable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
|
|
@ -79,7 +78,7 @@ public sealed class UnlocksTab : Window, ITab<MainTabType>
|
||||||
{
|
{
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImEx.Icon.Button(LunaStyle.AutoResizeIcon, "Restore all columns to their original size."u8))
|
if (ImEx.Icon.Button(LunaStyle.AutoResizeIcon, "Restore all columns to their original size."u8))
|
||||||
_table.Flags &= ~ImGuiTableFlags.Resizable;
|
_table.Flags &= ~TableFlags.Resizable;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsOpen)
|
if (!IsOpen)
|
||||||
|
|
|
||||||
|
|
@ -89,8 +89,7 @@ public static class UiHelpers
|
||||||
using (Im.Disabled(locked))
|
using (Im.Disabled(locked))
|
||||||
{
|
{
|
||||||
using var id = Im.Id.Push(label);
|
using var id = Im.Id.Push(label);
|
||||||
if (ImEx.TriStateCheckbox(StringU8.Empty, ref apply, ColorId.TriStateCross.Value(), ColorId.TriStateCheck.Value(),
|
if (ImEx.TriStateCheckbox(StringU8.Empty, ref apply, ColorId.TriStateNeutral.Value(), ColorId.TriStateCheck.Value(), ColorId.TriStateCross.Value()))
|
||||||
ColorId.TriStateNeutral.Value()))
|
|
||||||
{
|
{
|
||||||
(newValue, newApply) = apply switch
|
(newValue, newApply) = apply switch
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,8 @@ public class DesignResolver(
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool GetQuickDesign(ref DesignBase? design, ref SeString? error)
|
public bool GetQuickDesign(ref DesignBase? design, ref SeString? error)
|
||||||
{
|
{
|
||||||
design = quickDesignCombo.Design as Design;
|
design = quickDesignCombo.QuickDesign;
|
||||||
if (design != null)
|
if (design is not null)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
error = "You do not have selected any design in the Quick Design Bar.";
|
error = "You do not have selected any design in the Quick Design Bar.";
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
namespace Glamourer.Unlocks;
|
namespace Glamourer.Unlocks;
|
||||||
|
|
||||||
public class FavoriteManager : ISavable
|
public sealed class FavoriteManager : ISavable
|
||||||
{
|
{
|
||||||
private readonly record struct FavoriteHairStyle(Gender Gender, SubRace Race, CustomizeIndex Type, CustomizeValue Id)
|
public readonly record struct FavoriteHairStyle(Gender Gender, SubRace Race, CustomizeIndex Type, CustomizeValue Id)
|
||||||
{
|
{
|
||||||
public uint ToValue()
|
public uint ToValue()
|
||||||
=> Id.Value | ((uint)Type << 8) | ((uint)Race << 16) | ((uint)Gender << 24);
|
=> Id.Value | ((uint)Type << 8) | ((uint)Race << 16) | ((uint)Gender << 24);
|
||||||
|
|
@ -27,6 +27,17 @@ public class FavoriteManager : ISavable
|
||||||
private readonly HashSet<FavoriteHairStyle> _favoriteHairStyles = [];
|
private readonly HashSet<FavoriteHairStyle> _favoriteHairStyles = [];
|
||||||
private readonly HashSet<BonusItemId> _favoriteBonusItems = [];
|
private readonly HashSet<BonusItemId> _favoriteBonusItems = [];
|
||||||
|
|
||||||
|
public enum FavoriteType : byte
|
||||||
|
{
|
||||||
|
Item,
|
||||||
|
Stain,
|
||||||
|
Customization,
|
||||||
|
BonusItem,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Event invoked with type, ID (or <see cref="FavoriteHairStyle"/>) and whether the item was favorited or removed. </summary>
|
||||||
|
public event Action<FavoriteType, uint, bool>? FavoriteChanged;
|
||||||
|
|
||||||
public FavoriteManager(SaveService saveService)
|
public FavoriteManager(SaveService saveService)
|
||||||
{
|
{
|
||||||
_saveService = saveService;
|
_saveService = saveService;
|
||||||
|
|
@ -135,36 +146,44 @@ public class FavoriteManager : ISavable
|
||||||
|
|
||||||
public bool TryAdd(ItemId item)
|
public bool TryAdd(ItemId item)
|
||||||
{
|
{
|
||||||
if (item.Id == 0 || !_favorites.Add(item))
|
if (item.Id is 0 || !_favorites.Add(item))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
FavoriteChanged?.Invoke(FavoriteType.Item, item.Id, true);
|
||||||
Save();
|
Save();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryAdd(BonusItemId item)
|
public bool TryAdd(BonusItemId item)
|
||||||
{
|
{
|
||||||
if (item.Id == 0 || !_favoriteBonusItems.Add(item))
|
if (item.Id is 0 || !_favoriteBonusItems.Add(item))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
FavoriteChanged?.Invoke(FavoriteType.BonusItem, item.Id, true);
|
||||||
Save();
|
Save();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryAdd(StainId stain)
|
public bool TryAdd(StainId stain)
|
||||||
{
|
{
|
||||||
if (stain.Id == 0 || !_favoriteColors.Add(stain))
|
if (stain.Id is 0 || !_favoriteColors.Add(stain))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
FavoriteChanged?.Invoke(FavoriteType.Stain, stain.Id, true);
|
||||||
Save();
|
Save();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryAdd(Gender gender, SubRace race, CustomizeIndex type, CustomizeValue value)
|
public bool TryAdd(Gender gender, SubRace race, CustomizeIndex type, CustomizeValue value)
|
||||||
{
|
{
|
||||||
if (!TypeAllowed(type) || !_favoriteHairStyles.Add(new FavoriteHairStyle(gender, race, type, value)))
|
if (!TypeAllowed(type))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
var id = new FavoriteHairStyle(gender, race, type, value);
|
||||||
|
if (!_favoriteHairStyles.Add(id))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
FavoriteChanged?.Invoke(FavoriteType.Customization, id.ToValue(), true);
|
||||||
Save();
|
Save();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -181,6 +200,7 @@ public class FavoriteManager : ISavable
|
||||||
if (!_favorites.Remove(item))
|
if (!_favorites.Remove(item))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
FavoriteChanged?.Invoke(FavoriteType.Item, item.Id, false);
|
||||||
Save();
|
Save();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -190,6 +210,7 @@ public class FavoriteManager : ISavable
|
||||||
if (!_favoriteBonusItems.Remove(item))
|
if (!_favoriteBonusItems.Remove(item))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
FavoriteChanged?.Invoke(FavoriteType.BonusItem, item.Id, false);
|
||||||
Save();
|
Save();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -199,15 +220,18 @@ public class FavoriteManager : ISavable
|
||||||
if (!_favoriteColors.Remove(stain))
|
if (!_favoriteColors.Remove(stain))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
FavoriteChanged?.Invoke(FavoriteType.Stain, stain.Id, false);
|
||||||
Save();
|
Save();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Remove(Gender gender, SubRace race, CustomizeIndex type, CustomizeValue value)
|
public bool Remove(Gender gender, SubRace race, CustomizeIndex type, CustomizeValue value)
|
||||||
{
|
{
|
||||||
if (!_favoriteHairStyles.Remove(new FavoriteHairStyle(gender, race, type, value)))
|
var id = new FavoriteHairStyle(gender, race, type, value);
|
||||||
|
if (!_favoriteHairStyles.Remove(id))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
FavoriteChanged?.Invoke(FavoriteType.Customization, id.ToValue(), true);
|
||||||
Save();
|
Save();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
Luna
2
Luna
|
|
@ -1 +1 @@
|
||||||
Subproject commit 3d460349da4ab862961bbb3170ccf4f0fedf0eca
|
Subproject commit c52743f736892dde62f39e6a2b06fde4096cdff7
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 6f39fadad5333c73cc1d90219828f169c3bbaa2a
|
Subproject commit 223fb1b04fee05c439b7679e7f62bc890e5d0885
|
||||||
Loading…
Add table
Add a link
Reference in a new issue