diff --git a/Images/filterFound.png b/Images/filterFound.png new file mode 100644 index 0000000..f5ec40c Binary files /dev/null and b/Images/filterFound.png differ diff --git a/filterMod.png b/Images/filterMod.png similarity index 100% rename from filterMod.png rename to Images/filterMod.png diff --git a/Images/sortAZ.png b/Images/sortAZ.png new file mode 100644 index 0000000..9aa098e Binary files /dev/null and b/Images/sortAZ.png differ diff --git a/Images/sortAmmo.png b/Images/sortAmmo.png new file mode 100644 index 0000000..6a1769a Binary files /dev/null and b/Images/sortAmmo.png differ diff --git a/Images/sortAxe.png b/Images/sortAxe.png new file mode 100644 index 0000000..a282b98 Binary files /dev/null and b/Images/sortAxe.png differ diff --git a/Images/sortBait.png b/Images/sortBait.png new file mode 100644 index 0000000..4e7d583 Binary files /dev/null and b/Images/sortBait.png differ diff --git a/Images/sortDamage.png b/Images/sortDamage.png new file mode 100644 index 0000000..1c02d69 Binary files /dev/null and b/Images/sortDamage.png differ diff --git a/Images/sortDefense.png b/Images/sortDefense.png new file mode 100644 index 0000000..3fe4710 Binary files /dev/null and b/Images/sortDefense.png differ diff --git a/Images/sortFish.png b/Images/sortFish.png new file mode 100644 index 0000000..62f2fe4 Binary files /dev/null and b/Images/sortFish.png differ diff --git a/Images/sortHammer.png b/Images/sortHammer.png new file mode 100644 index 0000000..0479c89 Binary files /dev/null and b/Images/sortHammer.png differ diff --git a/Images/sortItemID.png b/Images/sortItemID.png new file mode 100644 index 0000000..cc99a8a Binary files /dev/null and b/Images/sortItemID.png differ diff --git a/Images/sortPick.png b/Images/sortPick.png new file mode 100644 index 0000000..8da6303 Binary files /dev/null and b/Images/sortPick.png differ diff --git a/Images/sortValue.png b/Images/sortValue.png new file mode 100644 index 0000000..0207de7 Binary files /dev/null and b/Images/sortValue.png differ diff --git a/ItemChecklist.cs b/ItemChecklist.cs index cd2b21c..998a1ad 100644 --- a/ItemChecklist.cs +++ b/ItemChecklist.cs @@ -1,11 +1,9 @@ -using Terraria; -using Terraria.ModLoader; -using System.Collections.Generic; -using Terraria.UI; -using Terraria.DataStructures; -using ItemChecklist.UI; -using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework; using System; +using System.Collections.Generic; +using Terraria; +using Terraria.ModLoader; +using Terraria.UI; namespace ItemChecklist { @@ -13,7 +11,6 @@ namespace ItemChecklist // TODO: World Checklist? MP shared checklist? // Has this item ever been seen on this world? - easy. Maintain separate bool array, on change, notify server, relay to clients. // send bool array as byte array? - // query magic storage? // WHY? I want to know everything we can craft yet public class ItemChecklist : Mod { @@ -25,17 +22,27 @@ namespace ItemChecklist public ItemChecklist() { - Properties = new ModProperties() - { - Autoload = true, - }; } public override void Load() { + // Latest uses ItemID.Sets.IsAMaterial, added 0.10.1.5 + if (ModLoader.version < new Version(0, 10, 1, 5)) + { + throw new Exception("\nThis mod uses functionality only present in the latest tModLoader. Please update tModLoader to use this mod\n\n"); + } + instance = this; ToggleChecklistHotKey = RegisterHotKey("Toggle Item Checklist", "I"); MagicStorageIntegration.Load(); + + if (!Main.dedServ) + { + UIElements.UICheckbox.checkboxTexture = GetTexture("UIElements/checkBox"); + UIElements.UICheckbox.checkmarkTexture = GetTexture("UIElements/checkMark"); + UIElements.UIHorizontalGrid.moreLeftTexture = GetTexture("UIElements/MoreLeft"); + UIElements.UIHorizontalGrid.moreRightTexture = GetTexture("UIElements/MoreRight"); + } } public override void Unload() @@ -45,6 +52,11 @@ namespace ItemChecklist ToggleChecklistHotKey = null; ItemChecklistInterface = null; MagicStorageIntegration.Unload(); + + UIElements.UICheckbox.checkboxTexture = null; + UIElements.UICheckbox.checkmarkTexture = null; + UIElements.UIHorizontalGrid.moreLeftTexture = null; + UIElements.UIHorizontalGrid.moreRightTexture = null; } public override void AddRecipes() @@ -52,7 +64,7 @@ namespace ItemChecklist if (!Main.dedServ) { ItemChecklistUI = new ItemChecklistUI(); - ItemChecklistUI.Activate(); + //ItemChecklistUI.Activate(); ItemChecklistInterface = new UserInterface(); ItemChecklistInterface.SetState(ItemChecklistUI); } @@ -96,6 +108,11 @@ namespace ItemChecklist OnNewItem?.Invoke(type); } + public override void UpdateUI(GameTime gameTime) + { + ItemChecklistInterface?.Update(gameTime); + } + int lastSeenScreenWidth; int lastSeenScreenHeight; public override void ModifyInterfaceLayers(List layers) @@ -115,8 +132,7 @@ namespace ItemChecklist lastSeenScreenWidth = Main.screenWidth; lastSeenScreenHeight = Main.screenHeight; } - - ItemChecklistInterface.Update(Main._drawInterfaceGameTime); + ItemChecklistUI.Draw(Main.spriteBatch); if (ItemChecklistUI.hoverText != "") diff --git a/ItemChecklist.csproj b/ItemChecklist.csproj index ec6e505..7e19dd2 100644 --- a/ItemChecklist.csproj +++ b/ItemChecklist.csproj @@ -65,18 +65,28 @@ + + False + C:\Program Files (x86)\Steam\steamapps\common\Terraria\Terraria.exe + - - - - - + + + + + + + + + + + @@ -85,12 +95,6 @@ - - - {3996d5fa-6e59-4fe4-9f2b-40eeef9645d5} - Terraria - - "C:\Program Files (x86)\Steam\steamapps\common\Terraria\tModLoaderServer.exe" -build "$(ProjectDir)\" -eac "$(TargetPath)" diff --git a/ItemChecklistGlobalItem.cs b/ItemChecklistGlobalItem.cs index aa2a172..81bad06 100644 --- a/ItemChecklistGlobalItem.cs +++ b/ItemChecklistGlobalItem.cs @@ -1,5 +1,4 @@ -using ItemChecklist.UI; -using Terraria; +using Terraria; using Terraria.ModLoader; namespace ItemChecklist diff --git a/ItemChecklistPlayer.cs b/ItemChecklistPlayer.cs index 861a4c9..87264e9 100644 --- a/ItemChecklistPlayer.cs +++ b/ItemChecklistPlayer.cs @@ -1,10 +1,7 @@ -using ItemChecklist.UI; -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Reflection; using Terraria; -using Terraria.DataStructures; using Terraria.GameInput; using Terraria.ID; using Terraria.ModLoader; @@ -30,7 +27,7 @@ namespace ItemChecklist internal int totalItemsFound; // eh, property? dunno. // Because of save, these values inherit the last used setting while loading - internal SortModes sortModePreference = SortModes.TerrariaSort; + //internal SortModes sortModePreference = SortModes.TerrariaSort; internal bool announcePreference; internal bool findChestItemsPreference = true; internal int showCompletedPreference; @@ -44,6 +41,14 @@ namespace ItemChecklist ItemChecklist.instance.ItemChecklistUI.UpdateNeeded(); } ItemChecklistUI.visible = !ItemChecklistUI.visible; + // Debug assistance, allows for reinitializing RecipeBrowserUI + //if (!ItemChecklistUI.visible) + //{ + // ItemChecklistUI.instance.RemoveAllChildren(); + // var isInitializedFieldInfo = typeof(Terraria.UI.UIElement).GetField("_isInitialized", BindingFlags.Instance | BindingFlags.NonPublic); + // isInitializedFieldInfo.SetValue(ItemChecklistUI.instance, false); + // ItemChecklistUI.instance.Activate(); + //} } } @@ -53,7 +58,7 @@ namespace ItemChecklist ItemChecklistUI.visible = false; ItemChecklistUI.announce = announcePreference; ItemChecklistUI.collectChestItems = findChestItemsPreference; - ItemChecklistUI.sortMode = sortModePreference; + //ItemChecklistUI.sortMode = sortModePreference; ItemChecklistUI.showCompleted = showCompletedPreference; ItemChecklist.instance.ItemChecklistUI.RefreshPreferences(); ItemChecklist.instance.ItemChecklistUI.UpdateNeeded(); @@ -78,7 +83,7 @@ namespace ItemChecklist announcePreference = false; findChestItemsPreference = true; - sortModePreference = SortModes.TerrariaSort; + //sortModePreference = SortModes.TerrariaSort; showCompletedPreference = 0; } } @@ -135,7 +140,7 @@ namespace ItemChecklist return new TagCompound { ["FoundItems"] = foundItems.Select(ItemIO.Save).ToList(), - ["SortMode"] = (int)ItemChecklistUI.sortMode, + //["SortMode"] = (int)ItemChecklistUI.sortMode, ["Announce"] = ItemChecklistUI.announce, // Not saving default, saving last used....good thing? ["CollectChestItems"] = ItemChecklistUI.collectChestItems, ["ShowCompleted"] = ItemChecklistUI.showCompleted, @@ -145,7 +150,7 @@ namespace ItemChecklist public override void Load(TagCompound tag) { foundItems = tag.GetList("FoundItems").Select(ItemIO.Load).ToList(); - sortModePreference = (SortModes)tag.GetInt("SortMode"); + //sortModePreference = (SortModes)tag.GetInt("SortMode"); announcePreference = tag.GetBool("Announce"); if (tag.ContainsKey("CollectChestItems")) // Missing tags get defaultvalue, which would be false, which isn't what we want. findChestItemsPreference = tag.GetBool("CollectChestItems"); diff --git a/ItemChecklistUI.cs b/ItemChecklistUI.cs index aba573d..97b9e46 100644 --- a/ItemChecklistUI.cs +++ b/ItemChecklistUI.cs @@ -1,36 +1,45 @@ -using Microsoft.Xna.Framework; +using ItemChecklist.UIElements; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; using Terraria; using Terraria.GameContent.UI.Elements; -using Terraria.UI; using Terraria.ID; -using System; -using System.Reflection; -using System.Linq; using Terraria.ModLoader; -using System.Collections.Generic; +using Terraria.UI; -namespace ItemChecklist.UI +namespace ItemChecklist { class ItemChecklistUI : UIState { + internal static ItemChecklistUI instance; public UIHoverImageButton foundFilterButton; public UIToggleHoverImageButton muteButton; - public UIHoverImageButton sortButton; + //public UIHoverImageButton sortButton; public UIHoverImageButton modFilterButton; public UIToggleHoverImageButton collectChestItemsButton; + public UIToggleHoverImageButton showBadgeButton; + private bool buttonsHaveDummyTextures; public UIPanel checklistPanel; + internal NewUITextBox itemNameFilter; + internal NewUITextBox itemDescriptionFilter; + internal SharedUI sharedUI; public UIGrid checklistGrid; - public static SortModes sortMode = SortModes.TerrariaSort; + //public static SortModes sortMode = SortModes.TerrariaSort; float spacing = 8f; public static bool visible = false; public static int showCompleted = 0; // 0: both, 1: unfound, 2: found public static bool announce = true; public static bool collectChestItems = true; + public static bool showBadge = true; public static string hoverText = ""; - ItemSlot[] itemSlots; + UIItemSlot[] itemSlots; internal static int[] vanillaIDsInSortOrder; internal List modnames; @@ -38,64 +47,124 @@ namespace ItemChecklist.UI public string[] foundFilterStrings = { "All", "Unfound", "Found" }; + public ItemChecklistUI() + { + instance = this; + } + public override void OnInitialize() { // Is initialize called? (Yes it is called on reload) I want to reset nicely with new character or new loaded mods: visible = false; announce = false; // overwritten by modplayer collectChestItems = false; + showBadge = false; checklistPanel = new UIPanel(); checklistPanel.SetPadding(10); checklistPanel.Left.Pixels = 0; checklistPanel.HAlign = 1f; - checklistPanel.Top.Set(50f, 0f); + checklistPanel.Top.Set(85f, 0f); + checklistPanel.Left.Set(-40f, 0f); checklistPanel.Width.Set(250f, 0f); - checklistPanel.Height.Set(-100, 1f); + checklistPanel.Height.Set(-125, 1f); checklistPanel.BackgroundColor = new Color(73, 94, 171); - foundFilterButton = new UIHoverImageButton(Main.itemTexture[ItemID.Book], "Cycle Found Filter: ??"); + int top = 0; + int left = 0; + + // Because OnInitialize Happens during load and because we need it to happen for OnEnterWorld, use dummy sprite. + buttonsHaveDummyTextures = true; + + foundFilterButton = new UIHoverImageButton(Main.magicPixel, "Cycle Found Filter: ??"); foundFilterButton.OnClick += (a, b) => ToggleFoundFilterButtonClicked(a, b, true); foundFilterButton.OnRightClick += (a, b) => ToggleFoundFilterButtonClicked(a, b, false); + foundFilterButton.Top.Pixels = top; checklistPanel.Append(foundFilterButton); + left += (int)spacing * 2 + 28; - muteButton = new UIToggleHoverImageButton(Main.itemTexture[ItemID.Megaphone], ItemChecklist.instance.GetTexture("closeButton"), "Toggle Messages", announce); - muteButton.OnClick += ToggleMuteButtonClicked; - muteButton.Left.Pixels = spacing * 2 + 28; - muteButton.Top.Pixels = 4; - checklistPanel.Append(muteButton); + //sortButton = new UIHoverImageButton(sortButtonTexture, "Cycle Sort Method: ??"); + //sortButton.OnClick += (a, b) => ToggleSortButtonClicked(a, b, true); + //sortButton.OnRightClick += (a, b) => ToggleSortButtonClicked(a, b, false); + //sortButton.Left.Pixels = spacing * 4 + 28 * 2; + //sortButton.Top.Pixels = top; + //checklistPanel.Append(sortButton); - sortButton = new UIHoverImageButton(Main.itemTexture[ItemID.ToxicFlask], "Cycle Sort Method: ??"); - sortButton.OnClick += (a, b) => ToggleSortButtonClicked(a, b, true); - sortButton.OnRightClick += (a, b) => ToggleSortButtonClicked(a, b, false); - sortButton.Left.Pixels = spacing * 4 + 28 * 2; - sortButton.Top.Pixels = 4; - checklistPanel.Append(sortButton); - - modFilterButton = new UIHoverImageButton(ItemChecklist.instance.GetTexture("filterMod"), "Cycle Mod Filter: ??"); + modFilterButton = new UIHoverImageButton(Main.magicPixel, "Cycle Mod Filter: ??"); modFilterButton.OnClick += (a, b) => ToggleModFilterButtonClicked(a, b, true); modFilterButton.OnRightClick += (a, b) => ToggleModFilterButtonClicked(a, b, false); - modFilterButton.Left.Pixels = spacing * 6 + 28 * 3; - modFilterButton.Top.Pixels = 4; + modFilterButton.Left.Pixels = left; + modFilterButton.Top.Pixels = top; checklistPanel.Append(modFilterButton); + left += (int)spacing * 2 + 28; - collectChestItemsButton = new UIToggleHoverImageButton(Main.cursorTextures[8], ItemChecklist.instance.GetTexture("closeButton"), "Toggle Collect Chest Items", collectChestItems); + muteButton = new UIToggleHoverImageButton(Main.magicPixel, ItemChecklist.instance.GetTexture("UIElements/closeButton"), "Toggle Messages", announce); + muteButton.OnClick += ToggleMuteButtonClicked; + muteButton.Left.Pixels = left; + muteButton.Top.Pixels = top; + checklistPanel.Append(muteButton); + left += (int)spacing * 2 + 28; + + collectChestItemsButton = new UIToggleHoverImageButton(Main.magicPixel, ItemChecklist.instance.GetTexture("UIElements/closeButton"), "Toggle Collect Chest Items", collectChestItems); collectChestItemsButton.OnClick += ToggleFindChestItemsButtonClicked; - collectChestItemsButton.Left.Pixels = spacing * 8 + 28 * 4; - collectChestItemsButton.Top.Pixels = 4; + collectChestItemsButton.Left.Pixels = left; + collectChestItemsButton.Top.Pixels = top; checklistPanel.Append(collectChestItemsButton); + left += (int)spacing * 2 + 28; + + showBadgeButton = new UIToggleHoverImageButton(Main.magicPixel, ItemChecklist.instance.GetTexture("UIElements/closeButton"), "Show Sort Value Text", showBadge); + showBadgeButton.OnClick += ToggleShowBadgeButtonClicked; + showBadgeButton.Left.Pixels = left; + showBadgeButton.Top.Pixels = top; + checklistPanel.Append(showBadgeButton); + left += (int)spacing * 2 + 28; + + top += 34; + + itemNameFilter = new NewUITextBox("Filter by Name"); + itemNameFilter.OnTextChanged += () => { ValidateItemFilter(); updateNeeded = true; }; + itemNameFilter.OnTabPressed += () => { itemDescriptionFilter.Focus(); }; + itemNameFilter.Top.Pixels = top; + //itemNameFilter.Left.Set(-152, 1f); + itemNameFilter.Width.Set(0, 1f); + itemNameFilter.Height.Set(25, 0f); + checklistPanel.Append(itemNameFilter); + + top += 30; + + itemDescriptionFilter = new NewUITextBox("Filter by tooltip"); + itemDescriptionFilter.OnTextChanged += () => { ValidateItemDescription(); updateNeeded = true; }; + itemDescriptionFilter.OnTabPressed += () => { itemNameFilter.Focus(); }; + itemDescriptionFilter.Top.Pixels = top; + //itemDescriptionFilter.Left.Set(-152, 1f); + itemDescriptionFilter.Width.Set(0, 1f); + itemDescriptionFilter.Height.Set(25, 0f); + checklistPanel.Append(itemDescriptionFilter); + + top += 30; + + sharedUI = new SharedUI(); + sharedUI.Initialize(); + + sharedUI.sortsAndFiltersPanel.Top.Set(top, 0f); + sharedUI.sortsAndFiltersPanel.Width.Set(0f, 1); + sharedUI.sortsAndFiltersPanel.Height.Set(60, 0f); + checklistPanel.Append(sharedUI.sortsAndFiltersPanel); + + top += 68; checklistGrid = new UIGrid(5); - checklistGrid.Top.Pixels = 32f + spacing; + checklistGrid.alternateSort = ItemGridSort; + checklistGrid.Top.Pixels = top; checklistGrid.Width.Set(-25f, 1f); - checklistGrid.Height.Set(-32f, 1f); - checklistGrid.ListPadding = 12f; + checklistGrid.Height.Set(-top, 1f); + checklistGrid.ListPadding = 2f; checklistPanel.Append(checklistGrid); FixedUIScrollbar checklistListScrollbar = new FixedUIScrollbar(); checklistListScrollbar.SetView(100f, 1000f); - checklistListScrollbar.Top.Pixels = 32f + spacing; - checklistListScrollbar.Height.Set(-32f - spacing, 1f); + checklistListScrollbar.Top.Pixels = top; + checklistListScrollbar.Height.Set(-top, 1f); checklistListScrollbar.HAlign = 1f; checklistPanel.Append(checklistListScrollbar); checklistGrid.SetScrollbar(checklistListScrollbar); @@ -105,11 +174,11 @@ namespace ItemChecklist.UI Append(checklistPanel); // load time impact, do this on first show? - itemSlots = new ItemSlot[ItemLoader.ItemCount]; + itemSlots = new UIItemSlot[ItemLoader.ItemCount]; Item[] itemSlotItems = new Item[ItemLoader.ItemCount]; for (int i = 0; i < ItemLoader.ItemCount; i++) { - itemSlots[i] = new ItemSlot(i); + itemSlots[i] = new UIItemSlot(i); itemSlotItems[i] = itemSlots[i].item; } @@ -132,10 +201,19 @@ namespace ItemChecklist.UI vanillaIDsInSortOrder[i] = Array.FindIndex(vanillaIDsInSortOrderTemp, x => x == i); } - modnames = new List() { "All", "Vanilla"}; + modnames = new List() { "All", "Vanilla" }; modnames.AddRange(ModLoader.GetLoadedMods()/*.Where(x => x != "ModLoader")*/); - updateneeded = true; + updateNeeded = true; + } + + private int ItemGridSort(UIElement x, UIElement y) + { + UIItemSlot a = x as UIItemSlot; + UIItemSlot b = y as UIItemSlot; + if (SharedUI.instance.SelectedSort != null) + return SharedUI.instance.SelectedSort.sort(a.item, b.item); + return a.item.type.CompareTo(b.item.type); } private void ToggleFoundFilterButtonClicked(UIMouseEvent evt, UIElement listeningElement, bool left) @@ -153,13 +231,13 @@ namespace ItemChecklist.UI muteButton.SetEnabled(announce); } - private void ToggleSortButtonClicked(UIMouseEvent evt, UIElement listeningElement, bool left) - { - Main.PlaySound(SoundID.MenuTick); - sortMode = left ? sortMode.NextEnum() : sortMode.PreviousEnum(); - sortButton.hoverText = "Cycle Sort Method: " + sortMode.ToFriendlyString(); - UpdateNeeded(); - } + //private void ToggleSortButtonClicked(UIMouseEvent evt, UIElement listeningElement, bool left) + //{ + // Main.PlaySound(SoundID.MenuTick); + // sortMode = left ? sortMode.NextEnum() : sortMode.PreviousEnum(); + // sortButton.hoverText = "Cycle Sort Method: " + sortMode.ToFriendlyString(); + // UpdateNeeded(); + //} private void ToggleModFilterButtonClicked(UIMouseEvent evt, UIElement listeningElement, bool left) { @@ -169,6 +247,13 @@ namespace ItemChecklist.UI UpdateNeeded(); } + private void ToggleShowBadgeButtonClicked(UIMouseEvent evt, UIElement listeningElement) + { + showBadge = !showBadge; + Main.PlaySound(showBadge ? SoundID.MenuOpen : SoundID.MenuClose); + showBadgeButton.SetEnabled(showBadge); + } + private void ToggleFindChestItemsButtonClicked(UIMouseEvent evt, UIElement listeningElement) { collectChestItems = !collectChestItems; @@ -179,18 +264,18 @@ namespace ItemChecklist.UI internal void RefreshPreferences() { foundFilterButton.hoverText = "Cycle Found Filter: " + foundFilterStrings[showCompleted]; - sortButton.hoverText = "Cycle Sort Method: " + sortMode.ToFriendlyString(); + //sortButton.hoverText = "Cycle Sort Method: " + sortMode.ToFriendlyString(); modFilterButton.hoverText = "Cycle Mod Filter: " + modnames[currentMod]; muteButton.SetEnabled(announce); collectChestItemsButton.SetEnabled(collectChestItems); UpdateNeeded(); } - private bool updateneeded; + private bool updateNeeded; private int lastfoundID = -1; internal void UpdateNeeded(int lastfoundID = -1) { - updateneeded = true; + updateNeeded = true; if (lastfoundID > 0) { this.lastfoundID = lastfoundID; @@ -200,12 +285,30 @@ namespace ItemChecklist.UI // todo, items on load. internal void UpdateCheckboxes() { - if (!updateneeded) { return; } - updateneeded = false; + if (!updateNeeded) { return; } + updateNeeded = false; checklistGrid.Clear(); + if (buttonsHaveDummyTextures) + { + Texture2D foundFilterTexture = Utilities.ResizeImage(ItemChecklist.instance.GetTexture("Images/filterFound"), 32, 32); + Texture2D muteButtonTexture = Utilities.ResizeImage(Main.itemTexture[ItemID.Megaphone], 32, 32); + //Texture2D sortButtonTexture = Utilities.ResizeImage(Main.itemTexture[ItemID.ToxicFlask], 32, 32); + Texture2D modFilterButtonTexture = Utilities.ResizeImage(ItemChecklist.instance.GetTexture("Images/filterMod"), 32, 32); + Texture2D collectChestItemsButtonTexture = Utilities.ResizeImage(Main.cursorTextures[8], 32, 32); + Texture2D showBadgeButtonTexture = Utilities.ResizeImage(Main.itemTexture[ItemID.Book], 32, 32); // Main.extraTexture[58] + + foundFilterButton.SetImage(foundFilterTexture); + muteButton.SetImage(muteButtonTexture); + modFilterButton.SetImage(modFilterButtonTexture); + collectChestItemsButton.SetImage(collectChestItemsButtonTexture); + showBadgeButton.SetImage(showBadgeButtonTexture); + + buttonsHaveDummyTextures = false; + } + var itemChecklistPlayer = Main.LocalPlayer.GetModPlayer(ItemChecklist.instance); - var temp = new List(); + var temp = new List(); for (int i = 0; i < itemChecklistPlayer.findableItems.Length; i++) { if (itemChecklistPlayer.findableItems[i]) @@ -213,11 +316,42 @@ namespace ItemChecklist.UI // filters here if ((showCompleted != 1 && itemChecklistPlayer.foundItem[i]) || (showCompleted != 2 && !itemChecklistPlayer.foundItem[i])) { - if (PassModFilter(itemSlots[i])) + if (!PassModFilter(itemSlots[i])) + continue; + + if (SharedUI.instance.SelectedCategory != null) { - ItemSlot box = itemSlots[i]; - temp.Add(box); + if (!SharedUI.instance.SelectedCategory.belongs(itemSlots[i].item) && !SharedUI.instance.SelectedCategory.subCategories.Any(x => x.belongs(itemSlots[i].item))) + continue; } + + bool filtered = false; + foreach (var filter in SharedUI.instance.availableFilters) + { + if (filter.button.selected) + if (!filter.belongs(itemSlots[i].item)) + filtered = true; + } + if (filtered) + continue; + + if (itemSlots[i].item.Name.IndexOf(itemNameFilter.currentString, StringComparison.OrdinalIgnoreCase) == -1) + continue; + + if (itemDescriptionFilter.currentString.Length > 0) + { + if ((itemSlots[i].item.ToolTip != null && GetTooltipsAsString(itemSlots[i].item.ToolTip).IndexOf(itemDescriptionFilter.currentString, StringComparison.OrdinalIgnoreCase) != -1) /*|| (recipe.createItem.toolTip2 != null && recipe.createItem.toolTip2.ToLower().IndexOf(itemDescriptionFilter.Text, StringComparison.OrdinalIgnoreCase) != -1)*/) + { + } + else + { + continue; + } + } + + UIItemSlot box = itemSlots[i]; + box.badge = SharedUI.instance.SelectedSort?.badge(box.item) ?? ""; + temp.Add(box); } } } @@ -230,7 +364,7 @@ namespace ItemChecklist.UI { checklistGrid.Goto(delegate (UIElement element) { - ItemSlot itemSlot = element as ItemSlot; + UIItemSlot itemSlot = element as UIItemSlot; return itemSlot != null && itemSlot.id == lastfoundID; }, true); } @@ -238,9 +372,9 @@ namespace ItemChecklist.UI } } - private bool PassModFilter(ItemSlot itemSlot) + private bool PassModFilter(UIItemSlot itemSlot) { - if(currentMod == 0) + if (currentMod == 0) { return true; } @@ -255,9 +389,34 @@ namespace ItemChecklist.UI return false; } + private void ValidateItemFilter() + { + if (itemNameFilter.currentString.Length > 0) + { + bool found = false; + foreach (var itemSlot in itemSlots) + { + if (itemSlot.item.Name.IndexOf(itemNameFilter.currentString, StringComparison.OrdinalIgnoreCase) != -1) + { + found = true; + break; + } + } + if (!found) + { + itemNameFilter.SetText(itemNameFilter.currentString.Substring(0, itemNameFilter.currentString.Length - 1)); + } + } + updateNeeded = true; + } + + private void ValidateItemDescription() + { + updateNeeded = true; + } + protected override void DrawSelf(SpriteBatch spriteBatch) { - UpdateCheckboxes(); ItemChecklistUI.hoverText = ""; Vector2 MousePosition = new Vector2((float)Main.mouseX, (float)Main.mouseY); if (checklistPanel.ContainsPoint(MousePosition)) @@ -265,16 +424,39 @@ namespace ItemChecklist.UI Main.player[Main.myPlayer].mouseInterface = true; } } + + public override void Update(GameTime gameTime) + { + base.Update(gameTime); + + sharedUI.Update(); + UpdateCheckboxes(); + } + + private string GetTooltipsAsString(ItemTooltip toolTip) + { + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < toolTip.Lines; j++) + { + sb.Append(toolTip.GetLine(j) + "\n"); + } + return sb.ToString().ToLower(); + } + + internal static void OnScrollWheel_FixHotbarScroll(UIScrollWheelEvent evt, UIElement listeningElement) + { + Main.LocalPlayer.ScrollHotbar(Terraria.GameInput.PlayerInput.ScrollWheelDelta / 120); + } } - public enum SortModes - { - ID, - Value, - AZ, - Rare, - TerrariaSort, - } + //public enum SortModes + //{ + // ID, + // Value, + // AZ, + // Rare, + // TerrariaSort, + //} public class FixedUIScrollbar : UIScrollbar { @@ -295,24 +477,24 @@ namespace ItemChecklist.UI } } - public static class Extensions - { - public static string ToFriendlyString(this SortModes sortmode) - { - switch (sortmode) - { - case SortModes.AZ: - return "Alphabetically"; - case SortModes.ID: - return "ID"; - case SortModes.Value: - return "Value"; - case SortModes.Rare: - return "Rarity"; - case SortModes.TerrariaSort: - return "Terraria Sort"; - } - return "Unknown Sort"; - } - } + //public static class Extensions + //{ + // public static string ToFriendlyString(this SortModes sortmode) + // { + // switch (sortmode) + // { + // case SortModes.AZ: + // return "Alphabetically"; + // case SortModes.ID: + // return "ID"; + // case SortModes.Value: + // return "Value"; + // case SortModes.Rare: + // return "Rarity"; + // case SortModes.TerrariaSort: + // return "Terraria Sort"; + // } + // return "Unknown Sort"; + // } + //} } diff --git a/MagicStorageIntegration.cs b/MagicStorageIntegration.cs index 5c4ac57..01cb7c7 100644 --- a/MagicStorageIntegration.cs +++ b/MagicStorageIntegration.cs @@ -1,5 +1,4 @@ -using System; -using MagicStorage; +using MagicStorage; using MagicStorage.Components; using Terraria; using Terraria.DataStructures; @@ -7,25 +6,57 @@ using Terraria.ModLoader; namespace ItemChecklist { - // autopause? + // This code can be used as an example of weak references. + // The most important part of weak references is remembering to test your mod with the referenced .tmod file deleted and a fresh start of tModLoader. + // If you do not, the mod might crash. + // Here we show a few pitfalls that might cause a TypeInitializationException to be thrown. + // Remember, you have to gate all access to Types and Methods defined in the weakly referenced mod or it will crash. + // All calls to methods in this class by this mod besides Load and Unload are gated with a check to Enabled. static class MagicStorageIntegration { + // Here we store a reference to the MagicStorage Mod instance. We can use it for many things. + // You can call all the Mod methods on it just like we do with our own Mod instance: MagicStorage.ItemType("ShadowDiamond") static Mod MagicStorage; + + // Here we define a bool property to quickly check if MagicStorage is loaded. public static bool Enabled => MagicStorage != null; + // Below is an alternate approach to the Enabled property seen above. + // To make sure an up-to-date version of the referenced mod is being used, usually we write "MagicStorage@0.4.3.1" in build.txt. + // This, however, would throw an error if the 0.4.1 were loaded. + // This approach, with the @0.4.3.1 removed from the weakReferences in build.txt and the Version check added to Enabled below, + // allows older versions of MagicStorage to load alongside this mod even though the integration won't work. + // Usually letting tModLoader handle the version requirement and forcing your users to update their mods is easier and better. + //public static bool Enabled => MagicStorage != null && MagicStorage.Version >= new Version(0, 4, 3, 1); + static Point16 previousStorageAccess = new Point16(-1, -1); - static StorageAccess tile; - //static StorageAccess tile = null; //throws TypeInitializationException + + // Here is an example of using Types in MagicStorage. Note the special approaches that must be made with weak referenced Mods. + //static StorageAccess tile = null; // Assigning a class/static field, even to null, will throw TypeInitializationException + static StorageAccess tile; // Not assigning a field seems to work public static void Load() { MagicStorage = ModLoader.GetMod("MagicStorage"); + if (Enabled) + // tile = null; // Will also crash. Here even though Enabled will be false, the Type of tile will still need to be resolved when this method runs. + Initialize(); // Move that logic into another method to prevent this. + } + + private static void Initialize() + { + tile = new StorageAccess(); // This method will only be called when Enable is true, preventing TypeInitializationException } public static void Unload() { - MagicStorage = null; + MagicStorage = null; // Make sure to null out any references to allow Garbage Collection to work. } + // StoragePlayer and TEStorageHeart are classes in MagicStorage. + // Make sure to extract the .dll from the .tmod and then add them to your .csproj as references. + // As a convention, I rename the .dll file ModName_v1.2.3.4.dll and place them in Mod Sources/Mods/lib. + // I do this for organization and so the .csproj loads properly for others using the GitHub repository. + // Remind contributors to download the referenced mod itself if they wish to build the mod. internal static void FindItemsInStorage() { var storagePlayer = Main.LocalPlayer.GetModPlayer(); diff --git a/SharedUI.cs b/SharedUI.cs new file mode 100644 index 0000000..a93b542 --- /dev/null +++ b/SharedUI.cs @@ -0,0 +1,661 @@ +using ItemChecklist.UIElements; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.Linq; +using Terraria; +using Terraria.GameContent.UI.Elements; +using Terraria.GameContent.UI.States; +using Terraria.ID; +using static ItemChecklist.Utilities; + +// Copied from my Recipe Browser mod. +namespace ItemChecklist +{ + class SharedUI + { + internal static SharedUI instance; + internal bool updateNeeded; + internal List modCategories = new List(); // TODO: copy over call? make it automatic somehow? + internal List modFilters = new List(); // TODO: copy over call? make it automatic somehow? + + internal UIPanel sortsAndFiltersPanel; + internal UIHorizontalGrid categoriesGrid; + internal UIHorizontalGrid subCategorySortsFiltersGrid; + internal InvisibleFixedUIHorizontalScrollbar lootGridScrollbar2; + + private Sort selectedSort; + internal Sort SelectedSort + { + get { return selectedSort; } + set + { + if (selectedSort != value) + { + updateNeeded = true; + ItemChecklistUI.instance.UpdateNeeded(); + } + selectedSort = value; + } + } + + private Category selectedCategory; + internal Category SelectedCategory + { + get { return selectedCategory; } + set + { + if (selectedCategory != value) + { + updateNeeded = true; + ItemChecklistUI.instance.UpdateNeeded(); + } + selectedCategory = value; + if (selectedCategory != null && selectedCategory.sorts.Count > 0) + SelectedSort = selectedCategory.sorts[0]; + else if (selectedCategory != null && selectedCategory.parent != null && selectedCategory.parent.sorts.Count > 0) + SelectedSort = selectedCategory.parent.sorts[0]; + } + } + + public SharedUI() + { + instance = this; + } + + internal void Initialize() + { + // Sorts + // Filters: Categories? + // Craft and Loot Badges as well! + // Hide with alt click? + // show hidden toggle + // Favorite: Only affects sort order? + + sortsAndFiltersPanel = new UIPanel(); + sortsAndFiltersPanel.SetPadding(6); + sortsAndFiltersPanel.Top.Set(0, 0f); + sortsAndFiltersPanel.Width.Set(-275, 1); + sortsAndFiltersPanel.Height.Set(60, 0f); + sortsAndFiltersPanel.BackgroundColor = new Color(73, 94, 221); + //sortsAndFiltersPanel.SetPadding(4); + //mainPanel.Append(sortsAndFiltersPanel); + //additionalDragTargets.Add(sortsAndFiltersPanel); + //SetupSortsAndCategories(); + + //PopulateSortsAndFiltersPanel(); + + updateNeeded = true; + } + + internal void Update() + { + if (!updateNeeded) { return; } + updateNeeded = false; + + // Delay this so we can integrate mod categories. + if (sorts == null) + { + SetupSortsAndCategories(); + } + + PopulateSortsAndFiltersPanel(); + } + + internal List availableFilters; + private void PopulateSortsAndFiltersPanel() + { + var availableSorts = new List(sorts); + availableFilters = new List(filters); + //sortsAndFiltersPanel.RemoveAllChildren(); + if (subCategorySortsFiltersGrid != null) + { + sortsAndFiltersPanel.RemoveChild(subCategorySortsFiltersGrid); + sortsAndFiltersPanel.RemoveChild(lootGridScrollbar2); + } + + bool doTopRow = false; + if (categoriesGrid == null) + { + doTopRow = true; + + categoriesGrid = new UIHorizontalGrid(); + categoriesGrid.Width.Set(0, 1f); + categoriesGrid.Height.Set(26, 0f); + categoriesGrid.ListPadding = 2f; + categoriesGrid.OnScrollWheel += ItemChecklistUI.OnScrollWheel_FixHotbarScroll; + sortsAndFiltersPanel.Append(categoriesGrid); + categoriesGrid.drawArrows = true; + + var lootGridScrollbar = new InvisibleFixedUIHorizontalScrollbar(ItemChecklist.ItemChecklistInterface); + lootGridScrollbar.SetView(100f, 1000f); + lootGridScrollbar.Width.Set(0, 1f); + lootGridScrollbar.Top.Set(0, 0f); + sortsAndFiltersPanel.Append(lootGridScrollbar); + categoriesGrid.SetScrollbar(lootGridScrollbar); + } + + subCategorySortsFiltersGrid = new UIHorizontalGrid(); + subCategorySortsFiltersGrid.Width.Set(0, 1f); + subCategorySortsFiltersGrid.Top.Set(26, 0f); + subCategorySortsFiltersGrid.Height.Set(26, 0f); + subCategorySortsFiltersGrid.ListPadding = 2f; + subCategorySortsFiltersGrid.OnScrollWheel += ItemChecklistUI.OnScrollWheel_FixHotbarScroll; + sortsAndFiltersPanel.Append(subCategorySortsFiltersGrid); + subCategorySortsFiltersGrid.drawArrows = true; + + lootGridScrollbar2 = new InvisibleFixedUIHorizontalScrollbar(ItemChecklist.ItemChecklistInterface); + lootGridScrollbar2.SetView(100f, 1000f); + lootGridScrollbar2.Width.Set(0, 1f); + lootGridScrollbar2.Top.Set(28, 0f); + sortsAndFiltersPanel.Append(lootGridScrollbar2); + subCategorySortsFiltersGrid.SetScrollbar(lootGridScrollbar2); + + //sortsAndFiltersPanelGrid = new UIGrid(); + //sortsAndFiltersPanelGrid.Width.Set(0, 1); + //sortsAndFiltersPanelGrid.Height.Set(0, 1); + //sortsAndFiltersPanel.Append(sortsAndFiltersPanelGrid); + + //sortsAndFiltersPanelGrid2 = new UIGrid(); + //sortsAndFiltersPanelGrid2.Width.Set(0, 1); + //sortsAndFiltersPanelGrid2.Height.Set(0, 1); + //sortsAndFiltersPanel.Append(sortsAndFiltersPanelGrid2); + + int count = 0; + + var visibleCategories = new List(); + var visibleSubCategories = new List(); + int left = 0; + foreach (var category in categories) + { + category.button.selected = false; + visibleCategories.Add(category); + bool meOrChildSelected = SelectedCategory == category; + foreach (var subcategory in category.subCategories) + { + subcategory.button.selected = false; + meOrChildSelected |= subcategory == SelectedCategory; + } + if (meOrChildSelected) + { + visibleSubCategories.AddRange(category.subCategories); + category.button.selected = true; + } + } + + if (doTopRow) + foreach (var category in visibleCategories) + { + var container = new UISortableElement(++count); + container.Width.Set(24, 0); + container.Height.Set(24, 0); + //category.button.Left.Pixels = left; + //if (category.parent != null) + // container.OrderIndex + // category.button.Top.Pixels = 12; + //sortsAndFiltersPanel.Append(category.button); + container.Append(category.button); + categoriesGrid.Add(container); + left += 26; + } + + //UISortableElement spacer = new UISortableElement(++count); + //spacer.Width.Set(0, 1); + //sortsAndFiltersPanelGrid2.Add(spacer); + + foreach (var category in visibleSubCategories) + { + var container = new UISortableElement(++count); + container.Width.Set(24, 0); + container.Height.Set(24, 0); + container.Append(category.button); + subCategorySortsFiltersGrid.Add(container); + left += 26; + } + + if (visibleSubCategories.Count > 0) + { + var container2 = new UISortableElement(++count); + container2.Width.Set(24, 0); + container2.Height.Set(24, 0); + var image = new UIImage(ItemChecklist.instance.GetTexture("UIElements/spacer")); + //image.Left.Set(6, 0); + image.HAlign = 0.5f; + container2.Append(image); + subCategorySortsFiltersGrid.Add(container2); + } + + // add to sorts here + if (SelectedCategory != null) + { + SelectedCategory.button.selected = true; + SelectedCategory.ParentAddToSorts(availableSorts); + } + + left = 0; + foreach (var sort in availableSorts) + { + sort.button.selected = false; + if (SelectedSort == sort) // TODO: SelectedSort no longwe valid + sort.button.selected = true; + //sort.button.Left.Pixels = left; + //sort.button.Top.Pixels = 24; + //sort.button.Width + //grid.Add(sort.button); + var container = new UISortableElement(++count); + container.Width.Set(24, 0); + container.Height.Set(24, 0); + container.Append(sort.button); + subCategorySortsFiltersGrid.Add(container); + //sortsAndFiltersPanel.Append(sort.button); + left += 26; + } + if (!availableSorts.Contains(SharedUI.instance.SelectedSort)) + { + availableSorts[0].button.selected = true; + SharedUI.instance.SelectedSort = availableSorts[0]; + updateNeeded = false; + } + + if (SharedUI.instance.filters.Count > 0) + { + var container2 = new UISortableElement(++count); + container2.Width.Set(24, 0); + container2.Height.Set(24, 0); + var image = new UIImage(ItemChecklist.instance.GetTexture("UIElements/spacer")); + image.HAlign = 0.5f; + container2.Append(image); + subCategorySortsFiltersGrid.Add(container2); + + foreach (var item in SharedUI.instance.filters) + { + var container = new UISortableElement(++count); + container.Width.Set(24, 0); + container.Height.Set(24, 0); + container.Append(item.button); + subCategorySortsFiltersGrid.Add(container); + } + } + } + + internal List categories; + internal List filters; + internal List sorts; + internal List craftingTiles; + private void SetupSortsAndCategories() + { + var tileUsageCounts = new Dictionary(); + int currentCount; + for (int i = 0; i < Recipe.numRecipes; i++) + { + for (int j = 0; j < 15; j++) + { + if (Main.recipe[i].requiredTile[j] == -1) + break; + tileUsageCounts.TryGetValue(Main.recipe[i].requiredTile[j], out currentCount); + tileUsageCounts[Main.recipe[i].requiredTile[j]] = currentCount + 1; + } + } + craftingTiles = tileUsageCounts.Select(x => x.Key).ToList(); + + Texture2D terrariaSort = ResizeImage(Main.inventorySortTexture[1], 24, 24); + Texture2D rarity = ResizeImage(Main.itemTexture[ItemID.MetalDetector], 24, 24); + + sorts = new List() + { + new Sort("ItemID", "Images/sortItemID", (x,y)=>x.type.CompareTo(y.type), x=>x.type.ToString()), + new Sort("Value", "Images/sortValue", (x,y)=>x.value.CompareTo(y.value), x=>x.value.ToString()), + new Sort("Alphabetical", "Images/sortAZ", (x,y)=>x.Name.CompareTo(y.Name), x=>x.Name.ToString()), + new Sort("Rarity", rarity, (x,y)=> x.rare==y.rare ? x.value.CompareTo(y.value) : Math.Abs(x.rare).CompareTo(Math.Abs(y.rare)), x=>x.rare.ToString()), + new Sort("Terraria Sort", terrariaSort, (x,y)=> -ItemChecklistUI.vanillaIDsInSortOrder[x.type].CompareTo(ItemChecklistUI.vanillaIDsInSortOrder[y.type]), x=>ItemChecklistUI.vanillaIDsInSortOrder[x.type].ToString()), + }; + + Texture2D materialsIcon = Utilities.StackResizeImage(new Texture2D[] { Main.itemTexture[ItemID.SpellTome] }, 24, 24); + filters = new List() + { + new Filter("Materials", x=>ItemID.Sets.IsAMaterial[x.type], materialsIcon), + }; + + // TODOS: Vanity armor, grapple, cart, potions buffs + // 24x24 pixels + + List yoyos = new List(); + for (int i = 0; i < ItemID.Sets.Yoyo.Length; ++i) + { + if (ItemID.Sets.Yoyo[i]) + { + yoyos.Add(i); + } + } + + Texture2D smallMelee = ResizeImage(Main.itemTexture[ItemID.GoldBroadsword], 24, 24); + Texture2D smallYoyo = ResizeImage(Main.itemTexture[Main.rand.Next(yoyos)], 24, 24); //Main.rand.Next(ItemID.Sets.Yoyo) ItemID.Yelets + Texture2D smallMagic = ResizeImage(Main.itemTexture[ItemID.GoldenShower], 24, 24); + Texture2D smallRanged = ResizeImage(Main.itemTexture[ItemID.FlintlockPistol], 24, 24); + Texture2D smallThrown = ResizeImage(Main.itemTexture[ItemID.Shuriken], 24, 24); + Texture2D smallSummon = ResizeImage(Main.itemTexture[ItemID.SlimeStaff], 24, 24); + Texture2D smallSentry = ResizeImage(Main.itemTexture[ItemID.DD2LightningAuraT1Popper], 24, 24); + Texture2D smallHead = ResizeImage(Main.itemTexture[ItemID.SilverHelmet], 24, 24); + Texture2D smallBody = ResizeImage(Main.itemTexture[ItemID.SilverChainmail], 24, 24); + Texture2D smallLegs = ResizeImage(Main.itemTexture[ItemID.SilverGreaves], 24, 24); + Texture2D smallTiles = ResizeImage(Main.itemTexture[ItemID.Sign], 24, 24); + Texture2D smallCraftingStation = ResizeImage(Main.itemTexture[ItemID.IronAnvil], 24, 24); + Texture2D smallWalls = ResizeImage(Main.itemTexture[ItemID.PearlstoneBrickWall], 24, 24); + Texture2D smallExpert = ResizeImage(Main.itemTexture[ItemID.EoCShield], 24, 24); + Texture2D smallPets = ResizeImage(Main.itemTexture[ItemID.ZephyrFish], 24, 24); + Texture2D smallLightPets = ResizeImage(Main.itemTexture[ItemID.FairyBell], 24, 24); + Texture2D smallBossSummon = ResizeImage(Main.itemTexture[ItemID.MechanicalSkull], 24, 24); + Texture2D smallMounts = ResizeImage(Main.itemTexture[ItemID.SlimySaddle], 24, 24); + Texture2D smallDyes = ResizeImage(Main.itemTexture[ItemID.OrangeDye], 24, 24); + Texture2D smallHairDye = ResizeImage(Main.itemTexture[ItemID.BiomeHairDye], 24, 24); + Texture2D smallQuestFish = ResizeImage(Main.itemTexture[ItemID.FallenStarfish], 24, 24); + Texture2D smallAccessories = ResizeImage(Main.itemTexture[ItemID.HermesBoots], 24, 24); + Texture2D smallWings = ResizeImage(Main.itemTexture[ItemID.LeafWings], 24, 24); + Texture2D smallCarts = ResizeImage(Main.itemTexture[ItemID.Minecart], 24, 24); + Texture2D smallHealth = ResizeImage(Main.itemTexture[ItemID.HealingPotion], 24, 24); + Texture2D smallMana = ResizeImage(Main.itemTexture[ItemID.ManaPotion], 24, 24); + Texture2D smallBuff = ResizeImage(Main.itemTexture[ItemID.RagePotion], 24, 24); + Texture2D smallAll = ResizeImage(Main.itemTexture[ItemID.AlphabetStatueA], 24, 24); + Texture2D smallContainer = ResizeImage(Main.itemTexture[ItemID.GoldChest], 24, 24); + Texture2D smallPaintings = ResizeImage(Main.itemTexture[ItemID.PaintingMartiaLisa], 24, 24); + Texture2D smallStatue = ResizeImage(Main.itemTexture[ItemID.HeartStatue], 24, 24); + Texture2D smallWiring = ResizeImage(Main.itemTexture[ItemID.Wire], 24, 24); + Texture2D smallConsumables = ResizeImage(Main.itemTexture[ItemID.PurificationPowder], 24, 24); + Texture2D smallExtractinator = ResizeImage(Main.itemTexture[ItemID.Extractinator], 24, 24); + Texture2D smallOther = ResizeImage(Main.itemTexture[ItemID.UnicornonaStick], 24, 24); + + Texture2D smallArmor = StackResizeImage(new Texture2D[] { Main.itemTexture[ItemID.SilverHelmet], Main.itemTexture[ItemID.SilverChainmail], Main.itemTexture[ItemID.SilverGreaves] }, 24, 24); + Texture2D smallPetsLightPets = StackResizeImage(new Texture2D[] { Main.itemTexture[ItemID.ZephyrFish], Main.itemTexture[ItemID.FairyBell] }, 24, 24); + Texture2D smallPlaceables = StackResizeImage(new Texture2D[] { Main.itemTexture[ItemID.Sign], Main.itemTexture[ItemID.PearlstoneBrickWall] }, 24, 24); + Texture2D smallWeapons = StackResizeImage(new Texture2D[] { smallMelee, smallMagic, smallThrown }, 24, 24); + Texture2D smallTools = StackResizeImage(new Texture2D[] { ItemChecklist.instance.GetTexture("Images/sortPick"), ItemChecklist.instance.GetTexture("Images/sortAxe"), ItemChecklist.instance.GetTexture("Images/sortHammer") }, 24, 24); + Texture2D smallFishing = StackResizeImage(new Texture2D[] { ItemChecklist.instance.GetTexture("Images/sortFish"), ItemChecklist.instance.GetTexture("Images/sortBait"), Main.itemTexture[ItemID.FallenStarfish] }, 24, 24); + Texture2D smallPotions = StackResizeImage(new Texture2D[] { Main.itemTexture[ItemID.HealingPotion], Main.itemTexture[ItemID.ManaPotion], Main.itemTexture[ItemID.RagePotion] }, 24, 24); + Texture2D smallBothDyes = StackResizeImage(new Texture2D[] { Main.itemTexture[ItemID.OrangeDye], Main.itemTexture[ItemID.BiomeHairDye] }, 24, 24); + Texture2D smallSortTiles = StackResizeImage(new Texture2D[] { Main.itemTexture[ItemID.Candelabra], Main.itemTexture[ItemID.GrandfatherClock] }, 24, 24); + + // Potions, other? + // should inherit children? + // should have other category? + if (WorldGen.statueList == null) + WorldGen.SetupStatueList(); + + categories = new List() { + new Category("All", x=> true, smallAll), + new Category("Weapons"/*, x=>x.damage>0*/, x=> false, smallWeapons) { //"Images/sortDamage" + subCategories = new List() { + new Category("Melee", x=>x.melee, smallMelee), + new Category("Yoyo", x=>ItemID.Sets.Yoyo[x.type], smallYoyo), + new Category("Magic", x=>x.magic, smallMagic), + new Category("Ranged", x=>x.ranged && x.ammo == 0, smallRanged) // TODO and ammo no + { + sorts = new List() { new Sort("Use Ammo Type", "Images/sortAmmo", (x,y)=>x.useAmmo.CompareTo(y.useAmmo), x => x.useAmmo.ToString()), } + }, + new Category("Throwing", x=>x.thrown, smallThrown), + new Category("Summon", x=>x.summon && !x.sentry, smallSummon), + new Category("Sentry", x=>x.summon && x.sentry, smallSentry), + }, + sorts = new List() { new Sort("Damage", "Images/sortDamage", (x,y)=>x.damage.CompareTo(y.damage), x => x.damage.ToString()), } // ascending + }, + new Category("Tools"/*,x=>x.pick>0||x.axe>0||x.hammer>0*/, x=>false, smallTools) { + subCategories = new List() { + new Category("Pickaxes", x=>x.pick>0, "Images/sortPick") { sorts = new List() { new Sort("Pick Power", "Images/sortPick", (x,y)=>x.pick.CompareTo(y.pick), x => x.pick.ToString()), } }, + new Category("Axes", x=>x.axe>0, "Images/sortAxe"){ sorts = new List() { new Sort("Axe Power", "Images/sortAxe", (x,y)=>x.axe.CompareTo(y.axe), x => (x.axe*5).ToString()), } }, + new Category("Hammers", x=>x.hammer>0, "Images/sortHammer"){ sorts = new List() { new Sort("Hammer Power", "Images/sortHammer", (x,y)=>x.hammer.CompareTo(y.hammer), x => x.hammer.ToString()), } }, + }, + }, + new Category("Armor"/*, x=>x.headSlot!=-1||x.bodySlot!=-1||x.legSlot!=-1*/, x => false, smallArmor) { + subCategories = new List() { + new Category("Head", x=>x.headSlot!=-1, smallHead), + new Category("Body", x=>x.bodySlot!=-1, smallBody), + new Category("Legs", x=>x.legSlot!=-1, smallLegs), + }, + sorts = new List() { new Sort("Defense", "Images/sortDefense", (x,y)=>x.defense.CompareTo(y.defense), x => x.defense.ToString()), } + }, + new Category("Tiles", x=>x.createTile!=-1, smallTiles) + { + subCategories = new List() + { + new Category("Crafting Stations", x=>craftingTiles.Contains(x.createTile), smallCraftingStation), + new Category("Containers", x=>x.createTile!=-1 && Main.tileContainer[x.createTile], smallContainer), + new Category("Wiring", x=>ItemID.Sets.SortingPriorityWiring[x.type] > -1, smallWiring), + new Category("Statues", x=>WorldGen.statueList.Any(point => point.X == x.createTile && point.Y == x.placeStyle), smallStatue), + //new Category("Paintings", x=>ItemID.Sets.SortingPriorityPainting[x.type] > -1, smallPaintings), // oops, this is painting tools not painting tiles + //new Category("5x4", x=>{ + // if(x.createTile!=-1) + // { + // var tod = Terraria.ObjectData.TileObjectData.GetTileData(x.createTile, x.placeStyle); + // return tod != null && tod.Width == 5 && tod.Height == 4; + // } + // return false; + //} , smallContainer), + }, + // wires + + // Banners + sorts = new List() { + new Sort("Place Tile", smallSortTiles, (x,y)=> x.createTile == y.createTile ? x.placeStyle.CompareTo(y.placeStyle) : x.createTile.CompareTo(y.createTile), x=>$"{x.createTile},{x.placeStyle}"), + } + }, + new Category("Walls", x=>x.createWall!=-1, smallWalls), + new Category("Accessories", x=>x.accessory, smallAccessories) + { + subCategories = new List() + { + new Category("Wings", x=>x.wingSlot > 0, smallWings) + } + }, + new Category("Ammo", x=>x.ammo!=0, ItemChecklist.instance.GetTexture("Images/sortAmmo")) + { + sorts = new List() { new Sort("Ammo Type", "Images/sortAmmo", (x,y)=>x.ammo.CompareTo(y.ammo), x => $"{x.ammo}"), } + // TODO: Filters/Subcategories for all ammo types? + }, + new Category("Potions", x=>(x.UseSound != null && x.UseSound.Style == 3), smallPotions) + { + subCategories = new List() { + new Category("Health Potions", x=>x.healLife > 0, smallHealth) { sorts = new List() { new Sort("Heal Life", smallHealth, (x,y)=>x.healLife.CompareTo(y.healLife), x => $"{x.healLife}"), } }, + new Category("Mana Potions", x=>x.healMana > 0, smallMana) { sorts = new List() { new Sort("Heal Mana", smallMana, (x,y)=>x.healMana.CompareTo(y.healMana), x => $"{x.healMana}"), }}, + new Category("Buff Potions", x=>(x.UseSound != null && x.UseSound.Style == 3) && x.buffType > 0, smallBuff), + // Todo: Automatic other category? + } + }, + new Category("Expert", x=>x.expert, smallExpert), + new Category("Pets"/*, x=> x.buffType > 0 && (Main.vanityPet[x.buffType] || Main.lightPet[x.buffType])*/, x=>false, smallPetsLightPets){ + subCategories = new List() { + new Category("Pets", x=>Main.vanityPet[x.buffType], smallPets), + new Category("Light Pets", x=>Main.lightPet[x.buffType], smallLightPets), + } + }, + new Category("Mounts", x=>x.mountType != -1, smallMounts) + { + subCategories = new List() + { + new Category("Carts", x=>x.mountType != -1 && MountID.Sets.Cart[x.mountType], smallCarts) // TODO: need mountType check? inherited parent logic or parent unions children? + } + }, + new Category("Dyes", x=>false, smallBothDyes) + { + subCategories = new List() + { + new Category("Dyes", x=>x.dye != 0, smallDyes), + new Category("Hair Dyes", x=>x.hairDye != -1, smallHairDye), + } + }, + new Category("Boss Summons", x=>ItemID.Sets.SortingPriorityBossSpawns[x.type] != -1 && x.type != ItemID.LifeCrystal && x.type != ItemID.ManaCrystal && x.type != ItemID.CellPhone && x.type != ItemID.IceMirror && x.type != ItemID.MagicMirror && x.type != ItemID.LifeFruit && x.netID != ItemID.TreasureMap || x.netID == ItemID.PirateMap, smallBossSummon) { // vanilla bug. + sorts = new List() { new Sort("Progression Order", "Images/sortDamage", (x,y)=>ItemID.Sets.SortingPriorityBossSpawns[x.type].CompareTo(ItemID.Sets.SortingPriorityBossSpawns[y.type]), x => $"{ItemID.Sets.SortingPriorityBossSpawns[x.type]}"), } + }, + new Category("Consumables", x=>x.consumable, smallConsumables), + new Category("Fishing"/*, x=> x.fishingPole > 0 || x.bait>0|| x.questItem*/, x=>false, smallFishing){ + subCategories = new List() { + new Category("Poles", x=>x.fishingPole > 0, "Images/sortFish") {sorts = new List() { new Sort("Pole Power", "Images/sortFish", (x,y)=>x.fishingPole.CompareTo(y.fishingPole), x => $"{x.fishingPole}"), } }, + new Category("Bait", x=>x.bait>0, "Images/sortBait") {sorts = new List() { new Sort("Bait Power", "Images/sortBait", (x,y)=>x.bait.CompareTo(y.bait), x => $"{x.bait}"), } }, + new Category("Quest Fish", x=>x.questItem, smallQuestFish), + } + }, + new Category("Extractinator", x=>ItemID.Sets.ExtractinatorMode[x.type] > -1, smallExtractinator), + //modCategory, + new Category("Other", x=>BelongsInOther(x), smallOther), + }; + + /* Think about this one. + foreach (var modCategory in RecipeBrowser.instance.modCategories) + { + if (string.IsNullOrEmpty(modCategory.parent)) + { + categories.Insert(categories.Count - 2, new Category(modCategory.name, modCategory.belongs, modCategory.icon)); + } + else + { + foreach (var item in categories) + { + if (item.name == modCategory.parent) + { + item.subCategories.Add(new Category(modCategory.name, modCategory.belongs, modCategory.icon)); + } + } + } + } + + foreach (var modCategory in RecipeBrowser.instance.modFilters) + { + filters.Add(new Filter(modCategory.name, modCategory.belongs, modCategory.icon)); + } + */ + + foreach (var parent in categories) + { + foreach (var child in parent.subCategories) + { + child.parent = parent; // 3 levels? + } + } + + SelectedSort = sorts[0]; + SelectedCategory = categories[0]; + } + + private bool BelongsInOther(Item item) + { + var cats = categories.Skip(1).Take(categories.Count - 2); + foreach (var category in cats) + { + if (category.BelongsRecursive(item)) + return false; + } + return true; + } + } + + internal class Filter + { + internal string name; + internal Predicate belongs; + internal List subCategories; // + internal List sorts; + internal UISilentImageButton button; + internal Category parent; + + public Filter(string name, Predicate belongs, Texture2D texture) + { + this.name = name; + subCategories = new List(); + sorts = new List(); + this.belongs = belongs; + + this.button = new UISilentImageButton(texture, name); + button.OnClick += (a, b) => + { + button.selected = !button.selected; + ItemChecklistUI.instance.UpdateNeeded(); + //Main.NewText("clicked on " + button.hoverText); + }; + } + } + + internal class Sort + { + internal Func sort; + internal Func badge; + internal UISilentImageButton button; + + public Sort(string hoverText, Texture2D texture, Func sort, Func badge) + { + this.sort = sort; + this.badge = badge; + button = new UISilentImageButton(texture, hoverText); + button.OnClick += (a, b) => + { + SharedUI.instance.SelectedSort = this; + }; + } + + public Sort(string hoverText, string textureFileName, Func sort, Func badge) : this(hoverText, ItemChecklist.instance.GetTexture(textureFileName), sort, badge) + { + } + } + + // Represents a requested Category or Filter. + internal class ModCategory + { + internal string name; + internal string parent; + internal Texture2D icon; + internal Predicate belongs; + public ModCategory(string name, string parent, Texture2D icon, Predicate belongs) + { + this.name = name; + this.parent = parent; + this.icon = icon; + this.belongs = belongs; + } + } + + // Can belong to 2 Category? -> ?? + // Separate filter? => yes, but Separate conditional filters? + // All children belong to parent -> yes. + internal class Category // Filter + { + internal string name; + internal Predicate belongs; + internal List subCategories; + internal List sorts; + internal UISilentImageButton button; + internal Category parent; + + public Category(string name, Predicate belongs, Texture2D texture = null) + { + if (texture == null) + texture = ItemChecklist.instance.GetTexture("Images/sortAmmo"); + this.name = name; + subCategories = new List(); + sorts = new List(); + this.belongs = belongs; + + this.button = new UISilentImageButton(texture, name); + button.OnClick += (a, b) => + { + //Main.NewText("clicked on " + button.hoverText); + SharedUI.instance.SelectedCategory = this; + }; + } + + public Category(string name, Predicate belongs, string textureFileName) : this(name, belongs, ItemChecklist.instance.GetTexture(textureFileName)) + { + } + + internal bool BelongsRecursive(Item item) + { + if (belongs(item)) + return true; + return subCategories.Any(x => x.belongs(item)); + } + + internal void ParentAddToSorts(List availableSorts) + { + if (parent != null) + parent.ParentAddToSorts(availableSorts); + availableSorts.AddRange(sorts); + } + } +} diff --git a/UIElements/MoreLeft.png b/UIElements/MoreLeft.png new file mode 100644 index 0000000..80da7d1 Binary files /dev/null and b/UIElements/MoreLeft.png differ diff --git a/UIElements/MoreRight.png b/UIElements/MoreRight.png new file mode 100644 index 0000000..4da2cc7 Binary files /dev/null and b/UIElements/MoreRight.png differ diff --git a/UIElements/NewUITextBox.cs b/UIElements/NewUITextBox.cs new file mode 100644 index 0000000..93b435e --- /dev/null +++ b/UIElements/NewUITextBox.cs @@ -0,0 +1,332 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using ReLogic.Graphics; +using System; +using Terraria; +using Terraria.GameContent.UI.Elements; +using Terraria.UI; + +namespace ItemChecklist.UIElements +{ + internal class NewUITextBox : UIPanel//UITextPanel + { + internal bool focused = false; + + //private int _cursor; + //private int _frameCount; + private int _maxLength = 60; + + private string hintText; + internal string currentString = ""; + private int textBlinkerCount; + private int textBlinkerState; + + public event Action OnFocus; + + public event Action OnUnfocus; + + public event Action OnTextChanged; + + public event Action OnTabPressed; + + public event Action OnEnterPressed; + + //public event Action OnUpPressed; + internal bool unfocusOnEnter = true; + + internal bool unfocusOnTab = true; + + //public NewUITextBox(string text, float textScale = 1, bool large = false) : base("", textScale, large) + public NewUITextBox(string hintText, string text = "") + { + this.hintText = hintText; + currentString = text; + SetPadding(0); + BackgroundColor = Color.White; + BorderColor = Color.White; + // keyBoardInput.newKeyEvent += KeyboardInput_newKeyEvent; + + Texture2D texture = ItemChecklist.instance.GetTexture("UIElements/closeButtonSmallWhite"); + var closeButton = new UIHoverImageButton(texture, ""); + closeButton.OnClick += (a, b) => SetText(""); + closeButton.Left.Set(-20f, 1f); + //closeButton.Top.Set(0f, .5f); + closeButton.VAlign = 0.5f; + //closeButton.HAlign = 0.5f; + Append(closeButton); + } + + public override void Click(UIMouseEvent evt) + { + Focus(); + base.Click(evt); + } + + public override void RightClick(UIMouseEvent evt) + { + base.RightClick(evt); + SetText(""); + } + + public void SetUnfocusKeys(bool unfocusOnEnter, bool unfocusOnTab) + { + this.unfocusOnEnter = unfocusOnEnter; + this.unfocusOnTab = unfocusOnTab; + } + + //void KeyboardInput_newKeyEvent(char obj) + //{ + // // Problem: keyBoardInput.newKeyEvent only fires on regular keyboard buttons. + + // if (!focused) return; + // if (obj.Equals((char)Keys.Back)) // '\b' + // { + // Backspace(); + // } + // else if (obj.Equals((char)Keys.Enter)) + // { + // Unfocus(); + // Main.chatRelease = false; + // } + // else if (Char.IsLetterOrDigit(obj)) + // { + // Write(obj.ToString()); + // } + //} + + public void Unfocus() + { + if (focused) + { + focused = false; + Main.blockInput = false; + + OnUnfocus?.Invoke(); + } + } + + public void Focus() + { + if (!focused) + { + Main.clrInput(); + focused = true; + Main.blockInput = true; + + OnFocus?.Invoke(); + } + } + + public override void Update(GameTime gameTime) + { + Vector2 MousePosition = new Vector2((float)Main.mouseX, (float)Main.mouseY); + if (!ContainsPoint(MousePosition) && Main.mouseLeft) + { + // TODO, figure out how to refocus without triggering unfocus while clicking enable button. + Unfocus(); + } + base.Update(gameTime); + } + + //public void Write(string text) + //{ + // base.SetText(base.Text.Insert(this._cursor, text)); + // this._cursor += text.Length; + // _cursor = Math.Min(Text.Length, _cursor); + // Recalculate(); + + // OnTextChanged?.Invoke(); + //} + + //public void WriteAll(string text) + //{ + // bool changed = text != Text; + // if (!changed) return; + // base.SetText(text); + // this._cursor = text.Length; + // //_cursor = Math.Min(Text.Length, _cursor); + // Recalculate(); + + // if (changed) + // { + // OnTextChanged?.Invoke(); + // } + //} + + public void SetText(string text) + { + if (text.ToString().Length > this._maxLength) + { + text = text.ToString().Substring(0, this._maxLength); + } + if (currentString != text) + { + currentString = text; + OnTextChanged?.Invoke(); + } + } + + public void SetTextMaxLength(int maxLength) + { + this._maxLength = maxLength; + } + + //public void Backspace() + //{ + // if (this._cursor == 0) + // { + // return; + // } + // base.SetText(base.Text.Substring(0, base.Text.Length - 1)); + // Recalculate(); + //} + + /*public void CursorLeft() + { + if (this._cursor == 0) + { + return; + } + this._cursor--; + } + + public void CursorRight() + { + if (this._cursor < base.Text.Length) + { + this._cursor++; + } + }*/ + + private static bool JustPressed(Keys key) + { + return Main.inputText.IsKeyDown(key) && !Main.oldInputText.IsKeyDown(key); + } + + protected override void DrawSelf(SpriteBatch spriteBatch) + { + Rectangle hitbox = GetInnerDimensions().ToRectangle(); + + // Draw panel + base.DrawSelf(spriteBatch); + // Main.spriteBatch.Draw(Main.magicPixel, hitbox, Color.Yellow); + + if (focused) + { + Terraria.GameInput.PlayerInput.WritingText = true; + Main.instance.HandleIME(); + string newString = Main.GetInputText(currentString); + if (!newString.Equals(currentString)) + { + currentString = newString; + OnTextChanged?.Invoke(); + } + else + { + currentString = newString; + } + + if (JustPressed(Keys.Tab)) + { + if (unfocusOnTab) Unfocus(); + OnTabPressed?.Invoke(); + } + if (JustPressed(Keys.Enter)) + { + Main.drawingPlayerChat = false; + if (unfocusOnEnter) Unfocus(); + OnEnterPressed?.Invoke(); + } + if (++textBlinkerCount >= 20) + { + textBlinkerState = (textBlinkerState + 1) % 2; + textBlinkerCount = 0; + } + Main.instance.DrawWindowsIMEPanel(new Vector2(98f, (float)(Main.screenHeight - 36)), 0f); + } + string displayString = currentString; + if (this.textBlinkerState == 1 && focused) + { + displayString = displayString + "|"; + } + CalculatedStyle space = base.GetDimensions(); + Color color = Color.Black; + if (currentString.Length == 0) + { + } + Vector2 drawPos = space.Position() + new Vector2(4, 2); + if (currentString.Length == 0 && !focused) + { + color *= 0.5f; + //Utils.DrawBorderString(spriteBatch, hintText, new Vector2(space.X, space.Y), Color.Gray, 1f); + spriteBatch.DrawString(Main.fontMouseText, hintText, drawPos, color); + } + else + { + //Utils.DrawBorderString(spriteBatch, displayString, drawPos, Color.White, 1f); + spriteBatch.DrawString(Main.fontMouseText, displayString, drawPos, color); + } + + // CalculatedStyle innerDimensions2 = base.GetInnerDimensions(); + // Vector2 pos2 = innerDimensions2.Position(); + // if (IsLarge) + // { + // pos2.Y -= 10f * TextScale * TextScale; + // } + // else + // { + // pos2.Y -= 2f * TextScale; + // } + // //pos2.X += (innerDimensions2.Width - TextSize.X) * 0.5f; + // if (IsLarge) + // { + // Utils.DrawBorderStringBig(spriteBatch, Text, pos2, TextColor, TextScale, 0f, 0f, -1); + // return; + // } + // Utils.DrawBorderString(spriteBatch, Text, pos2, TextColor, TextScale, 0f, 0f, -1); + // + // this._frameCount++; + // + // CalculatedStyle innerDimensions = base.GetInnerDimensions(); + // Vector2 pos = innerDimensions.Position(); + // DynamicSpriteFont spriteFont = base.IsLarge ? Main.fontDeathText : Main.fontMouseText; + // Vector2 vector = new Vector2(spriteFont.MeasureString(base.Text.Substring(0, this._cursor)).X, base.IsLarge ? 32f : 16f) * base.TextScale; + // if (base.IsLarge) + // { + // pos.Y -= 8f * base.TextScale; + // } + // else + // { + // pos.Y -= 1f * base.TextScale; + // } + // if (Text.Length == 0) + // { + // Vector2 hintTextSize = new Vector2(spriteFont.MeasureString(hintText.ToString()).X, IsLarge ? 32f : 16f) * TextScale; + // pos.X += 5;//(hintTextSize.X); + // if (base.IsLarge) + // { + // Utils.DrawBorderStringBig(spriteBatch, hintText, pos, Color.Gray, base.TextScale, 0f, 0f, -1); + // return; + // } + // Utils.DrawBorderString(spriteBatch, hintText, pos, Color.Gray, base.TextScale, 0f, 0f, -1); + // pos.X -= 5; + // //pos.X -= (innerDimensions.Width - hintTextSize.X) * 0.5f; + // } + // + // if (!focused) return; + // + // pos.X += /*(innerDimensions.Width - base.TextSize.X) * 0.5f*/ +vector.X - (base.IsLarge ? 8f : 4f) * base.TextScale + 6f; + // if ((this._frameCount %= 40) > 20) + // { + // return; + // } + // if (base.IsLarge) + // { + // Utils.DrawBorderStringBig(spriteBatch, "|", pos, base.TextColor, base.TextScale, 0f, 0f, -1); + // return; + // } + // Utils.DrawBorderString(spriteBatch, "|", pos, base.TextColor, base.TextScale, 0f, 0f, -1); + } + } +} \ No newline at end of file diff --git a/UIElements/ScrollbarHorizontal.png b/UIElements/ScrollbarHorizontal.png new file mode 100644 index 0000000..c199fe3 Binary files /dev/null and b/UIElements/ScrollbarHorizontal.png differ diff --git a/UIElements/ScrollbarInnerHorizontal.png b/UIElements/ScrollbarInnerHorizontal.png new file mode 100644 index 0000000..99b84aa Binary files /dev/null and b/UIElements/ScrollbarInnerHorizontal.png differ diff --git a/UICheckbox.cs b/UIElements/UICheckbox.cs similarity index 86% rename from UICheckbox.cs rename to UIElements/UICheckbox.cs index f05b8f8..38fc4bc 100644 --- a/UICheckbox.cs +++ b/UIElements/UICheckbox.cs @@ -1,16 +1,16 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using Terraria.ModLoader; -using Terraria.GameContent.UI.Elements; -using Terraria.UI; using System; +using Terraria.GameContent.UI.Elements; +using Terraria.ModLoader; +using Terraria.UI; -namespace ItemChecklist.UI +namespace ItemChecklist.UIElements { class UICheckbox : UIText { - static Texture2D checkboxTexture = ((ItemChecklist)ModLoader.GetMod("ItemChecklist")).GetTexture("checkBox"); - static Texture2D checkmarkTexture = ((ItemChecklist)ModLoader.GetMod("ItemChecklist")).GetTexture("checkMark"); + public static Texture2D checkboxTexture; + public static Texture2D checkmarkTexture; public event EventHandler SelectedChanged; float order = 0; diff --git a/UIGrid.cs b/UIElements/UIGrid.cs similarity index 95% rename from UIGrid.cs rename to UIElements/UIGrid.cs index 0ca5967..c7be839 100644 --- a/UIGrid.cs +++ b/UIElements/UIGrid.cs @@ -6,7 +6,7 @@ using Terraria; using Terraria.GameContent.UI.Elements; using Terraria.UI; -namespace ItemChecklist +namespace ItemChecklist.UIElements { public class UIGrid : UIElement { @@ -170,9 +170,13 @@ namespace ItemChecklist this.UpdateScrollbar(); } + internal Comparison alternateSort; public void UpdateOrder() { - this._items.Sort(new Comparison(this.SortMethod)); + if (alternateSort != null) + this._items.Sort(alternateSort); + else + this._items.Sort(new Comparison(this.SortMethod)); this.UpdateScrollbar(); } diff --git a/UIElements/UIHorizontalGrid.cs b/UIElements/UIHorizontalGrid.cs new file mode 100644 index 0000000..67d9986 --- /dev/null +++ b/UIElements/UIHorizontalGrid.cs @@ -0,0 +1,227 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using Terraria; +using Terraria.UI; + +namespace ItemChecklist.UIElements +{ + public class UIHorizontalGrid : UIElement + { + public delegate bool ElementSearchMethod(UIElement element); + + private class UIInnerList : UIElement + { + public override bool ContainsPoint(Vector2 point) + { + return true; + } + + protected override void DrawChildren(SpriteBatch spriteBatch) + { + Vector2 position = this.Parent.GetDimensions().Position(); + Vector2 dimensions = new Vector2(this.Parent.GetDimensions().Width, this.Parent.GetDimensions().Height); + foreach (UIElement current in this.Elements) + { + Vector2 position2 = current.GetDimensions().Position(); + Vector2 dimensions2 = new Vector2(current.GetDimensions().Width, current.GetDimensions().Height); + if (Collision.CheckAABBvAABBCollision(position, dimensions, position2, dimensions2)) + { + current.Draw(spriteBatch); + } + } + } + } + + public List _items = new List(); + protected UIHorizontalScrollbar _scrollbar; + internal UIElement _innerList = new UIHorizontalGrid.UIInnerList(); + private float _innerListWidth; + public float ListPadding = 5f; + + public static Texture2D moreLeftTexture; + public static Texture2D moreRightTexture; + + public int Count + { + get + { + return this._items.Count; + } + } + + // todo, vertical/horizontal orientation, left to right, etc? + public UIHorizontalGrid() + { + this._innerList.OverflowHidden = false; + this._innerList.Width.Set(0f, 1f); + this._innerList.Height.Set(0f, 1f); + this.OverflowHidden = true; + base.Append(this._innerList); + } + + public float GetTotalWidth() + { + return this._innerListWidth; + } + + public void Goto(UIHorizontalGrid.ElementSearchMethod searchMethod, bool center = false) + { + for (int i = 0; i < this._items.Count; i++) + { + if (searchMethod(this._items[i])) + { + this._scrollbar.ViewPosition = this._items[i].Left.Pixels; + if (center) + { + this._scrollbar.ViewPosition = this._items[i].Left.Pixels - GetInnerDimensions().Width / 2 + _items[i].GetOuterDimensions().Width / 2; + } + return; + } + } + } + + public virtual void Add(UIElement item) + { + this._items.Add(item); + this._innerList.Append(item); + this.UpdateOrder(); + this._innerList.Recalculate(); + } + + public virtual void AddRange(IEnumerable items) + { + this._items.AddRange(items); + foreach (var item in items) + this._innerList.Append(item); + this.UpdateOrder(); + this._innerList.Recalculate(); + } + + public virtual bool Remove(UIElement item) + { + this._innerList.RemoveChild(item); + this.UpdateOrder(); + return this._items.Remove(item); + } + + public virtual void Clear() + { + this._innerList.RemoveAllChildren(); + this._items.Clear(); + } + + public override void Recalculate() + { + base.Recalculate(); + this.UpdateScrollbar(); + } + + public override void ScrollWheel(UIScrollWheelEvent evt) + { + base.ScrollWheel(evt); + if (this._scrollbar != null) + { + this._scrollbar.ViewPosition -= (float)evt.ScrollWheelValue; + } + } + + public override void RecalculateChildren() + { + float availableHeight = GetInnerDimensions().Height; + base.RecalculateChildren(); + float left = 0f; + float top = 0f; + float maxRowWidth = 0f; + for (int i = 0; i < this._items.Count; i++) + { + var item = this._items[i]; + var outerDimensions = item.GetOuterDimensions(); + if (top + outerDimensions.Height > availableHeight && top > 0) + { + left += maxRowWidth + this.ListPadding; + top = 0; + maxRowWidth = 0; + } + maxRowWidth = Math.Max(maxRowWidth, outerDimensions.Width); + item.Top.Set(top, 0f); + top += outerDimensions.Height + this.ListPadding; + item.Left.Set(left, 0f); + item.Recalculate(); + } + this._innerListWidth = left + maxRowWidth; + } + + private void UpdateScrollbar() + { + if (this._scrollbar == null) + { + return; + } + this._scrollbar.SetView(base.GetInnerDimensions().Width, this._innerListWidth); + } + + public void SetScrollbar(UIHorizontalScrollbar scrollbar) + { + this._scrollbar = scrollbar; + this.UpdateScrollbar(); + } + + public void UpdateOrder() + { + this._items.Sort(new Comparison(this.SortMethod)); + this.UpdateScrollbar(); + } + + public int SortMethod(UIElement item1, UIElement item2) + { + return item1.CompareTo(item2); + } + + public override List GetSnapPoints() + { + List list = new List(); + SnapPoint item; + if (base.GetSnapPoint(out item)) + { + list.Add(item); + } + foreach (UIElement current in this._items) + { + list.AddRange(current.GetSnapPoints()); + } + return list; + } + + protected override void DrawSelf(SpriteBatch spriteBatch) + { + //var r = GetDimensions().ToRectangle(); + //r.Inflate(-10,-10); + //spriteBatch.Draw(Main.magicPixel, r, Color.Yellow); + if (this._scrollbar != null) + { + this._innerList.Left.Set(-this._scrollbar.GetValue(), 0f); + } + this.Recalculate(); + } + + public bool drawArrows; + protected override void DrawChildren(SpriteBatch spriteBatch) + { + base.DrawChildren(spriteBatch); + if (drawArrows) + { + var inner = GetInnerDimensions().ToRectangle(); + if (this._scrollbar.ViewPosition != 0) + { + spriteBatch.Draw(moreLeftTexture, new Vector2(inner.X, inner.Y), Color.White * .5f); + } + if (this._scrollbar.ViewPosition < _innerListWidth - inner.Width) + { + spriteBatch.Draw(moreRightTexture, new Vector2(inner.Right - moreRightTexture.Width, inner.Y), Color.White * .5f); + } + } + } + } +} \ No newline at end of file diff --git a/UIElements/UIHorizontalScrollbar.cs b/UIElements/UIHorizontalScrollbar.cs new file mode 100644 index 0000000..97525e6 --- /dev/null +++ b/UIElements/UIHorizontalScrollbar.cs @@ -0,0 +1,170 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Terraria; +using Terraria.UI; + +namespace ItemChecklist.UIElements +{ + public class UIHorizontalScrollbar : UIElement + { + private float _viewPosition; + private float _viewSize = 1f; + private float _maxViewSize = 20f; + private bool _isDragging; + private bool _isHoveringOverHandle; + private float _dragXOffset; + private Texture2D _texture; + private Texture2D _innerTexture; + + public float ViewPosition + { + get + { + return this._viewPosition; + } + set + { + this._viewPosition = MathHelper.Clamp(value, 0f, this._maxViewSize - this._viewSize); + } + } + + public UIHorizontalScrollbar() + { + this.Height.Set(20f, 0f); + this.MaxHeight.Set(20f, 0f); + this._texture = ItemChecklist.instance.GetTexture("UIElements/ScrollbarHorizontal"); //TextureManager.Load("Images/UI/Scrollbar"); + this._innerTexture = ItemChecklist.instance.GetTexture("UIElements/ScrollbarInnerHorizontal"); //TextureManager.Load("Images/UI/ScrollbarInner"); + this.PaddingLeft = 5f; + this.PaddingRight = 5f; + } + + public void SetView(float viewSize, float maxViewSize) + { + viewSize = MathHelper.Clamp(viewSize, 0f, maxViewSize); + this._viewPosition = MathHelper.Clamp(this._viewPosition, 0f, maxViewSize - viewSize); + this._viewSize = viewSize; + this._maxViewSize = maxViewSize; + } + + public float GetValue() + { + return this._viewPosition; + } + + private Rectangle GetHandleRectangle() + { + CalculatedStyle innerDimensions = base.GetInnerDimensions(); + if (this._maxViewSize == 0f && this._viewSize == 0f) + { + this._viewSize = 1f; + this._maxViewSize = 1f; + } + //return new Rectangle((int)innerDimensions.X, (int)(innerDimensions.Y + innerDimensions.Height * (this._viewPosition / this._maxViewSize)) - 3, 20, (int)(innerDimensions.Height * (this._viewSize / this._maxViewSize)) + 7); + return new Rectangle((int)(innerDimensions.X + innerDimensions.Width * (this._viewPosition / this._maxViewSize)) - 3, (int)innerDimensions.Y, (int)(innerDimensions.Width * (this._viewSize / this._maxViewSize)) + 7, 20); + } + + private void DrawBar(SpriteBatch spriteBatch, Texture2D texture, Rectangle dimensions, Color color) + { + //spriteBatch.Draw(texture, new Rectangle(dimensions.X, dimensions.Y - 6, dimensions.Width, 6), new Rectangle?(new Rectangle(0, 0, texture.Width, 6)), color); + //spriteBatch.Draw(texture, new Rectangle(dimensions.X, dimensions.Y, dimensions.Width, dimensions.Height), new Rectangle?(new Rectangle(0, 6, texture.Width, 4)), color); + //spriteBatch.Draw(texture, new Rectangle(dimensions.X, dimensions.Y + dimensions.Height, dimensions.Width, 6), new Rectangle?(new Rectangle(0, texture.Height - 6, texture.Width, 6)), color); + spriteBatch.Draw(texture, new Rectangle(dimensions.X - 6, dimensions.Y, 6, dimensions.Height), new Rectangle(0, 0, 6, texture.Height), color); + spriteBatch.Draw(texture, new Rectangle(dimensions.X, dimensions.Y, dimensions.Width, dimensions.Height), new Rectangle(6, 0, 4, texture.Height), color); + spriteBatch.Draw(texture, new Rectangle(dimensions.X + dimensions.Width, dimensions.Y, 6, dimensions.Height), new Rectangle(texture.Width - 6, 0, 6, texture.Height), color); + } + + protected override void DrawSelf(SpriteBatch spriteBatch) + { + CalculatedStyle dimensions = base.GetDimensions(); + CalculatedStyle innerDimensions = base.GetInnerDimensions(); + if (this._isDragging) + { + float num = UserInterface.ActiveInstance.MousePosition.X - innerDimensions.X - this._dragXOffset; + this._viewPosition = MathHelper.Clamp(num / innerDimensions.Width * this._maxViewSize, 0f, this._maxViewSize - this._viewSize); + } + Rectangle handleRectangle = this.GetHandleRectangle(); + Vector2 mousePosition = UserInterface.ActiveInstance.MousePosition; + bool isHoveringOverHandle = this._isHoveringOverHandle; + this._isHoveringOverHandle = handleRectangle.Contains(new Point((int)mousePosition.X, (int)mousePosition.Y)); + if (!isHoveringOverHandle && this._isHoveringOverHandle && Main.hasFocus) + { + Main.PlaySound(12, -1, -1, 1, 1f, 0f); + } + this.DrawBar(spriteBatch, this._texture, dimensions.ToRectangle(), Color.White); + this.DrawBar(spriteBatch, this._innerTexture, handleRectangle, Color.White * ((this._isDragging || this._isHoveringOverHandle) ? 1f : 0.85f)); + } + + public override void MouseDown(UIMouseEvent evt) + { + base.MouseDown(evt); + if (evt.Target == this) + { + Rectangle handleRectangle = this.GetHandleRectangle(); + if (handleRectangle.Contains(new Point((int)evt.MousePosition.X, (int)evt.MousePosition.Y))) + { + this._isDragging = true; + this._dragXOffset = evt.MousePosition.X - (float)handleRectangle.X; + return; + } + CalculatedStyle innerDimensions = base.GetInnerDimensions(); + float num = UserInterface.ActiveInstance.MousePosition.X - innerDimensions.X - (float)(handleRectangle.Width >> 1); + this._viewPosition = MathHelper.Clamp(num / innerDimensions.Width * this._maxViewSize, 0f, this._maxViewSize - this._viewSize); + } + } + + public override void MouseUp(UIMouseEvent evt) + { + base.MouseUp(evt); + this._isDragging = false; + } + } + + public class FixedUIHorizontalScrollbar : UIHorizontalScrollbar + { + internal UserInterface userInterface; + + public FixedUIHorizontalScrollbar(UserInterface userInterface) + { + this.userInterface = userInterface; + } + + protected override void DrawSelf(SpriteBatch spriteBatch) + { + UserInterface temp = UserInterface.ActiveInstance; + UserInterface.ActiveInstance = userInterface; + base.DrawSelf(spriteBatch); + UserInterface.ActiveInstance = temp; + } + + public override void MouseDown(UIMouseEvent evt) + { + UserInterface temp = UserInterface.ActiveInstance; + UserInterface.ActiveInstance = userInterface; + base.MouseDown(evt); + UserInterface.ActiveInstance = temp; + } + } + + public class InvisibleFixedUIHorizontalScrollbar : FixedUIHorizontalScrollbar + { + public InvisibleFixedUIHorizontalScrollbar(UserInterface userInterface) : base(userInterface) + { + } + + protected override void DrawSelf(SpriteBatch spriteBatch) + { + UserInterface temp = UserInterface.ActiveInstance; + UserInterface.ActiveInstance = userInterface; + //base.DrawSelf(spriteBatch); + UserInterface.ActiveInstance = temp; + } + + public override void MouseDown(UIMouseEvent evt) + { + UserInterface temp = UserInterface.ActiveInstance; + UserInterface.ActiveInstance = userInterface; + base.MouseDown(evt); + UserInterface.ActiveInstance = temp; + } + } +} diff --git a/UIHoverImageButton.cs b/UIElements/UIHoverImageButton.cs similarity index 74% rename from UIHoverImageButton.cs rename to UIElements/UIHoverImageButton.cs index a35c2c1..d4d8c5a 100644 --- a/UIHoverImageButton.cs +++ b/UIElements/UIHoverImageButton.cs @@ -1,8 +1,6 @@ -using ItemChecklist.UI; -using Microsoft.Xna.Framework.Graphics; -using Terraria.GameContent.UI.Elements; +using Microsoft.Xna.Framework.Graphics; -namespace ItemChecklist +namespace ItemChecklist.UIElements { internal class UIHoverImageButton : UIImageButton { diff --git a/ItemSlot.cs b/UIElements/UIItemSlot.cs similarity index 66% rename from ItemSlot.cs rename to UIElements/UIItemSlot.cs index 4562c84..17cffa0 100644 --- a/ItemSlot.cs +++ b/UIElements/UIItemSlot.cs @@ -1,60 +1,60 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using System; -using Terraria.UI; +using ReLogic.Graphics; using Terraria; -using ItemChecklist.UI; +using Terraria.UI; -namespace ItemChecklist +namespace ItemChecklist.UIElements { - internal class ItemSlot : UIElement + internal class UIItemSlot : UIElement { public static Texture2D backgroundTexture = Main.inventoryBack9Texture; private Texture2D _texture; // private float _visibilityActive = 1f; // private float _visibilityInactive = 0.4f; - private float scale = 0.6f; + private float scale = 0.75f; internal int id; internal Item item; + public string badge; - public ItemSlot(int id) + public UIItemSlot(int id) { this._texture = Main.itemTexture[id]; this.id = id; this.item = new Item(); - item.SetDefaults(id); + item.SetDefaults(id, true); this.Width.Set(backgroundTexture.Width * scale, 0f); this.Height.Set(backgroundTexture.Height * scale, 0f); } - public override int CompareTo(object obj) - { - ItemSlot other = obj as ItemSlot; - int result; - switch (ItemChecklistUI.sortMode) - { - case SortModes.ID: - return id.CompareTo(other.id); - case SortModes.AZ: - return item.Name.CompareTo(other.item.Name); - case SortModes.Value: - result = item.value.CompareTo(other.item.value); - if (result == 0) - result = item.Name.CompareTo(other.item.Name); - return result; - case SortModes.Rare: - result = item.rare.CompareTo(other.item.rare); - if (result == 0) - result = item.Name.CompareTo(other.item.Name); - return result; - case SortModes.TerrariaSort: - return ItemChecklistUI.vanillaIDsInSortOrder[id].CompareTo(ItemChecklistUI.vanillaIDsInSortOrder[other.id]); - } + //public override int CompareTo(object obj) + //{ + // UIItemSlot other = obj as UIItemSlot; + // int result; + // switch (ItemChecklistUI.sortMode) + // { + // case SortModes.ID: + // return id.CompareTo(other.id); + // case SortModes.AZ: + // return item.Name.CompareTo(other.item.Name); + // case SortModes.Value: + // result = item.value.CompareTo(other.item.value); + // if (result == 0) + // result = item.Name.CompareTo(other.item.Name); + // return result; + // case SortModes.Rare: + // result = item.rare.CompareTo(other.item.rare); + // if (result == 0) + // result = item.Name.CompareTo(other.item.Name); + // return result; + // case SortModes.TerrariaSort: + // return ItemChecklistUI.vanillaIDsInSortOrder[id].CompareTo(ItemChecklistUI.vanillaIDsInSortOrder[other.id]); + // } - return id.CompareTo(other.id); - } + // return id.CompareTo(other.id); + //} protected override void DrawSelf(SpriteBatch spriteBatch) { @@ -98,15 +98,16 @@ namespace ItemChecklist { spriteBatch.Draw(_texture, drawPosition, new Rectangle?(rectangle2), colorColor, 0f, Vector2.Zero, num, SpriteEffects.None, 0f); } - //if (this.item.stack > 1) - //{ - // spriteBatch.DrawString(Main.fontItemStack, this.item.stack.ToString(), new Vector2(dimensions.Position().X + 10f * scale, dimensions.Position().Y + 26f * scale), Color.White, 0f, Vector2.Zero, scale, SpriteEffects.None, 0f); - //} - + if (ItemChecklistUI.showBadge && !string.IsNullOrEmpty(badge)) + { + spriteBatch.DrawString(Main.fontItemStack, badge, new Vector2(dimensions.Position().X + 10f * scale, dimensions.Position().Y + 26f * scale), Color.White, 0f, Vector2.Zero, scale, SpriteEffects.None, 0f); + } if (IsMouseHovering) { ItemChecklistUI.hoverText = item.Name + (item.modItem != null ? " [" + item.modItem.mod.Name + "]" : ""); + + Main.HoverItem = item.Clone(); } } } diff --git a/UIElements/UISilentImageButton.cs b/UIElements/UISilentImageButton.cs new file mode 100644 index 0000000..e98708c --- /dev/null +++ b/UIElements/UISilentImageButton.cs @@ -0,0 +1,63 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Terraria; +using Terraria.UI; + +namespace ItemChecklist.UIElements +{ + class UISilentImageButton : UIElement + { + private Texture2D _texture; + private float _visibilityActive = 1f; + private float _visibilityHovered = .9f; + private float _visibilityInactive = 0.8f; // or color? same thing? + + public bool selected; + internal string hoverText; + + public UISilentImageButton(Texture2D texture, string hoverText) + { + this._texture = texture; + this.Width.Set((float)this._texture.Width, 0f); + this.Height.Set((float)this._texture.Height, 0f); + this.hoverText = hoverText; + } + + public void SetImage(Texture2D texture) + { + this._texture = texture; + this.Width.Set((float)this._texture.Width, 0f); + this.Height.Set((float)this._texture.Height, 0f); + } + + protected override void DrawSelf(SpriteBatch spriteBatch) + { + if (selected) + { + var r = GetDimensions().ToRectangle(); + r.Inflate(0,0); + //spriteBatch.Draw(UIElements.UIRecipeSlot.selectedBackgroundTexture, r, Color.White); + spriteBatch.Draw( Main.inventoryBack14Texture, r, Color.White); + } + + CalculatedStyle dimensions = base.GetDimensions(); + spriteBatch.Draw(this._texture, dimensions.Position(), Color.White * (selected ? _visibilityActive : ( IsMouseHovering ? _visibilityHovered : this._visibilityInactive))); + if (IsMouseHovering) + { + Main.hoverItemName = hoverText; + } + } + + public override void MouseOver(UIMouseEvent evt) + { + base.MouseOver(evt); + //Main.PlaySound(12, -1, -1, 1, 1f, 0f); + } + + //public void SetVisibility(float whenActive, float whenInactive) + //{ + // this._visibilityActive = MathHelper.Clamp(whenActive, 0f, 1f); + // this._visibilityInactive = MathHelper.Clamp(whenInactive, 0f, 1f); + //} + } +} diff --git a/UIElements/UIToggleHoverImageButton.cs b/UIElements/UIToggleHoverImageButton.cs new file mode 100644 index 0000000..b18de9b --- /dev/null +++ b/UIElements/UIToggleHoverImageButton.cs @@ -0,0 +1,92 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Terraria; +using Terraria.UI; + +namespace ItemChecklist.UIElements +{ + public class UIToggleHoverImageButton : UIImageButton + { + //private Texture2D _texture; + private Texture2D overlay; + private float _visibilityActive = 1f; + private float _visibilityInactive = 0.4f; + bool enabled; + internal string hoverText; + + public UIToggleHoverImageButton(Texture2D texture, Texture2D overlay, string hoverText, bool enabled = false) : base(texture) + { + this._texture = texture; + this.overlay = overlay; + this.Width.Set((float)this._texture.Width, 0f); + this.Height.Set((float)this._texture.Height, 0f); + this.hoverText = hoverText; + this.enabled = enabled; + } + + public void SetEnabled(bool enabled) + { + this.enabled = enabled; + } + + protected override void DrawSelf(SpriteBatch spriteBatch) + { + CalculatedStyle dimensions = base.GetDimensions(); + spriteBatch.Draw(this._texture, dimensions.Position(), Color.White * (base.IsMouseHovering ? this._visibilityActive : this._visibilityInactive)); + if (!enabled) + { + // 32x32, overlay is 24x24. + spriteBatch.Draw(this.overlay, dimensions.Position() + new Vector2(4), Color.White * (base.IsMouseHovering ? this._visibilityActive : this._visibilityInactive)); + } + if (IsMouseHovering) + { + ItemChecklistUI.hoverText = hoverText; + } + } + + public override void MouseOver(UIMouseEvent evt) + { + base.MouseOver(evt); + Main.PlaySound(12, -1, -1, 1, 1f, 0f); + } + } + + public class UIImageButton : UIElement + { + protected Texture2D _texture; + private float _visibilityActive = 1f; + private float _visibilityInactive = 0.4f; + + public UIImageButton(Texture2D texture) + { + this._texture = texture; + this.Width.Set((float)this._texture.Width, 0f); + this.Height.Set((float)this._texture.Height, 0f); + } + + public void SetImage(Texture2D texture) + { + this._texture = texture; + this.Width.Set((float)this._texture.Width, 0f); + this.Height.Set((float)this._texture.Height, 0f); + } + + protected override void DrawSelf(SpriteBatch spriteBatch) + { + CalculatedStyle dimensions = base.GetDimensions(); + spriteBatch.Draw(this._texture, dimensions.Position(), Color.White * (base.IsMouseHovering ? this._visibilityActive : this._visibilityInactive)); + } + + public override void MouseOver(UIMouseEvent evt) + { + base.MouseOver(evt); + Main.PlaySound(12, -1, -1, 1, 1f, 0f); + } + + public void SetVisibility(float whenActive, float whenInactive) + { + this._visibilityActive = MathHelper.Clamp(whenActive, 0f, 1f); + this._visibilityInactive = MathHelper.Clamp(whenInactive, 0f, 1f); + } + } +} \ No newline at end of file diff --git a/checkBox.png b/UIElements/checkBox.png similarity index 100% rename from checkBox.png rename to UIElements/checkBox.png diff --git a/checkMark.png b/UIElements/checkMark.png similarity index 100% rename from checkMark.png rename to UIElements/checkMark.png diff --git a/closeButton.png b/UIElements/closeButton.png similarity index 100% rename from closeButton.png rename to UIElements/closeButton.png diff --git a/UIElements/closeButtonSmallWhite.png b/UIElements/closeButtonSmallWhite.png new file mode 100644 index 0000000..e444455 Binary files /dev/null and b/UIElements/closeButtonSmallWhite.png differ diff --git a/UIElements/spacer.png b/UIElements/spacer.png new file mode 100644 index 0000000..8d5e22f Binary files /dev/null and b/UIElements/spacer.png differ diff --git a/UIToggleHoverImageButton.cs b/UIToggleHoverImageButton.cs deleted file mode 100644 index 9d2529f..0000000 --- a/UIToggleHoverImageButton.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using Terraria.UI; -using ItemChecklist.UI; - -namespace Terraria.GameContent.UI.Elements -{ - public class UIToggleHoverImageButton : UIImageButton - { - private Texture2D _texture; - private Texture2D overlay; - private float _visibilityActive = 1f; - private float _visibilityInactive = 0.4f; - bool enabled; - internal string hoverText; - - public UIToggleHoverImageButton(Texture2D texture, Texture2D overlay, string hoverText, bool enabled = false) : base(texture) - { - this._texture = texture; - this.overlay = overlay; - this.Width.Set((float)this._texture.Width, 0f); - this.Height.Set((float)this._texture.Height, 0f); - this.hoverText = hoverText; - this.enabled = enabled; - } - - public void SetEnabled(bool enabled) - { - this.enabled = enabled; - } - - protected override void DrawSelf(SpriteBatch spriteBatch) - { - CalculatedStyle dimensions = base.GetDimensions(); - spriteBatch.Draw(this._texture, dimensions.Position(), Color.White * (base.IsMouseHovering ? this._visibilityActive : this._visibilityInactive)); - if (!enabled) - { - spriteBatch.Draw(this.overlay, dimensions.Position(), Color.White * (base.IsMouseHovering ? this._visibilityActive : this._visibilityInactive)); - } - if (IsMouseHovering) - { - ItemChecklistUI.hoverText = hoverText; - } - } - - public override void MouseOver(UIMouseEvent evt) - { - base.MouseOver(evt); - Main.PlaySound(12, -1, -1, 1, 1f, 0f); - } - } -} \ No newline at end of file diff --git a/Utilities.cs b/Utilities.cs new file mode 100644 index 0000000..61f3cf3 --- /dev/null +++ b/Utilities.cs @@ -0,0 +1,79 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Terraria; + +namespace ItemChecklist +{ + static class Utilities + { + internal static Texture2D StackResizeImage(Texture2D[] texture2D, int desiredWidth, int desiredHeight) + { + float overlap = .5f; + float totalScale = 1 / (1f + ((1 - overlap) * (texture2D.Length - 1))); + int newWidth = (int)(desiredWidth * totalScale); + int newHeight = (int)(desiredHeight * totalScale); + //var texture2Ds = texture2D.Select(x => ResizeImage(x, newWidth, newHeight)); + + RenderTarget2D renderTarget = new RenderTarget2D(Main.graphics.GraphicsDevice, desiredWidth, desiredHeight); + Main.instance.GraphicsDevice.SetRenderTarget(renderTarget); + Main.instance.GraphicsDevice.Clear(Color.Transparent); + Main.spriteBatch.Begin(); + + int index = 0; + foreach (var texture in texture2D) + { + float scale = 1; + if (texture.Width > newWidth || texture.Height > newHeight) + { + if (texture.Height > texture.Width) + scale = (float)newHeight / texture.Height; + else + scale = (float)newWidth / texture.Width; + } + + Vector2 position = new Vector2(newWidth / 2, newHeight / 2); + position += new Vector2(index * (1 - overlap) * newWidth, index * (1 - overlap) * newHeight); + Main.spriteBatch.Draw(texture, position, null, Color.White, 0f, new Vector2(texture.Width / 2, texture.Height / 2), scale, SpriteEffects.None, 0f); + index++; + } + Main.spriteBatch.End(); + Main.instance.GraphicsDevice.SetRenderTarget(null); + + Texture2D mergedTexture = new Texture2D(Main.instance.GraphicsDevice, desiredWidth, desiredHeight); + Color[] content = new Color[desiredWidth * desiredHeight]; + renderTarget.GetData(content); + mergedTexture.SetData(content); + return mergedTexture; + } + + internal static Texture2D ResizeImage(Texture2D texture2D, int desiredWidth, int desiredHeight) + { + RenderTarget2D renderTarget = new RenderTarget2D(Main.graphics.GraphicsDevice, desiredWidth, desiredHeight); + Main.instance.GraphicsDevice.SetRenderTarget(renderTarget); + Main.instance.GraphicsDevice.Clear(Color.Transparent); + Main.spriteBatch.Begin(); + + float scale = 1; + if (texture2D.Width > desiredWidth || texture2D.Height > desiredHeight) + { + if (texture2D.Height > texture2D.Width) + scale = (float)desiredWidth / texture2D.Height; + else + scale = (float)desiredWidth / texture2D.Width; + } + + //new Vector2(texture2D.Width / 2 * scale, texture2D.Height / 2 * scale) desiredWidth/2, desiredHeight/2 + Main.spriteBatch.Draw(texture2D, new Vector2(desiredWidth / 2, desiredHeight / 2), null, Color.White, 0f, new Vector2(texture2D.Width / 2, texture2D.Height / 2), scale, SpriteEffects.None, 0f); + + Main.spriteBatch.End(); + Main.instance.GraphicsDevice.SetRenderTarget(null); + + Texture2D mergedTexture = new Texture2D(Main.instance.GraphicsDevice, desiredWidth, desiredHeight); + Color[] content = new Color[desiredWidth * desiredHeight]; + renderTarget.GetData(content); + mergedTexture.SetData(content); + return mergedTexture; + } + } +} + diff --git a/build.txt b/build.txt index 69f1b0d..2ed885a 100644 --- a/build.txt +++ b/build.txt @@ -1,5 +1,5 @@ author = jopojelly -version = 0.4 +version = 0.5 displayName = Item Checklist homepage = https://forums.terraria.org/index.php?threads/item-checklist-in-game-100-item-collection-checklist.52786/ hideCode = false diff --git a/description.txt b/description.txt index 1473652..d2d3556 100644 --- a/description.txt +++ b/description.txt @@ -2,12 +2,21 @@ Toggle the checklist with the hotkey assigned to it in the settings. -The checklist has several buttons at the top. +The checklist has several buttons at the top followed by some search filters and then the category chooser panel. Cycle Found Filter: Filters the list to show All, only Found, or only missing items. -Cycle Sort Method: Sorts the list by ID, Value, Alphabetical, Rarity, or the chest auto-sorting algorithm. Cycle Mod Filter: Lets you filter by all items, only vanilla items, or individual mods. Toggle Messages: Toggles the announcement chat text that happens when you pick up a new item. Toggle Collect Chest Items: You can toggle the behavior of counting items seen in chests as "collected". +Show Sort Value Text: Toggles showing additional text on the items in the checklist related to the currently selected sort. + +Filter by Name: Filters the checklist by item name. +Filter by tooltip: Filters the list by item tooltip. Try searching for "minions". + +Categories, Sub-Categories, Sorts, and Filters: The 1st line contains various categories. Sub-Categories will show up on the 2nd line if available. Sorts are also on the 2nd line, click on one to sort the checklist. Finally, Filters end the 2nd line. Use the scrollwheel to scroll these panels. + +Cycle Sort Method: Sorts the list by ID, Value, Alphabetical, Rarity, or the chest auto-sorting algorithm. If you use Magic Storage and have the Toggle Collect Chest Items enabled, you will also collect all items in storage if you access it. + +If you have Recipe Browser, try out its Query Hovered Item on the Checklist items to quickly bring the item into Recipe Browser. \ No newline at end of file