diff --git a/ARControl/Configuration.cs b/ARControl/Configuration.cs index e7ec011..77bdfdf 100644 --- a/ARControl/Configuration.cs +++ b/ARControl/Configuration.cs @@ -18,13 +18,20 @@ internal sealed class Configuration : IPluginConfiguration public required Guid Id { get; set; } public required string Name { get; set; } public required ListType Type { get; set; } = ListType.CollectOneTime; + public required ListPriority Priority { get; set; } = ListPriority.InOrder; public List Items { get; set; } = new(); } public enum ListType { CollectOneTime, - KeepAlways, + KeepStocked, + } + + public enum ListPriority + { + InOrder, + Balanced, } public sealed class QueuedItem @@ -33,7 +40,7 @@ internal sealed class Configuration : IPluginConfiguration public required int RemainingQuantity { get; set; } } - public class CharacterGroup + public sealed class CharacterGroup { public required Guid Id { get; set; } public required string Name { get; set; } diff --git a/ARControl/Windows/ConfigWindow.cs b/ARControl/Windows/ConfigWindow.cs index 82a1b4a..52da773 100644 --- a/ARControl/Windows/ConfigWindow.cs +++ b/ARControl/Windows/ConfigWindow.cs @@ -23,6 +23,8 @@ internal sealed class ConfigWindow : Window private static readonly Vector4 ColorGreen = ImGuiColors.HealerGreen; private static readonly Vector4 ColorRed = ImGuiColors.DalamudRed; private static readonly Vector4 ColorGrey = ImGuiColors.DalamudGrey; + private static readonly string[] StockingTypeLabels = { "Collect Once", "Keep in Stock" }; + private static readonly string[] PriorityLabels = { "Collect in order of the list", "Collect item with lowest inventory first" }; private readonly DalamudPluginInterface _pluginInterface; private readonly Configuration _configuration; @@ -31,10 +33,15 @@ internal sealed class ConfigWindow : Window private readonly ICommandManager _commandManager; private readonly IPluginLog _pluginLog; + private readonly Dictionary _currentEditPopups = new(); private string _searchString = string.Empty; - private Configuration.QueuedItem? _dragDropSource; - private bool _enableDragDrop; - private string _newGroupName = string.Empty; + private TemporaryConfig _newGroup = new() { Name = string.Empty }; + private TemporaryConfig _newList = new() + { + Name = string.Empty, + ListType = Configuration.ListType.CollectOneTime, + ListPriority = Configuration.ListPriority.InOrder + }; private bool _checkPerCharacter = true; private bool _onlyShowMissing = true; @@ -65,146 +72,294 @@ internal sealed class ConfigWindow : Window { if (ImGui.BeginTabBar("ARConfigTabs")) { - //DrawItemQueue(); - DrawCharacters(); + DrawVentureLists(); DrawCharacterGroups(); - //DrawGatheredItemsToCheck(); + DrawCharacters(); + DrawGatheredItemsToCheck(); ImGui.EndTabBar(); } } - /* - private unsafe void DrawItemQueue() + private unsafe void DrawVentureLists() { - if (ImGui.BeginTabItem("Item Lists")) + if (ImGui.BeginTabItem("Venture Lists")) { - if (ImGui.BeginCombo("Add Item...##VentureSelection", "")) + Configuration.ItemList? listToDelete = null; + foreach (var list in _configuration.ItemLists) { - ImGuiEx.SetNextItemFullWidth(); - ImGui.InputTextWithHint("", "Filter...", ref _searchString, 256); + ImGui.PushID($"List{list.Id}"); - foreach (var ventures in _gameCache.Ventures - .Where(x => x.Name.ToLower().Contains(_searchString.ToLower())) - .OrderBy(x => x.Level) - .ThenBy(x => x.Name) - .ThenBy(x => x.ItemId) - .GroupBy(x => x.ItemId)) + if (ImGuiComponents.IconButton(FontAwesomeIcon.Cog)) { - var venture = ventures.First(); - if (ImGui.Selectable( - $"{venture.Name} ({string.Join(" ", ventures.Select(x => x.CategoryName))})##SelectVenture{venture.RowId}")) + _currentEditPopups[list.Id] = new TemporaryConfig { - _configuration.QueuedItems.Add(new Configuration.QueuedItem - { - ItemId = venture.ItemId, - RemainingQuantity = 0, - }); - _searchString = string.Empty; - Save(); - } + Name = list.Name, + ListType = list.Type, + ListPriority = list.Priority, + }; + ImGui.OpenPopup($"##EditList{list.Id}"); } + DrawVentureListEditorPopup(list, ref listToDelete); - ImGui.EndCombo(); - } - - ImGui.Separator(); - - ImGui.Indent(30); - - Configuration.QueuedItem? itemToRemove = null; - Configuration.QueuedItem? itemToAdd = null; - int indexToAdd = 0; - for (int i = 0; i < _configuration.QueuedItems.Count; ++i) - { - var item = _configuration.QueuedItems[i]; - ImGui.PushID($"QueueItem{i}"); - var ventures = _gameCache.Ventures.Where(x => x.ItemId == item.ItemId).ToList(); - var venture = ventures.First(); - - if (!_enableDragDrop) + ImGui.SameLine(); + if (ImGui.CollapsingHeader($"{list.Name} {(list.Type == Configuration.ListType.CollectOneTime ? SeIconChar.BoxedNumber1.ToIconChar() : SeIconChar.Circle.ToIconChar())}")) { - ImGui.SetNextItemWidth(130); - int quantity = item.RemainingQuantity; - if (ImGui.InputInt($"{venture.Name} ({string.Join(" ", ventures.Select(x => x.CategoryName))})", - ref quantity, 100)) - { - item.RemainingQuantity = quantity; - Save(); - } + ImGui.Indent(30); + DrawVentureListItemSelection(list); + ImGui.Unindent(30); } - else - { - ImGui.Selectable($"{item.RemainingQuantity}x {venture.Name}"); - - if (ImGui.BeginDragDropSource()) - { - ImGui.SetDragDropPayload("ArcDragDrop", nint.Zero, 0); - _dragDropSource = item; - - ImGui.EndDragDropSource(); - } - - if (ImGui.BeginDragDropTarget()) - { - if (_dragDropSource != null && ImGui.AcceptDragDropPayload("ArcDragDrop").NativePtr != null) - { - itemToAdd = _dragDropSource; - indexToAdd = i; - - _dragDropSource = null; - } - - ImGui.EndDragDropTarget(); - } - } - - ImGui.OpenPopupOnItemClick($"###ctx{i}", ImGuiPopupFlags.MouseButtonRight); - if (ImGui.BeginPopupContextItem($"###ctx{i}")) - { - if (ImGui.MenuItem($"Remove {venture.Name}")) - itemToRemove = item; - - ImGui.EndPopup(); - } - ImGui.PopID(); } - if (itemToRemove != null) + if (listToDelete != null) { - _configuration.QueuedItems.Remove(itemToRemove); + _configuration.ItemLists.Remove(listToDelete); Save(); } - if (itemToAdd != null) - { - _pluginLog.Information($"Updating {itemToAdd.ItemId} → {indexToAdd}"); - _configuration.QueuedItems.Remove(itemToAdd); - _configuration.QueuedItems.Insert(indexToAdd, itemToAdd); - Save(); - } - - ImGui.Unindent(30); - - if (_configuration.QueuedItems.Count > 0) - ImGui.Separator(); - - if (ImGuiComponents.IconButtonWithText(_enableDragDrop ? FontAwesomeIcon.Times : FontAwesomeIcon.Sort, _enableDragDrop ? "Disable Drag&Drop" : "Enable Drag&Drop")) - { - _enableDragDrop = !_enableDragDrop; - } - - ImGui.SameLine(); - if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Check, "Remove all finished items")) - { - if (_configuration.QueuedItems.RemoveAll(q => q.RemainingQuantity == 0) > 0) - Save(); - } - + ImGui.Separator(); + DrawNewVentureList(); ImGui.EndTabItem(); } } -*/ + + private void DrawVentureListEditorPopup(Configuration.ItemList list, ref Configuration.ItemList? listToDelete) + { + var assignedCharacters = _configuration.Characters + .Where(x => x.Type == Configuration.CharacterType.Standalone && x.ItemListIds.Contains(list.Id)) + .OrderBy(x => x.WorldName) + .ThenBy(x => x.LocalContentId) + .ToList(); + var assignedGroups = _configuration.CharacterGroups + .Where(x => x.ItemListIds.Contains(list.Id)) + .ToList(); + if (_currentEditPopups.TryGetValue(list.Id, out TemporaryConfig? temporaryConfig) && + ImGui.BeginPopup($"##EditList{list.Id}")) + { + var (save, canSave) = DrawVentureListEditor(temporaryConfig, list); + ImGui.BeginDisabled(!canSave || (list.Name == temporaryConfig.Name && + list.Type == temporaryConfig.ListType && + list.Priority == temporaryConfig.ListPriority)); + save |= ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Save, "Save"); + ImGui.EndDisabled(); + + if (save && canSave) + { + list.Name = temporaryConfig.Name; + list.Type = temporaryConfig.ListType; + + if (list.Type == Configuration.ListType.CollectOneTime) + list.Priority = Configuration.ListPriority.InOrder; + else + list.Priority = temporaryConfig.ListPriority; + + ImGui.CloseCurrentPopup(); + Save(); + } + else + { + ImGui.SameLine(); + ImGui.BeginDisabled(assignedCharacters.Count > 0 || assignedGroups.Count > 0); + if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Times, "Delete")) + { + listToDelete = list; + ImGui.CloseCurrentPopup(); + } + + ImGui.EndDisabled(); + if ((assignedCharacters.Count > 0 || assignedGroups.Count > 0) && + ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) + { + ImGui.BeginTooltip(); + ImGui.Text( + $"Remove this list from the {assignedCharacters.Count} character(s) and {assignedGroups.Count} group(s) using it before deleting it."); + foreach (var character in assignedCharacters) + ImGui.BulletText($"{character.CharacterName} @ {character.WorldName}"); + foreach (var group in assignedGroups) + ImGui.BulletText($"{group.Name}"); + ImGui.EndTooltip(); + } + } + + ImGui.EndPopup(); + } + } + + private void DrawNewVentureList() + { + if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Plus, "Add Venture List")) + ImGui.OpenPopup("##AddList"); + + if (ImGui.BeginPopup("##AddList")) + { + (bool save, bool canSave) = DrawVentureListEditor(_newList, null); + + ImGui.BeginDisabled(!canSave); + save |= ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Save, "Save"); + ImGui.EndDisabled(); + + if (save && canSave) + { + _configuration.ItemLists.Add(new Configuration.ItemList + { + Id = Guid.NewGuid(), + Name = _newList.Name, + Type = _newList.ListType, + Priority = _newList.ListPriority, + }); + + _newList = new() + { + Name = string.Empty, + ListType = Configuration.ListType.CollectOneTime, + ListPriority = Configuration.ListPriority.InOrder + }; + + ImGui.CloseCurrentPopup(); + Save(); + } + + ImGui.EndPopup(); + } + } + + private (bool Save, bool CanSave) DrawVentureListEditor(TemporaryConfig temporaryConfig, Configuration.ItemList? list) + { + string listName = temporaryConfig.Name; + bool save = ImGui.InputTextWithHint("", "List Name...", ref listName, 64, + ImGuiInputTextFlags.EnterReturnsTrue); + bool canSave = IsValidListName(listName, list); + temporaryConfig.Name = listName; + + ImGui.PushID($"Type{list?.Id ?? Guid.Empty}"); + int type = (int)temporaryConfig.ListType; + if (ImGui.Combo("", ref type, StockingTypeLabels, StockingTypeLabels.Length)) + { + temporaryConfig.ListType = (Configuration.ListType)type; + if (temporaryConfig.ListType == Configuration.ListType.CollectOneTime) + temporaryConfig.ListPriority = Configuration.ListPriority.InOrder; + } + + ImGui.PopID(); + + if (temporaryConfig.ListType == Configuration.ListType.KeepStocked) + { + ImGui.PushID($"Priority{list?.Id ?? Guid.Empty}"); + int priority = (int)temporaryConfig.ListPriority; + if (ImGui.Combo("", ref priority, PriorityLabels, PriorityLabels.Length)) + temporaryConfig.ListPriority = (Configuration.ListPriority)priority; + ImGui.PopID(); + } + + return (save, canSave); + } + + private void DrawVentureListItemSelection(Configuration.ItemList list) + { + ImGuiEx.SetNextItemFullWidth(); + if (ImGui.BeginCombo($"##VentureSelection{list.Id}", "Add Item...")) + { + ImGuiEx.SetNextItemFullWidth(); + ImGui.InputTextWithHint("", "Filter...", ref _searchString, 256); + + foreach (var ventures in _gameCache.Ventures + .Where(x => x.Name.ToLower().Contains(_searchString.ToLower())) + .OrderBy(x => x.Level) + .ThenBy(x => x.Name) + .ThenBy(x => x.ItemId) + .GroupBy(x => x.ItemId)) + { + var venture = ventures.First(); + if (ImGui.Selectable( + $"{venture.Name} ({string.Join(" ", ventures.Select(x => x.CategoryName))})##SelectVenture{venture.RowId}")) + { + list.Items.Add(new Configuration.QueuedItem + { + ItemId = venture.ItemId, + RemainingQuantity = 0, + }); + _searchString = string.Empty; + Save(); + } + } + + ImGui.EndCombo(); + } + + ImGui.Separator(); + + Configuration.QueuedItem? itemToRemove = null; + Configuration.QueuedItem? itemToAdd = null; + int indexToAdd = 0; + float windowX = ImGui.GetContentRegionAvail().X; + for (int i = 0; i < list.Items.Count; ++i) + { + var item = list.Items[i]; + ImGui.PushID($"QueueItem{i}"); + var ventures = _gameCache.Ventures.Where(x => x.ItemId == item.ItemId).ToList(); + var venture = ventures.First(); + + ImGui.SetNextItemWidth(130); + int quantity = item.RemainingQuantity; + if (ImGui.InputInt($"{venture.Name} ({string.Join(" ", ventures.Select(x => x.CategoryName))})", + ref quantity, 100)) + { + item.RemainingQuantity = quantity; + Save(); + } + + ImGui.SameLine(windowX - 30); + ImGui.BeginDisabled(i == 0); + if (ImGuiComponents.IconButton($"##Up{i}", FontAwesomeIcon.ArrowUp)) + { + itemToAdd = item; + indexToAdd = i - 1; + } + ImGui.EndDisabled(); + + ImGui.SameLine(0, 0); + ImGui.BeginDisabled(i == list.Items.Count - 1); + if (ImGuiComponents.IconButton($"##Down{i}", FontAwesomeIcon.ArrowDown)) + { + itemToAdd = item; + indexToAdd = i + 1; + } + ImGui.EndDisabled(); + + ImGui.SameLine(); + if (ImGuiComponents.IconButton($"##Remove{i}", FontAwesomeIcon.Times)) + itemToRemove = item; + + ImGui.PopID(); + } + + if (itemToRemove != null) + { + list.Items.Remove(itemToRemove); + Save(); + } + + if (itemToAdd != null) + { + _pluginLog.Information($"Updating {itemToAdd.ItemId} → {indexToAdd}"); + list.Items.Remove(itemToAdd); + list.Items.Insert(indexToAdd, itemToAdd); + Save(); + } + + if (list.Items.Count > 0 && list.Type == Configuration.ListType.CollectOneTime) + { + ImGui.BeginDisabled(list.Items.All(x => x.RemainingQuantity > 0)); + if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Check, "Remove all finished items")) + { + list.Items.RemoveAll(q => q.RemainingQuantity <= 0); + Save(); + } + ImGui.EndDisabled(); + ImGui.Spacing(); + } + } + private void DrawCharacters() { if (ImGui.BeginTabItem("Retainers")) @@ -290,7 +445,7 @@ internal sealed class ConfigWindow : Window // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract if (character.ItemListIds == null) character.ItemListIds = new(); - DrawListSelection(character.LocalContentId.ToString(), character.ItemListIds); + DrawVentureListSelection(character.LocalContentId.ToString(), character.ItemListIds); } else { @@ -301,11 +456,13 @@ internal sealed class ConfigWindow : Window var lists = group.ItemListIds .Where(listId => listId != Guid.Empty) .Select(listId => _configuration.ItemLists.SingleOrDefault(x => x.Id == listId)) + .Where(list => list != null) + .Cast() .ToList(); if (lists.Count > 0) { foreach (var list in lists) - ImGui.TextUnformatted($"{SeIconChar.LinkMarker.ToIconChar()} {list.Name}"); + ImGui.BulletText($"{list.Name}"); } else ImGui.TextColored(ImGuiColors.DalamudRed, "(None)"); @@ -354,87 +511,176 @@ internal sealed class ConfigWindow : Window { if (ImGui.BeginTabItem("Groups")) { + Configuration.CharacterGroup? groupToDelete = null; foreach (var group in _configuration.CharacterGroups) { ImGui.PushID($"##Group{group.Id}"); - ImGuiComponents.IconButton(FontAwesomeIcon.Cog); - ImGui.SameLine(); - - var assignedCharacters = _configuration.Characters - .Where(x => x.Type == Configuration.CharacterType.PartOfCharacterGroup && - x.CharacterGroupId == group.Id) - .ToList(); - string countLabel = assignedCharacters.Count == 0 ? "no characters" - : assignedCharacters.Count == 1 ? "1 character" - : $"{assignedCharacters.Count} characters"; - if (ImGui.CollapsingHeader($"{group.Name} ({countLabel})")) + if (ImGuiComponents.IconButton(FontAwesomeIcon.Cog)) { - ImGui.Indent(30); - if (ImGui.BeginTabBar("GroupOptions")) + _currentEditPopups[group.Id] = new TemporaryConfig { - if (ImGui.BeginTabItem("Venture Lists")) - { - DrawListSelection(group.Id.ToString(), group.ItemListIds); - ImGui.EndTabItem(); - } - - if (ImGui.BeginTabItem("Characters")) - { - ImGui.Text("Characters in this group:"); - ImGui.Indent(30); - foreach (var character in assignedCharacters.OrderBy(x => x.WorldName) - .ThenBy(x => x.LocalContentId)) - ImGui.TextUnformatted($"{character.CharacterName} @ {character.WorldName}"); - ImGui.Unindent(30); - } - - ImGui.EndTabBar(); - } - - ImGui.Unindent(30); + Name = group.Name, + }; + ImGui.OpenPopup($"##EditGroup{group.Id}"); } + DrawCharacterGroupEditorPopup(group, out var assignedCharacters, ref groupToDelete); + ImGui.SameLine(); + DrawCharacterGroup(group, assignedCharacters); + ImGui.PopID(); } - ImGui.Separator(); - - if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Plus, "Add Group")) - ImGui.OpenPopup("##AddGroup"); - - if (ImGui.BeginPopup("##AddGroup")) + if (groupToDelete != null) { - bool save = ImGui.InputTextWithHint("", "Group Name...", ref _newGroupName, 64, ImGuiInputTextFlags.EnterReturnsTrue); - bool canSave = _newGroupName.Length >= 2 && - !_configuration.CharacterGroups.Any(x => _newGroupName.EqualsIgnoreCase(x.Name)); - ImGui.BeginDisabled(!canSave); - save |= ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Save, "Save"); - ImGui.EndDisabled(); - - if (canSave && save) - { - _configuration.CharacterGroups.Add(new Configuration.CharacterGroup - { - Id = Guid.NewGuid(), - Name = _newGroupName, - Icon = FontAwesomeIcon.None, - ItemListIds = new(), - }); - - _newGroupName = string.Empty; - - ImGui.CloseCurrentPopup(); - Save(); - } - ImGui.EndPopup(); + _configuration.CharacterGroups.Remove(groupToDelete); + Save(); } + ImGui.Separator(); + DrawNewCharacterGroup(); ImGui.EndTabItem(); } } - /* + private void DrawCharacterGroupEditorPopup(Configuration.CharacterGroup group, out List assignedCharacters, ref Configuration.CharacterGroup? groupToDelete) + { + assignedCharacters = _configuration.Characters + .Where(x => x.Type == Configuration.CharacterType.PartOfCharacterGroup && + x.CharacterGroupId == group.Id) + .OrderBy(x => x.WorldName) + .ThenBy(x => x.LocalContentId) + .ToList(); + if (_currentEditPopups.TryGetValue(group.Id, out TemporaryConfig? temporaryConfig) && ImGui.BeginPopup($"##EditGroup{group.Id}")) + { + (bool save, bool canSave) = DrawGroupEditor(temporaryConfig, group); + + ImGui.BeginDisabled(!canSave || group.Name == temporaryConfig.Name); + save |= ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Save, "Save"); + ImGui.EndDisabled(); + + if (save && canSave) + { + group.Name = temporaryConfig.Name; + + ImGui.CloseCurrentPopup(); + Save(); + } + else + { + ImGui.SameLine(); + ImGui.BeginDisabled(assignedCharacters.Count > 0); + if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Times, "Delete")) + { + groupToDelete = group; + ImGui.CloseCurrentPopup(); + } + ImGui.EndDisabled(); + if (assignedCharacters.Count > 0 && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) + { + ImGui.BeginTooltip(); + ImGui.Text( + $"Remove the {assignedCharacters.Count} character(s) from this group before deleting it."); + foreach (var character in assignedCharacters) + ImGui.BulletText($"{character.CharacterName} @ {character.WorldName}"); + ImGui.EndTooltip(); + } + } + ImGui.EndPopup(); + } + } + + private void DrawCharacterGroup(Configuration.CharacterGroup group, List assignedCharacters) + { + string countLabel = assignedCharacters.Count == 0 ? "no characters" + : assignedCharacters.Count == 1 ? "1 character" + : $"{assignedCharacters.Count} characters"; + if (ImGui.CollapsingHeader($"{group.Name} ({countLabel})")) + { + ImGui.Indent(30); + if (ImGui.BeginTabBar("GroupOptions")) + { + if (ImGui.BeginTabItem("Venture Lists")) + { + DrawVentureListSelection(group.Id.ToString(), group.ItemListIds); + ImGui.EndTabItem(); + } + + if (ImGui.BeginTabItem("Characters")) + { + ImGui.Text("Characters in this group:"); + ImGui.Indent(30); + foreach (var character in assignedCharacters.OrderBy(x => x.WorldName) + .ThenBy(x => x.LocalContentId)) + ImGui.TextUnformatted($"{character.CharacterName} @ {character.WorldName}"); + ImGui.Unindent(30); + } + + ImGui.EndTabBar(); + } + + ImGui.Unindent(30); + } + } + + private void DrawNewCharacterGroup() + { + if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Plus, "Add Group")) + ImGui.OpenPopup("##AddGroup"); + + if (ImGui.BeginPopup("##AddGroup")) + { + (bool save, bool canSave) = DrawGroupEditor(_newGroup, null); + + ImGui.BeginDisabled(!canSave); + save |= ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Save, "Save"); + ImGui.EndDisabled(); + + if (save && canSave) + { + _configuration.CharacterGroups.Add(new Configuration.CharacterGroup + { + Id = Guid.NewGuid(), + Name = _newGroup.Name, + Icon = FontAwesomeIcon.None, + ItemListIds = new(), + }); + + _newGroup = new() { Name = string.Empty }; + + ImGui.CloseCurrentPopup(); + Save(); + } + + ImGui.EndPopup(); + } + } + + private (bool Save, bool CanSave) DrawGroupEditor(TemporaryConfig group, Configuration.CharacterGroup? existingGroup) + { + string name = group.Name; + bool save = ImGui.InputTextWithHint("", "Group Name...", ref name, 64, ImGuiInputTextFlags.EnterReturnsTrue); + bool canSave = IsValidGroupName(name, existingGroup); + + group.Name = name; + return (save, canSave); + } + + private bool IsValidGroupName(string name, Configuration.CharacterGroup? existingGroup) + { + return name.Length >= 2 && + !name.Contains('%') && + !_configuration.CharacterGroups.Any(x => x != existingGroup && name.EqualsIgnoreCase(x.Name)); + } + + private bool IsValidListName(string name, Configuration.ItemList? existingList) + { + return name.Length >= 2 && + !name.Contains('%') && + !_configuration.ItemLists.Any(x => x != existingList && name.EqualsIgnoreCase(x.Name)); + } + private void DrawGatheredItemsToCheck() { if (ImGui.BeginTabItem("Locked Items")) @@ -444,7 +690,8 @@ internal sealed class ConfigWindow : Window ImGui.Separator(); var itemsToCheck = - _configuration.QueuedItems + _configuration.ItemLists + .SelectMany(x => x.Items) .Select(x => x.ItemId) .Distinct() .Select(itemId => new @@ -462,10 +709,10 @@ internal sealed class ConfigWindow : Window .ToList(); var charactersToCheck = _configuration.Characters - .Where(x => x.Managed) + .Where(x => x.Type != Configuration.CharacterType.NotManaged) .OrderBy(x => x.WorldName) .ThenBy(x => x.LocalContentId) - .Select(x => new CheckedCharacter(x, itemsToCheck)) + .Select(x => new CheckedCharacter(_configuration, x, itemsToCheck)) .ToList(); if (_checkPerCharacter) @@ -552,9 +799,9 @@ internal sealed class ConfigWindow : Window ImGui.EndTabItem(); } - }*/ + } - private void DrawListSelection(string id, List selectedLists) + private void DrawVentureListSelection(string id, List selectedLists) { ImGui.PushID($"##ListSelection{id}"); @@ -565,17 +812,21 @@ internal sealed class ConfigWindow : Window Id = Guid.Empty, Name = "---", Type = Configuration.ListType.CollectOneTime, + Priority = Configuration.ListPriority.InOrder, } }.Concat(_configuration.ItemLists) .Select(x => (x.Id, x.Name, x)).ToList(); int? itemToRemove = null; + int? itemToAdd = null; + int indexToAdd = 0; + float windowX = ImGui.GetContentRegionAvail().X; for (int i = 0; i < selectedLists.Count; ++i) { - ImGui.PushID($"##{id}_Item{i}"); var listId = selectedLists[i]; var listIndex = itemLists.FindIndex(x => x.Id == listId); + ImGui.SetNextItemWidth(windowX - 76); if (ImGui.Combo("", ref listIndex, itemLists.Select(x => x.Name).ToArray(), itemLists.Count)) { selectedLists[i] = itemLists[listIndex].Id; @@ -583,22 +834,22 @@ internal sealed class ConfigWindow : Window } ImGui.SameLine(); - if (ImGuiComponents.IconButton($"##Jump{i}", FontAwesomeIcon.Edit)) - { - - } - - ImGui.SameLine(); + ImGui.BeginDisabled(i == 0); if (ImGuiComponents.IconButton($"##Up{i}", FontAwesomeIcon.ArrowUp)) { - + itemToAdd = i; + indexToAdd = i - 1; } + ImGui.EndDisabled(); ImGui.SameLine(0, 0); + ImGui.BeginDisabled(i == selectedLists.Count - 1); if (ImGuiComponents.IconButton($"##Down{i}", FontAwesomeIcon.ArrowDown)) { - + itemToAdd = i; + indexToAdd = i + 1; } + ImGui.EndDisabled(); ImGui.SameLine(); if (ImGuiComponents.IconButton($"##Remove{i}", FontAwesomeIcon.Times)) @@ -617,8 +868,8 @@ internal sealed class ConfigWindow : Window var list = itemLists[listIndex].List; ImGui.Indent(30); ImGui.Text(list.Type == Configuration.ListType.CollectOneTime - ? $"{SeIconChar.LinkMarker.ToIconString()} Items on this list will be collected once." - : $"{SeIconChar.LinkMarker.ToIconString()} Items on this list will be kept in stock on each character."); + ? $"{SeIconChar.BoxedNumber1.ToIconString()} Items on this list will be collected once." + : $"{SeIconChar.Circle.ToIconString()} Items on this list will be kept in stock on each character."); ImGui.Spacing(); foreach (var item in list.Items) { @@ -639,6 +890,14 @@ internal sealed class ConfigWindow : Window Save(); } + if (itemToAdd != null) + { + Guid listId = selectedLists[itemToAdd.Value]; + selectedLists.RemoveAt(itemToAdd.Value); + selectedLists.Insert(indexToAdd, listId); + Save(); + } + var unusedLists = itemLists.Where(x => x.Id != Guid.Empty && !selectedLists.Contains(x.Id)).ToList(); ImGui.BeginDisabled(unusedLists.Count == 0); if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Plus, "Add Venture List to this Group")) @@ -669,16 +928,44 @@ internal sealed class ConfigWindow : Window private sealed class CheckedCharacter { - public CheckedCharacter(Configuration.CharacterConfiguration character, + public CheckedCharacter(Configuration configuration, Configuration.CharacterConfiguration character, List itemsToCheck) { Character = character; + List itemListIds = new(); + if (character.Type == Configuration.CharacterType.Standalone) + { + itemListIds = character.ItemListIds; + } + else if (character.Type == Configuration.CharacterType.PartOfCharacterGroup) + { + var group = configuration.CharacterGroups.SingleOrDefault(x => x.Id == character.CharacterGroupId); + if (group != null) + itemListIds = group.ItemListIds; + } + + var itemIdsOnLists = itemListIds.Where(listId => listId != Guid.Empty) + .Select(listId => configuration.ItemLists.SingleOrDefault(x => x.Id == listId)) + .Where(list => list != null) + .SelectMany(list => list!.Items) + .Select(x => x.ItemId) + .ToList(); + foreach (var item in itemsToCheck) { + // check if the item is on any relevant list + if (!itemIdsOnLists.Contains(item.ItemId)) + { + Items[item.ItemId] = ColorGrey; + continue; + } + + // check if we are the correct job bool enabled = character.Retainers.Any(x => item.Ventures.Any(v => v.MatchesJob(x.Job))); if (enabled) { + // do we have it gathered on this char? if (character.GatheredItems.Contains(item.GatheredItem.GatheredItemId)) Items[item.ItemId] = ColorGreen; else @@ -706,4 +993,11 @@ internal sealed class ConfigWindow : Window public required List Ventures { get; init; } public required uint ItemId { get; init; } } + + private sealed class TemporaryConfig + { + public required string Name { get; set; } + public Configuration.ListType ListType { get; set; } + public Configuration.ListPriority ListPriority { get; set; } + } }