diff --git a/Assets/pin.blp b/Assets/pin.blp new file mode 100644 index 0000000..e6ee043 Binary files /dev/null and b/Assets/pin.blp differ diff --git a/Core/Database.lua b/Core/Database.lua index bedc744..0f3024e 100644 --- a/Core/Database.lua +++ b/Core/Database.lua @@ -149,6 +149,7 @@ function DB:Initialize() Guda_CharDB.settings.theme = "pfui" Guda_CharDB.settings.hideBorders = true Guda_CharDB.settings.bgTransparency = 0 + Guda_CharDB.settings.iconSpacing = 8 end end @@ -162,6 +163,11 @@ function DB:Initialize() Guda_CharDB.setProtectionExceptions = {} end + -- Initialize pinned slots storage + if not Guda_CharDB.pinnedSlots then + Guda_CharDB.pinnedSlots = {} + end + -- Initialize CategoryManager for custom categories if addon.Modules.CategoryManager then addon.Modules.CategoryManager:Initialize() @@ -540,6 +546,37 @@ function DB:IsItemProtected(itemID) return false end +------------------------------------------------- +-- Pinned Slots (per-character, slot-based) +-- Slots pinned by the user are skipped during sorting. +-- Key format: bagID * 1000 + slot +------------------------------------------------- + +function DB:IsPinnedSlot(bagID, slot) + if not bagID or not slot or not Guda_CharDB or not Guda_CharDB.pinnedSlots then return false end + return Guda_CharDB.pinnedSlots[bagID * 1000 + slot] and true or false +end + +function DB:TogglePinnedSlot(bagID, slot) + if not bagID or not slot or not Guda_CharDB then return false end + if not Guda_CharDB.pinnedSlots then + Guda_CharDB.pinnedSlots = {} + end + local key = bagID * 1000 + slot + if Guda_CharDB.pinnedSlots[key] then + Guda_CharDB.pinnedSlots[key] = nil + return false -- unpinned + else + Guda_CharDB.pinnedSlots[key] = true + return true -- pinned + end +end + +function DB:GetPinnedSlotSet() + if not Guda_CharDB or not Guda_CharDB.pinnedSlots then return {} end + return Guda_CharDB.pinnedSlots +end + -- Cleanup old characters (not updated in 90 days) function DB:CleanupOldCharacters() local cutoff = time() - (90 * 24 * 60 * 60) -- 90 days diff --git a/Guda.toc b/Guda.toc index 68a03ef..f72e2e7 100644 --- a/Guda.toc +++ b/Guda.toc @@ -2,7 +2,7 @@ ## Title: Guda ## Notes: All-in-one bag and bank addon for World of Warcraft 1.12.1 (Turtle WoW) ## Author: Vati -## Version: 2.1.4 +## Version: 2.1.5 ## SavedVariables: Guda_DB ## SavedVariablesPerCharacter: Guda_CharDB diff --git a/Sorting/SortEngine.lua b/Sorting/SortEngine.lua index 2837ada..695e727 100644 --- a/Sorting/SortEngine.lua +++ b/Sorting/SortEngine.lua @@ -642,7 +642,7 @@ end -- PHASE 2: Specialized Item Routing --=========================================================================== -local function RouteSpecializedItems(bagIDs, containers) +local function RouteSpecializedItems(bagIDs, containers, pinnedSlots) local routingPlan = {} -- Scan all items and plan moves to specialized containers @@ -650,6 +650,8 @@ local function RouteSpecializedItems(bagIDs, containers) local numSlots = addon.Modules.Utils:GetBagSlotCount(bagID) if numSlots and numSlots > 0 then for slot = 1, numSlots do + -- Skip pinned slots + if not (pinnedSlots and pinnedSlots[bagID * 1000 + slot]) then local link = GetContainerItemLink(bagID, slot) if link then local preferredType = addon.Modules.Utils:GetItemPreferredContainer(link) @@ -665,7 +667,8 @@ local function RouteSpecializedItems(bagIDs, containers) if not foundSlot then local targetSlots = addon.Modules.Utils:GetBagSlotCount(targetBagID) for targetSlot = 1, targetSlots do - if not GetContainerItemLink(targetBagID, targetSlot) then + if not GetContainerItemLink(targetBagID, targetSlot) + and not (pinnedSlots and pinnedSlots[targetBagID * 1000 + targetSlot]) then table.insert(routingPlan, { fromBag = bagID, fromSlot = slot, @@ -681,6 +684,7 @@ local function RouteSpecializedItems(bagIDs, containers) end end end + end -- pinned check end end end @@ -701,7 +705,7 @@ end -- PHASE 3: Stack Consolidation --=========================================================================== -local function ConsolidateStacks(bagIDs) +local function ConsolidateStacks(bagIDs, pinnedSlots) local itemGroups = {} -- Collect all items with their locations @@ -709,6 +713,10 @@ local function ConsolidateStacks(bagIDs) local numSlots = addon.Modules.Utils:GetBagSlotCount(bagID) if numSlots and numSlots > 0 then for slot = 1, numSlots do + -- Skip pinned slots + if pinnedSlots and pinnedSlots[bagID * 1000 + slot] then + -- do nothing + else local link = GetContainerItemLink(bagID, slot) if link then local texture, count = GetContainerItemInfo(bagID, slot) @@ -733,6 +741,7 @@ local function ConsolidateStacks(bagIDs) priority = tonumber(addon.Modules.Utils:GetContainerPriority(bagID)) or 0 }) end + end -- pinned check end end end @@ -1147,7 +1156,7 @@ end -- PHASE 5: Empty Slot Management & Apply Sort --=========================================================================== -local function CollectItems(bagIDs) +local function CollectItems(bagIDs, pinnedSlots) local items = {} local sequence = 0 -- Add sequence number for stable sort @@ -1156,6 +1165,10 @@ local function CollectItems(bagIDs) if addon.Modules.Utils:IsBagValid(bagID) then for slot = 1, numSlots do + -- Skip pinned slots — they are not touched by sorting + if pinnedSlots and pinnedSlots[bagID * 1000 + slot] then + -- do nothing, slot is pinned + else -- Scan directly from game API instead of cached data local texture, itemCount, locked = GetContainerItemInfo(bagID, slot) local itemLink = GetContainerItemLink(bagID, slot) @@ -1194,14 +1207,15 @@ local function CollectItems(bagIDs) class = category or "", }) end - end - end - end + end -- if pinnedSlots + end -- for slot + end -- if isBagValid + end -- for bagID return items end -local function BuildTargetPositions(bagIDs, itemCount) +local function BuildTargetPositions(bagIDs, itemCount, pinnedSlots) local positions = {} local index = 1 @@ -1234,8 +1248,11 @@ local function BuildTargetPositions(bagIDs, itemCount) if addon.Modules.Utils:IsBagValid(bagID) then for slot = 1, numSlots do if index <= itemCount then - positions[index] = {bag = bagID, slot = slot} - index = index + 1 + -- Skip pinned slots + if not (pinnedSlots and pinnedSlots[bagID * 1000 + slot]) then + positions[index] = {bag = bagID, slot = slot} + index = index + 1 + end else break end @@ -1402,7 +1419,7 @@ end -- Build tail positions (end-to-start) for a given count across the provided bags, -- starting from the "last" regular bag (lowest priority, then highest bagID), -- and spilling into previous bags when needed. -local function BuildGreyTailPositions(bagIDs, greyCount) +local function BuildGreyTailPositions(bagIDs, greyCount, pinnedSlots) local positions = {} if greyCount <= 0 then return positions end @@ -1439,7 +1456,7 @@ local function BuildGreyTailPositions(bagIDs, greyCount) local tailSlots = {} for _, info in ipairs(ordered) do for slot = info.numSlots, 1, -1 do - if table.getn(tailSlots) < greyCount then + if table.getn(tailSlots) < greyCount and not (pinnedSlots and pinnedSlots[info.bagID * 1000 + slot]) then table.insert(tailSlots, { bag = info.bagID, slot = slot }) else break @@ -1507,6 +1524,7 @@ end function SortEngine:AnalyzeContainer(bagIDs, containerType) -- Detect specialized bags (same as SortBags) local containers = DetectSpecializedBags(bagIDs) + local pinnedSlots = addon.Modules.DB and addon.Modules.DB:GetPinnedSlotSet() or {} local totalOutOfPlace = 0 local totalItems = 0 @@ -1515,10 +1533,10 @@ function SortEngine:AnalyzeContainer(bagIDs, containerType) for _, bagType in ipairs({"enchant", "herb", "soul", "quiver", "ammo"}) do local specialBags = containers[bagType] for _, bagID in ipairs(specialBags) do - local items = CollectItems({bagID}) + local items = CollectItems({bagID}, pinnedSlots) if table.getn(items) > 0 then local sortedItems = SortItems(items) - local targetPositions = BuildTargetPositions({bagID}, table.getn(items)) + local targetPositions = BuildTargetPositions({bagID}, table.getn(items), pinnedSlots) for i, item in ipairs(sortedItems) do local target = targetPositions[i] @@ -1543,7 +1561,7 @@ function SortEngine:AnalyzeContainer(bagIDs, containerType) end if table.getn(validRegularBags) > 0 then - local allItems = CollectItems(validRegularBags) + local allItems = CollectItems(validRegularBags, pinnedSlots) totalItems = totalItems + table.getn(allItems) -- Split greys/non-greys like SortBags does @@ -1552,7 +1570,7 @@ function SortEngine:AnalyzeContainer(bagIDs, containerType) -- Check non-grey positioning (should be in front positions) if table.getn(nonGreys) > 0 then local sortedNonGreys = SortItems(nonGreys) - local frontPositions = BuildTargetPositions(validRegularBags, table.getn(sortedNonGreys)) + local frontPositions = BuildTargetPositions(validRegularBags, table.getn(sortedNonGreys), pinnedSlots) for i, item in ipairs(sortedNonGreys) do local target = frontPositions[i] @@ -1565,7 +1583,7 @@ function SortEngine:AnalyzeContainer(bagIDs, containerType) -- Check grey positioning (should be in tail positions) if table.getn(greys) > 0 then -- CRITICAL FIX: Only use bags that actually exist and have slots - local tailPositions = BuildGreyTailPositions(validRegularBags, table.getn(greys)) + local tailPositions = BuildGreyTailPositions(validRegularBags, table.getn(greys), pinnedSlots) for i, item in ipairs(greys) do local target = tailPositions[i] @@ -1611,24 +1629,27 @@ end function SortEngine:SortBagsPass() local bagIDs = addon.Constants.BAGS + -- Cache pinned slots for this pass + local pinnedSlots = addon.Modules.DB and addon.Modules.DB:GetPinnedSlotSet() or {} + -- Phase 1: Detect specialized bags local containers = DetectSpecializedBags(bagIDs) -- Phase 2: Route specialized items to their bags - local routeCount = RouteSpecializedItems(bagIDs, containers) + local routeCount = RouteSpecializedItems(bagIDs, containers, pinnedSlots) -- Phase 3: Consolidate stacks in ALL bags (including specialized) - local consolidateCount = ConsolidateStacks(bagIDs) + local consolidateCount = ConsolidateStacks(bagIDs, pinnedSlots) -- Phase 4: Sort items WITHIN each specialized bag (enchant, herb, soul, quiver, ammo) local specializedMoves = 0 for _, bagType in ipairs({"enchant", "herb", "soul", "quiver", "ammo"}) do local specialBags = containers[bagType] for _, bagID in ipairs(specialBags) do - local items = CollectItems({bagID}) + local items = CollectItems({bagID}, pinnedSlots) if table.getn(items) > 0 then items = SortItems(items) - local targetPositions = BuildTargetPositions({bagID}, table.getn(items)) + local targetPositions = BuildTargetPositions({bagID}, table.getn(items), pinnedSlots) local moveCount = ApplySort({bagID}, items, targetPositions) specializedMoves = specializedMoves + moveCount end @@ -1642,7 +1663,7 @@ function SortEngine:SortBagsPass() local regularMoves = 0 local regularBagIDs = containers.regular if table.getn(regularBagIDs) > 0 then - local allItems = CollectItems(regularBagIDs) + local allItems = CollectItems(regularBagIDs, pinnedSlots) local nonGreys, greys = SplitGreyItems(allItems) local combinedItems = {} @@ -1651,7 +1672,7 @@ function SortEngine:SortBagsPass() -- Non-greys: sorted to front positions if table.getn(nonGreys) > 0 then local sortedNonGreys = SortItems(nonGreys) - local frontPositions = BuildTargetPositions(regularBagIDs, table.getn(sortedNonGreys)) + local frontPositions = BuildTargetPositions(regularBagIDs, table.getn(sortedNonGreys), pinnedSlots) for i, item in ipairs(sortedNonGreys) do table.insert(combinedItems, item) table.insert(combinedPositions, frontPositions[i]) @@ -1660,7 +1681,7 @@ function SortEngine:SortBagsPass() -- Greys: to tail positions (end->start) if table.getn(greys) > 0 then - local tailPositions = BuildGreyTailPositions(regularBagIDs, table.getn(greys)) + local tailPositions = BuildGreyTailPositions(regularBagIDs, table.getn(greys), pinnedSlots) for i, item in ipairs(greys) do table.insert(combinedItems, item) table.insert(combinedPositions, tailPositions[i]) @@ -1764,24 +1785,27 @@ function SortEngine:SortBankPass() local bagIDs = addon.Constants.BANK_BAGS + -- Cache pinned slots for this pass + local pinnedSlots = addon.Modules.DB and addon.Modules.DB:GetPinnedSlotSet() or {} + -- Phase 1: Detect specialized bags local containers = DetectSpecializedBags(bagIDs) -- Phase 2: Route specialized items - local routeCount = RouteSpecializedItems(bagIDs, containers) + local routeCount = RouteSpecializedItems(bagIDs, containers, pinnedSlots) -- Phase 3: Consolidate stacks - local consolidateCount = ConsolidateStacks(bagIDs) + local consolidateCount = ConsolidateStacks(bagIDs, pinnedSlots) -- Phase 4: Sort items WITHIN each specialized bag (single pass) local specializedMoves = 0 for _, bagType in ipairs({"enchant", "herb", "soul", "quiver", "ammo"}) do local specialBags = containers[bagType] for _, bagID in ipairs(specialBags) do - local items = CollectItems({bagID}) + local items = CollectItems({bagID}, pinnedSlots) if table.getn(items) > 0 then items = SortItems(items) - local targetPositions = BuildTargetPositions({bagID}, table.getn(items)) + local targetPositions = BuildTargetPositions({bagID}, table.getn(items), pinnedSlots) local moved = ApplySort({bagID}, items, targetPositions) specializedMoves = specializedMoves + moved end @@ -1792,7 +1816,7 @@ function SortEngine:SortBankPass() local regularBagIDs = containers.regular local regularMoves = 0 if table.getn(regularBagIDs) > 0 then - local allItems = CollectItems(regularBagIDs) + local allItems = CollectItems(regularBagIDs, pinnedSlots) local nonGreys, greys = SplitGreyItems(allItems) local combinedItems = {} @@ -1800,7 +1824,7 @@ function SortEngine:SortBankPass() if table.getn(nonGreys) > 0 then local sortedNonGreys = SortItems(nonGreys) - local frontPositions = BuildTargetPositions(regularBagIDs, table.getn(sortedNonGreys)) + local frontPositions = BuildTargetPositions(regularBagIDs, table.getn(sortedNonGreys), pinnedSlots) for i, item in ipairs(sortedNonGreys) do table.insert(combinedItems, item) table.insert(combinedPositions, frontPositions[i]) @@ -1808,7 +1832,7 @@ function SortEngine:SortBankPass() end if table.getn(greys) > 0 then - local tailPositions = BuildGreyTailPositions(regularBagIDs, table.getn(greys)) + local tailPositions = BuildGreyTailPositions(regularBagIDs, table.getn(greys), pinnedSlots) for i, item in ipairs(greys) do table.insert(combinedItems, item) table.insert(combinedPositions, tailPositions[i]) diff --git a/UI/ItemButton.lua b/UI/ItemButton.lua index 8a500f5..e85e769 100644 --- a/UI/ItemButton.lua +++ b/UI/ItemButton.lua @@ -530,7 +530,6 @@ local function AcquireLockIcon() local icon = table.remove(lockIconPool) if not icon then icon = CreateFrame("Frame", nil, UIParent) - icon:SetFrameStrata("HIGH") icon:SetWidth(13) icon:SetHeight(13) @@ -556,6 +555,7 @@ local function ReleaseLockIcon(icon) if icon then icon:Hide() icon:ClearAllPoints() + icon:SetParent(UIParent) table.insert(lockIconPool, icon) end end @@ -577,6 +577,7 @@ local function UpdateLockIcon(button, iconSize) if not button.lockIcon then button.lockIcon = AcquireLockIcon() end + button.lockIcon:SetParent(button) local lockSize = math.max(8, math.min(12, iconSize * 0.35 - 3)) button.lockIcon:SetWidth(lockSize) button.lockIcon:SetHeight(lockSize) @@ -603,6 +604,85 @@ local function HideLockIcon(button) end end +--===================================================== +-- Pin Icon Pool (indicates slot is pinned / sort-protected) +--===================================================== +local pinIconPool = {} + +local function AcquirePinIcon() + local icon = table.remove(pinIconPool) + if not icon then + icon = CreateFrame("Frame", nil, UIParent) + icon:SetWidth(13) + icon:SetHeight(13) + + -- Shadow (behind) + local shadow = icon:CreateTexture(nil, "BACKGROUND") + shadow:SetWidth(15) + shadow:SetHeight(15) + shadow:SetPoint("CENTER", icon, "CENTER", 0, 0) + shadow:SetTexture("Interface\\AddOns\\Guda\\Assets\\pin") + shadow:SetVertexColor(0, 0, 0, 0.9) + icon.shadow = shadow + + -- Icon (front) + local texture = icon:CreateTexture(nil, "OVERLAY") + texture:SetAllPoints(icon) + texture:SetTexture("Interface\\AddOns\\Guda\\Assets\\pin") + icon.texture = texture + end + return icon +end + +local function ReleasePinIcon(icon) + if icon then + icon:Hide() + icon:ClearAllPoints() + icon:SetParent(UIParent) + table.insert(pinIconPool, icon) + end +end + +local function UpdatePinIcon(button, iconSize) + local DB = addon.Modules.DB + if not DB then return end + + local isPinned = false + if button.bagID and button.slotID and not button.otherChar and not button.isReadOnly then + isPinned = DB:IsPinnedSlot(button.bagID, button.slotID) + end + + if isPinned then + if not button.pinIcon then + button.pinIcon = AcquirePinIcon() + end + button.pinIcon:SetParent(button) + local pinSize = math.max(10, math.min(14, iconSize * 0.35)) + button.pinIcon:SetWidth(pinSize) + button.pinIcon:SetHeight(pinSize) + if button.pinIcon.shadow then + button.pinIcon.shadow:SetWidth(pinSize + 2) + button.pinIcon.shadow:SetHeight(pinSize + 2) + end + button.pinIcon:ClearAllPoints() + button.pinIcon:SetPoint("TOPLEFT", button, "TOPLEFT", -2, 2) + button.pinIcon:SetFrameLevel(button:GetFrameLevel() + 5) + button.pinIcon:Show() + else + if button.pinIcon then + ReleasePinIcon(button.pinIcon) + button.pinIcon = nil + end + end +end + +local function HidePinIcon(button) + if button.pinIcon then + ReleasePinIcon(button.pinIcon) + button.pinIcon = nil + end +end + -- Hook UseContainerItem to prevent selling/disenchanting protected items local OriginalUseContainerItem = UseContainerItem UseContainerItem = function(bag, slot, ...) @@ -988,6 +1068,7 @@ function Guda_ItemButton_OnLoad(self) self:SetScript("OnHide", function() HideJunkIcon(this) HideLockIcon(this) + HidePinIcon(this) end) -- Track cursor item on drag start for category drag-drop @@ -1043,6 +1124,30 @@ function Guda_ItemButton_OnLoad(self) return end + -- Pin/unpin slot with Alt+Right-Click + if IsAltKeyDown() and arg1 == "RightButton" and not this.otherChar and not this.isReadOnly then + if this.bagID ~= nil and this.slotID and addon.Modules.DB then + local isNowPinned = addon.Modules.DB:TogglePinnedSlot(this.bagID, this.slotID) + local itemName = "" + if this.hasItem and this.itemData and this.itemData.link then + itemName = " " .. this.itemData.link + end + if isNowPinned then + addon:Print("Slot pinned" .. itemName .. " (skipped during sort)") + else + addon:Print("Slot unpinned" .. itemName) + end + -- Refresh to show/hide pin icon + if addon.Modules.BagFrame and addon.Modules.BagFrame.Update then + addon.Modules.BagFrame:Update() + end + if addon.Modules.BankFrame and addon.Modules.BankFrame.Update then + addon.Modules.BankFrame:Update() + end + end + return + end + if IsAltKeyDown() and arg1 == "LeftButton" and this.hasItem and not this.otherChar and not this.isReadOnly then local link = GetContainerItemLink(this.bagID, this.slotID) if link and addon and addon.Modules and addon.Modules.Utils then @@ -1504,8 +1609,9 @@ local function ClearItemButton(self, emptySlotBg, countText, bagID) -- Hide junk icon HideJunkIcon(self) - -- Hide lock icon + -- Hide lock and pin icons HideLockIcon(self) + HidePinIcon(self) -- Hide normal texture self:SetNormalTexture("") @@ -1647,8 +1753,9 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha end end - -- Update lock icon + -- Update lock and pin icons UpdateLockIcon(self, iconSize) + UpdatePinIcon(self, iconSize) -- Update empty slot bg anchors/texture based on slot style UpdateEmptySlotBackground(self, emptySlotBg, iconSize) @@ -1838,17 +1945,17 @@ function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCha if not self.categoryMarkIcon then self.categoryMarkIcon = self:CreateTexture(nil, "OVERLAY", 7) end - local markSize = math.max(10, math.floor(iconSize * 0.3)) + 6 + local markSize = math.max(10, math.floor(iconSize * 0.3)) + 3 self.categoryMarkIcon:SetWidth(markSize) self.categoryMarkIcon:SetHeight(markSize) self.categoryMarkIcon:ClearAllPoints() - local markOffX, markOffY = 2, 2 + local markOffX, markOffY = 1, 2 if addon.Modules and addon.Modules.Theme and addon.Modules.Theme:GetSlotStyle() == "square" then - markOffX, markOffY = -2, -2 + markOffX, markOffY = -1, -1 end self.categoryMarkIcon:SetPoint("BOTTOMLEFT", anchor, "BOTTOMLEFT", markOffX, markOffY) self.categoryMarkIcon:SetTexture(categoryMarkTexture) - self.categoryMarkIcon:SetVertexColor(0.85, 0.65, 0.13, 1) + self.categoryMarkIcon:SetVertexColor(1, 1, 1, 1) self.categoryMarkIcon:SetAlpha(1) self.categoryMarkIcon:Show() else diff --git a/UI/QuestItemBar.lua b/UI/QuestItemBar.lua index 967f01c..49f36a8 100644 --- a/UI/QuestItemBar.lua +++ b/UI/QuestItemBar.lua @@ -259,8 +259,17 @@ function QuestItemBar:Update() button.slotID = nil local icon = getglobal(button:GetName() .. "IconTexture") - icon:SetTexture("Interface\\Buttons\\UI-EmptySlot") - icon:SetVertexColor(0.5, 0.5, 0.5, 0.5) + local slotStyle = "rounded" + if addon.Modules and addon.Modules.Theme then + slotStyle = addon.Modules.Theme:GetSlotStyle() + end + if slotStyle == "square" then + icon:SetTexture("Interface\\Buttons\\WHITE8x8") + icon:SetVertexColor(0.05, 0.05, 0.05, 0.5) + else + icon:SetTexture("Interface\\Buttons\\UI-EmptySlot") + icon:SetVertexColor(0.5, 0.5, 0.5, 0.5) + end local countText = getglobal(button:GetName() .. "Count") countText:Hide() @@ -324,18 +333,44 @@ function QuestItemBar:Update() end -- Scale border proportionally (64/37 is the standard ratio for WoW item buttons) - local borderSize = buttonSize * 64 / 37 + local slotStyle = "rounded" + if addon.Modules and addon.Modules.Theme then + slotStyle = addon.Modules.Theme:GetSlotStyle() + end + local normalTex = getglobal(button:GetName() .. "NormalTexture") - if normalTex then - normalTex:SetWidth(borderSize) - normalTex:SetHeight(borderSize) + if slotStyle == "square" then + -- Hide rounded border in pfUI mode + button:SetNormalTexture("") + if normalTex then + normalTex:SetTexture(nil) + normalTex:Hide() + end + -- Crop icon for pfUI style + if icon then + icon:SetTexCoord(.08, .92, .08, .92) + end + else + local borderSize = buttonSize * 64 / 37 + if normalTex then + normalTex:SetWidth(borderSize) + normalTex:SetHeight(borderSize) + end end -- Resize empty slot background local emptyBg = getglobal(button:GetName() .. "_EmptySlotBg") if emptyBg then - emptyBg:SetWidth(buttonSize) - emptyBg:SetHeight(buttonSize) + if slotStyle == "square" then + emptyBg:SetTexture("Interface\\Buttons\\WHITE8x8") + emptyBg:SetVertexColor(0.05, 0.05, 0.05, 1) + emptyBg:ClearAllPoints() + emptyBg:SetPoint("TOPLEFT", button, "TOPLEFT", 0, 0) + emptyBg:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", 0, 0) + else + emptyBg:SetWidth(buttonSize) + emptyBg:SetHeight(buttonSize) + end end -- Update visual overlays (cooldown, etc) @@ -562,12 +597,27 @@ function QuestItemBar:UpdateFlyout(parent) btnIcon:SetHeight(buttonSize) end - -- Scale border proportionally (64/37 is the standard ratio for WoW item buttons) - local borderSize = buttonSize * 64 / 37 + -- Scale or hide border based on theme local btnNormalTex = getglobal(btn:GetName() .. "NormalTexture") - if btnNormalTex then - btnNormalTex:SetWidth(borderSize) - btnNormalTex:SetHeight(borderSize) + local flyoutSlotStyle = "rounded" + if addon.Modules and addon.Modules.Theme then + flyoutSlotStyle = addon.Modules.Theme:GetSlotStyle() + end + if flyoutSlotStyle == "square" then + btn:SetNormalTexture("") + if btnNormalTex then + btnNormalTex:SetTexture(nil) + btnNormalTex:Hide() + end + if btnIcon then + btnIcon:SetTexCoord(.08, .92, .08, .92) + end + else + local borderSize = buttonSize * 64 / 37 + if btnNormalTex then + btnNormalTex:SetWidth(borderSize) + btnNormalTex:SetHeight(borderSize) + end end -- Resize empty slot background diff --git a/UI/SettingsPopup.lua b/UI/SettingsPopup.lua index 9374ff0..fbbfb0b 100644 --- a/UI/SettingsPopup.lua +++ b/UI/SettingsPopup.lua @@ -58,7 +58,13 @@ function Guda_SettingsPopup_OnLoad(self) "Ctrl + Right Click on any item to lock/unlock it.\n" .. "Locked items cannot be sold at vendors, deleted, or disenchanted.\n" .. "Equipment set items are automatically protected.\n" .. + "Ctrl + Right Click a set item to toggle its protection.\n" .. "A lock icon appears on the bottom-right corner.\n\n" .. + "|cffffd100Pin Slot:|r\n" .. + "Alt + Right Click on any bag slot to pin/unpin it.\n" .. + "Pinned slots are skipped during sorting.\n" .. + "The pin stays on the slot, not the item.\n" .. + "A pin icon appears on the top-left corner.\n\n" .. "|cffffd100Moving Bars:|r\n" .. "Shift + Left Click and drag any item on the Quest Item Bar or Tracked Item Bar to move the bar.\n" instructions:SetText(text)