first commit
This commit is contained in:
@@ -0,0 +1,201 @@
|
|||||||
|
-- Guda Database Module
|
||||||
|
-- Handles saving and loading character data
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
local DB = {}
|
||||||
|
addon.Modules.DB = DB
|
||||||
|
|
||||||
|
-- Current player info
|
||||||
|
local playerName, playerRealm, playerFaction
|
||||||
|
|
||||||
|
-- Initialize database
|
||||||
|
function DB:Initialize()
|
||||||
|
-- Get player info
|
||||||
|
playerName = UnitName("player")
|
||||||
|
playerRealm = GetRealmName()
|
||||||
|
playerFaction = UnitFactionGroup("player")
|
||||||
|
|
||||||
|
local fullName = playerName .. "-" .. playerRealm
|
||||||
|
|
||||||
|
-- Initialize global DB
|
||||||
|
if not Guda_DB then
|
||||||
|
Guda_DB = {
|
||||||
|
version = addon.VERSION,
|
||||||
|
characters = {},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize character DB
|
||||||
|
if not Guda_CharDB then
|
||||||
|
Guda_CharDB = {
|
||||||
|
settings = {
|
||||||
|
showBankInBags = true,
|
||||||
|
showOtherChars = true,
|
||||||
|
bagColumns = 10,
|
||||||
|
bankColumns = 15,
|
||||||
|
sortMethod = "quality", -- quality, name, type
|
||||||
|
iconSize = addon.Constants and addon.Constants.BUTTON_SIZE or 37,
|
||||||
|
iconFontSize = 12,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ensure new settings exist for existing installations
|
||||||
|
if not Guda_CharDB.settings.bagColumns then
|
||||||
|
Guda_CharDB.settings.bagColumns = 10
|
||||||
|
end
|
||||||
|
if not Guda_CharDB.settings.bankColumns then
|
||||||
|
Guda_CharDB.settings.bankColumns = 15
|
||||||
|
end
|
||||||
|
if not Guda_CharDB.settings.iconSize then
|
||||||
|
Guda_CharDB.settings.iconSize = addon.Constants and addon.Constants.BUTTON_SIZE or 37
|
||||||
|
end
|
||||||
|
if not Guda_CharDB.settings.iconFontSize then
|
||||||
|
Guda_CharDB.settings.iconFontSize = 12
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize this character's data
|
||||||
|
if not Guda_DB.characters[fullName] then
|
||||||
|
Guda_DB.characters[fullName] = {
|
||||||
|
name = playerName,
|
||||||
|
realm = playerRealm,
|
||||||
|
faction = playerFaction,
|
||||||
|
class = UnitClass("player"),
|
||||||
|
level = UnitLevel("player"),
|
||||||
|
money = 0,
|
||||||
|
bags = {},
|
||||||
|
bank = {},
|
||||||
|
lastUpdate = time(),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
addon:Debug("Database initialized for %s", fullName)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get current player's full name
|
||||||
|
function DB:GetPlayerFullName()
|
||||||
|
return playerName .. "-" .. playerRealm
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get current character data
|
||||||
|
function DB:GetCurrentCharacter()
|
||||||
|
local fullName = self:GetPlayerFullName()
|
||||||
|
return Guda_DB.characters[fullName]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Save bag data
|
||||||
|
function DB:SaveBags(bagData)
|
||||||
|
local char = self:GetCurrentCharacter()
|
||||||
|
if char then
|
||||||
|
char.bags = bagData
|
||||||
|
char.lastUpdate = time()
|
||||||
|
addon:Debug("Saved bag data")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Save bank data
|
||||||
|
function DB:SaveBank(bankData)
|
||||||
|
local char = self:GetCurrentCharacter()
|
||||||
|
if char then
|
||||||
|
char.bank = bankData
|
||||||
|
char.lastUpdate = time()
|
||||||
|
addon:Debug("Saved bank data")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Save money
|
||||||
|
function DB:SaveMoney(copper)
|
||||||
|
local char = self:GetCurrentCharacter()
|
||||||
|
if char then
|
||||||
|
char.money = copper
|
||||||
|
char.level = UnitLevel("player")
|
||||||
|
addon:Debug("Saved money: %d copper", copper)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get all characters (optionally filter by faction)
|
||||||
|
function DB:GetAllCharacters(sameFactionOnly)
|
||||||
|
local chars = {}
|
||||||
|
for fullName, data in pairs(Guda_DB.characters) do
|
||||||
|
if not sameFactionOnly or data.faction == playerFaction then
|
||||||
|
table.insert(chars, {
|
||||||
|
fullName = fullName,
|
||||||
|
name = data.name,
|
||||||
|
realm = data.realm,
|
||||||
|
class = data.class,
|
||||||
|
level = data.level,
|
||||||
|
faction = data.faction,
|
||||||
|
money = data.money,
|
||||||
|
lastUpdate = data.lastUpdate,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sort by name
|
||||||
|
table.sort(chars, function(a, b)
|
||||||
|
return a.name < b.name
|
||||||
|
end)
|
||||||
|
|
||||||
|
return chars
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get character's bags
|
||||||
|
function DB:GetCharacterBags(fullName)
|
||||||
|
local char = Guda_DB.characters[fullName]
|
||||||
|
return char and char.bags or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get character's bank
|
||||||
|
function DB:GetCharacterBank(fullName)
|
||||||
|
local char = Guda_DB.characters[fullName]
|
||||||
|
return char and char.bank or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get total money across all characters
|
||||||
|
function DB:GetTotalMoney(sameFactionOnly)
|
||||||
|
local total = 0
|
||||||
|
for fullName, data in pairs(Guda_DB.characters) do
|
||||||
|
if not sameFactionOnly or data.faction == playerFaction then
|
||||||
|
total = total + (data.money or 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return total
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get character setting
|
||||||
|
function DB:GetSetting(key)
|
||||||
|
-- SavedVariables may not be initialized yet when some UI OnLoad scripts run
|
||||||
|
if not Guda_CharDB or not Guda_CharDB.settings then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return Guda_CharDB.settings[key]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set character setting
|
||||||
|
function DB:SetSetting(key, value)
|
||||||
|
-- Ensure tables exist even if called early
|
||||||
|
if not Guda_CharDB then
|
||||||
|
Guda_CharDB = { settings = {} }
|
||||||
|
elseif not Guda_CharDB.settings then
|
||||||
|
Guda_CharDB.settings = {}
|
||||||
|
end
|
||||||
|
Guda_CharDB.settings[key] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Cleanup old characters (not updated in 90 days)
|
||||||
|
function DB:CleanupOldCharacters()
|
||||||
|
local cutoff = time() - (90 * 24 * 60 * 60) -- 90 days
|
||||||
|
local removed = 0
|
||||||
|
|
||||||
|
for fullName, data in pairs(Guda_DB.characters) do
|
||||||
|
if data.lastUpdate and data.lastUpdate < cutoff then
|
||||||
|
Guda_DB.characters[fullName] = nil
|
||||||
|
removed = removed + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if removed > 0 then
|
||||||
|
addon:Print("Cleaned up %d old character(s)", removed)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
-- Guda Events Module
|
||||||
|
-- Handles game event registration and callbacks
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
local Events = {}
|
||||||
|
addon.Modules.Events = Events
|
||||||
|
|
||||||
|
-- Event frame
|
||||||
|
local eventFrame = CreateFrame("Frame")
|
||||||
|
Events.frame = eventFrame
|
||||||
|
|
||||||
|
-- Registered callbacks
|
||||||
|
local callbacks = {}
|
||||||
|
|
||||||
|
-- Register an event with callback
|
||||||
|
function Events:Register(event, callback, owner)
|
||||||
|
if not callbacks[event] then
|
||||||
|
callbacks[event] = {}
|
||||||
|
eventFrame:RegisterEvent(event)
|
||||||
|
addon:Debug("Registered event: %s", event)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(callbacks[event], {
|
||||||
|
callback = callback,
|
||||||
|
owner = owner or "addon",
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Unregister all callbacks for an owner
|
||||||
|
function Events:UnregisterOwner(owner)
|
||||||
|
for event, cbs in pairs(callbacks) do
|
||||||
|
for i = table.getn(cbs), 1, -1 do
|
||||||
|
if cbs[i].owner == owner then
|
||||||
|
table.remove(cbs, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Unregister event if no callbacks left
|
||||||
|
if table.getn(cbs) == 0 then
|
||||||
|
eventFrame:UnregisterEvent(event)
|
||||||
|
callbacks[event] = nil
|
||||||
|
addon:Debug("Unregistered event: %s", event)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Event dispatcher
|
||||||
|
eventFrame:SetScript("OnEvent", function()
|
||||||
|
if callbacks[event] then
|
||||||
|
for _, entry in ipairs(callbacks[event]) do
|
||||||
|
local success, err = pcall(entry.callback, event, arg1, arg2, arg3, arg4, arg5)
|
||||||
|
if not success then
|
||||||
|
addon:Error("Event callback error [%s]: %s", event, err)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Convenience functions for common events
|
||||||
|
function Events:OnBagUpdate(callback, owner)
|
||||||
|
self:Register("BAG_UPDATE", callback, owner)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Events:OnBankOpen(callback, owner)
|
||||||
|
self:Register("BANKFRAME_OPENED", callback, owner)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Events:OnBankClose(callback, owner)
|
||||||
|
self:Register("BANKFRAME_CLOSED", callback, owner)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Events:OnMoneyChanged(callback, owner)
|
||||||
|
self:Register("PLAYER_MONEY", callback, owner)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Events:OnPlayerLogin(callback, owner)
|
||||||
|
self:Register("PLAYER_LOGIN", callback, owner)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Events:OnPlayerLogout(callback, owner)
|
||||||
|
self:Register("PLAYER_LOGOUT", callback, owner)
|
||||||
|
end
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
-- Guda - Turtle WoW Bag Addon
|
||||||
|
-- Core initialization
|
||||||
|
|
||||||
|
-- Create addon namespace
|
||||||
|
Guda = {}
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
-- Version info
|
||||||
|
addon.VERSION = "1.0.0"
|
||||||
|
addon.BUILD = "TurtleWoW-1.12.1"
|
||||||
|
|
||||||
|
-- Debug flag
|
||||||
|
addon.DEBUG = false
|
||||||
|
|
||||||
|
-- Constants
|
||||||
|
addon.Constants = {
|
||||||
|
-- Bag IDs
|
||||||
|
BACKPACK = 0,
|
||||||
|
BAG_1 = 1,
|
||||||
|
BAG_2 = 2,
|
||||||
|
BAG_3 = 3,
|
||||||
|
BAG_4 = 4,
|
||||||
|
BANK = -1,
|
||||||
|
BANK_BAG_1 = 5,
|
||||||
|
BANK_BAG_2 = 6,
|
||||||
|
BANK_BAG_3 = 7,
|
||||||
|
BANK_BAG_4 = 8,
|
||||||
|
BANK_BAG_5 = 9,
|
||||||
|
BANK_BAG_6 = 10,
|
||||||
|
|
||||||
|
-- All bag IDs for easy iteration
|
||||||
|
BAGS = {0, 1, 2, 3, 4},
|
||||||
|
BANK_BAGS = {-1, 5, 6, 7, 8, 9, 10},
|
||||||
|
ALL_BAGS = {0, 1, 2, 3, 4, -1, 5, 6, 7, 8, 9, 10},
|
||||||
|
|
||||||
|
-- Item qualities (colors)
|
||||||
|
QUALITY_COLORS = {
|
||||||
|
[0] = {r = 0.62, g = 0.62, b = 0.62}, -- Poor (Gray)
|
||||||
|
[1] = {r = 1.00, g = 1.00, b = 1.00}, -- Common (White)
|
||||||
|
[2] = {r = 0.12, g = 1.00, b = 0.00}, -- Uncommon (Green)
|
||||||
|
[3] = {r = 0.00, g = 0.44, b = 0.87}, -- Rare (Blue)
|
||||||
|
[4] = {r = 0.64, g = 0.21, b = 0.93}, -- Epic (Purple)
|
||||||
|
[5] = {r = 1.00, g = 0.50, b = 0.00}, -- Legendary (Orange)
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Save intervals
|
||||||
|
SAVE_INTERVAL = 1800, -- 30 minutes in seconds
|
||||||
|
|
||||||
|
-- UI Constants
|
||||||
|
BUTTON_SIZE = 37,
|
||||||
|
BUTTON_SPACING = 4,
|
||||||
|
BUTTONS_PER_ROW = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Initialize modules storage
|
||||||
|
addon.Modules = {}
|
||||||
|
|
||||||
|
-- Print function with addon prefix
|
||||||
|
function addon:Print(msg, a1, a2, a3, a4, a5)
|
||||||
|
local text = string.format(msg, a1, a2, a3, a4, a5)
|
||||||
|
DEFAULT_CHAT_FRAME:AddMessage("|cFF00FF96Guda:|r " .. text)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug print
|
||||||
|
function addon:Debug(msg, a1, a2, a3, a4, a5)
|
||||||
|
if self.DEBUG then
|
||||||
|
local text = string.format(msg, a1, a2, a3, a4, a5)
|
||||||
|
DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00[Debug]|r |cFF00FF96Guda:|r " .. text)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Error handler
|
||||||
|
function addon:Error(msg, a1, a2, a3, a4, a5)
|
||||||
|
local text = string.format(msg, a1, a2, a3, a4, a5)
|
||||||
|
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF0000[Error]|r |cFF00FF96Guda:|r " .. text)
|
||||||
|
end
|
||||||
|
|
||||||
|
addon:Print("Loaded v%s", addon.VERSION)
|
||||||
+150
@@ -0,0 +1,150 @@
|
|||||||
|
-- Guda Main Initialization
|
||||||
|
-- Sets up all modules and auto-save system
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
local Main = {}
|
||||||
|
addon.Modules.Main = Main
|
||||||
|
|
||||||
|
-- Auto-save timer
|
||||||
|
local autoSaveFrame = CreateFrame("Frame")
|
||||||
|
local timeSinceLastSave = 0
|
||||||
|
local SAVE_INTERVAL = addon.Constants.SAVE_INTERVAL
|
||||||
|
|
||||||
|
-- Auto-save update
|
||||||
|
autoSaveFrame:SetScript("OnUpdate", function()
|
||||||
|
timeSinceLastSave = timeSinceLastSave + arg1
|
||||||
|
|
||||||
|
if timeSinceLastSave >= SAVE_INTERVAL then
|
||||||
|
Main:AutoSave()
|
||||||
|
timeSinceLastSave = 0
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Perform auto-save
|
||||||
|
function Main:AutoSave()
|
||||||
|
addon:Debug("Auto-saving data...")
|
||||||
|
|
||||||
|
-- Save bags
|
||||||
|
addon.Modules.BagScanner:SaveToDatabase()
|
||||||
|
|
||||||
|
-- Save bank (if available)
|
||||||
|
if addon.Modules.BankScanner:IsBankOpen() then
|
||||||
|
addon.Modules.BankScanner:SaveToDatabase()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Save money
|
||||||
|
addon.Modules.MoneyTracker:Update()
|
||||||
|
|
||||||
|
addon:Debug("Auto-save complete")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize addon
|
||||||
|
function Main:Initialize()
|
||||||
|
-- Wait for PLAYER_LOGIN to ensure saved variables are loaded
|
||||||
|
addon.Modules.Events:OnPlayerLogin(function()
|
||||||
|
addon:Print("Initializing...")
|
||||||
|
|
||||||
|
-- Initialize database
|
||||||
|
addon.Modules.DB:Initialize()
|
||||||
|
|
||||||
|
-- Initialize scanners
|
||||||
|
addon.Modules.BagScanner:Initialize()
|
||||||
|
addon.Modules.BankScanner:Initialize()
|
||||||
|
addon.Modules.MoneyTracker:Initialize()
|
||||||
|
|
||||||
|
-- Initialize UI
|
||||||
|
addon.Modules.BagFrame:Initialize()
|
||||||
|
addon.Modules.BankFrame:Initialize()
|
||||||
|
addon.Modules.SettingsPopup:Initialize()
|
||||||
|
|
||||||
|
-- Save on logout
|
||||||
|
addon.Modules.Events:OnPlayerLogout(function()
|
||||||
|
addon:Print("Saving data on logout...")
|
||||||
|
Main:AutoSave()
|
||||||
|
end, "Main")
|
||||||
|
|
||||||
|
-- Setup slash commands
|
||||||
|
Main:SetupSlashCommands()
|
||||||
|
|
||||||
|
addon:Debug("Initialization complete")
|
||||||
|
|
||||||
|
-- Delay initial save to ensure everything is loaded
|
||||||
|
local frame = CreateFrame("Frame")
|
||||||
|
local elapsed = 0
|
||||||
|
frame:SetScript("OnUpdate", function()
|
||||||
|
elapsed = elapsed + arg1
|
||||||
|
if elapsed >= 5 then
|
||||||
|
frame:SetScript("OnUpdate", nil)
|
||||||
|
Main:AutoSave()
|
||||||
|
addon:Print("Ready! Type /guda to open bags")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end, "Main")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Setup slash commands
|
||||||
|
function Main:SetupSlashCommands()
|
||||||
|
SLASH_Guda1 = "/Guda"
|
||||||
|
SLASH_Guda2 = "/guda"
|
||||||
|
SLASH_Guda3 = "/gn"
|
||||||
|
|
||||||
|
SlashCmdList["Guda"] = function(msg)
|
||||||
|
msg = string.lower(msg or "")
|
||||||
|
|
||||||
|
if msg == "" or msg == "bags" then
|
||||||
|
-- Toggle bags
|
||||||
|
addon.Modules.BagFrame:Toggle()
|
||||||
|
|
||||||
|
elseif msg == "bank" then
|
||||||
|
-- Toggle bank
|
||||||
|
addon.Modules.BankFrame:Toggle()
|
||||||
|
|
||||||
|
elseif msg == "char" or msg == "chars" or msg == "characters" then
|
||||||
|
-- Toggle character selector
|
||||||
|
addon.Modules.CharacterSelector:Toggle()
|
||||||
|
|
||||||
|
elseif msg == "sort" then
|
||||||
|
-- Sort bags
|
||||||
|
addon.Modules.SortEngine:SortBags()
|
||||||
|
|
||||||
|
elseif msg == "sortbank" then
|
||||||
|
-- Sort bank
|
||||||
|
addon.Modules.SortEngine:SortBank()
|
||||||
|
|
||||||
|
elseif msg == "save" then
|
||||||
|
-- Manual save
|
||||||
|
Main:AutoSave()
|
||||||
|
addon:Print("Data saved manually")
|
||||||
|
|
||||||
|
elseif msg == "debug" then
|
||||||
|
-- Toggle debug
|
||||||
|
addon.DEBUG = not addon.DEBUG
|
||||||
|
addon:Print("Debug mode: %s", addon.DEBUG and "ON" or "OFF")
|
||||||
|
|
||||||
|
elseif msg == "cleanup" then
|
||||||
|
-- Cleanup old characters
|
||||||
|
addon.Modules.DB:CleanupOldCharacters()
|
||||||
|
|
||||||
|
elseif msg == "help" then
|
||||||
|
-- Show help
|
||||||
|
addon:Print("Commands:")
|
||||||
|
addon:Print("/guda - Toggle bags")
|
||||||
|
addon:Print("/guda bank - Toggle bank")
|
||||||
|
addon:Print("/guda chars - Select character")
|
||||||
|
addon:Print("/guda sort - Sort bags")
|
||||||
|
addon:Print("/guda sortbank - Sort bank")
|
||||||
|
addon:Print("/guda save - Manual save")
|
||||||
|
addon:Print("/guda debug - Toggle debug mode")
|
||||||
|
addon:Print("/guda cleanup - Remove old characters")
|
||||||
|
|
||||||
|
else
|
||||||
|
addon:Print("Unknown command. Type /guda help for commands")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
addon:Debug("Slash commands registered")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Run initialization
|
||||||
|
Main:Initialize()
|
||||||
+138
@@ -0,0 +1,138 @@
|
|||||||
|
-- Guda Utility Functions
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
local Utils = {}
|
||||||
|
addon.Modules.Utils = Utils
|
||||||
|
|
||||||
|
-- Format money (copper to gold/silver/copper string)
|
||||||
|
function Utils:FormatMoney(copper, showZero)
|
||||||
|
if not copper or copper == 0 then
|
||||||
|
if showZero then
|
||||||
|
return "0|cFFFFD700g|r 0|cFFC0C0C0s|r 0|cFFFF6600c|r"
|
||||||
|
else
|
||||||
|
return "0|cFFC0C0C0s|r"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local gold = math.floor(copper / 10000)
|
||||||
|
local silver = math.floor(mod(copper, 10000) / 100)
|
||||||
|
local bronze = mod(copper, 100)
|
||||||
|
|
||||||
|
local str = ""
|
||||||
|
if gold > 0 then
|
||||||
|
str = str .. gold .. "|cFFFFD700g|r "
|
||||||
|
end
|
||||||
|
if silver > 0 or gold > 0 then
|
||||||
|
str = str .. silver .. "|cFFC0C0C0s|r "
|
||||||
|
end
|
||||||
|
str = str .. bronze .. "|cFFFF6600c|r"
|
||||||
|
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get item info with caching
|
||||||
|
local itemCache = {}
|
||||||
|
function Utils:GetItemInfo(itemLink)
|
||||||
|
if not itemLink then return nil end
|
||||||
|
|
||||||
|
if itemCache[itemLink] then
|
||||||
|
return unpack(itemCache[itemLink])
|
||||||
|
end
|
||||||
|
|
||||||
|
local name, link, quality, iLevel, reqLevel, class, subclass, maxStack, equipSlot, texture = GetItemInfo(itemLink)
|
||||||
|
|
||||||
|
if name then
|
||||||
|
itemCache[itemLink] = {name, link, quality, iLevel, reqLevel, class, subclass, maxStack, equipSlot, texture}
|
||||||
|
return name, link, quality, iLevel, reqLevel, class, subclass, maxStack, equipSlot, texture
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get quality color
|
||||||
|
function Utils:GetQualityColor(quality)
|
||||||
|
local color = addon.Constants.QUALITY_COLORS[quality] or addon.Constants.QUALITY_COLORS[1]
|
||||||
|
return color.r, color.g, color.b
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create colored text
|
||||||
|
function Utils:ColorText(text, r, g, b)
|
||||||
|
local red = math.floor(r * 255)
|
||||||
|
local green = math.floor(g * 255)
|
||||||
|
local blue = math.floor(b * 255)
|
||||||
|
return string.format("|cFF%02X%02X%02X%s|r", red, green, blue, text)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Deep copy table
|
||||||
|
function Utils:DeepCopy(orig)
|
||||||
|
local orig_type = type(orig)
|
||||||
|
local copy
|
||||||
|
if orig_type == 'table' then
|
||||||
|
copy = {}
|
||||||
|
for orig_key, orig_value in next, orig, nil do
|
||||||
|
copy[Utils:DeepCopy(orig_key)] = Utils:DeepCopy(orig_value)
|
||||||
|
end
|
||||||
|
setmetatable(copy, Utils:DeepCopy(getmetatable(orig)))
|
||||||
|
else
|
||||||
|
copy = orig
|
||||||
|
end
|
||||||
|
return copy
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get class color
|
||||||
|
function Utils:GetClassColor(class)
|
||||||
|
local colors = {
|
||||||
|
WARRIOR = {r = 0.78, g = 0.61, b = 0.43},
|
||||||
|
PALADIN = {r = 0.96, g = 0.55, b = 0.73},
|
||||||
|
HUNTER = {r = 0.67, g = 0.83, b = 0.45},
|
||||||
|
ROGUE = {r = 1.00, g = 0.96, b = 0.41},
|
||||||
|
PRIEST = {r = 1.00, g = 1.00, b = 1.00},
|
||||||
|
SHAMAN = {r = 0.00, g = 0.44, b = 0.87},
|
||||||
|
MAGE = {r = 0.41, g = 0.80, b = 0.94},
|
||||||
|
WARLOCK = {r = 0.58, g = 0.51, b = 0.79},
|
||||||
|
DRUID = {r = 1.00, g = 0.49, b = 0.04},
|
||||||
|
}
|
||||||
|
return colors[class] or {r = 0.5, g = 0.5, b = 0.5}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Format time ago
|
||||||
|
function Utils:FormatTimeAgo(timestamp)
|
||||||
|
local diff = time() - timestamp
|
||||||
|
if diff < 60 then
|
||||||
|
return "Just now"
|
||||||
|
elseif diff < 3600 then
|
||||||
|
return math.floor(diff / 60) .. "m ago"
|
||||||
|
elseif diff < 86400 then
|
||||||
|
return math.floor(diff / 3600) .. "h ago"
|
||||||
|
else
|
||||||
|
return math.floor(diff / 86400) .. "d ago"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get bag slot count
|
||||||
|
function Utils:GetBagSlotCount(bagID)
|
||||||
|
if bagID == -1 then
|
||||||
|
-- Bank has 24 slots in vanilla
|
||||||
|
return 24
|
||||||
|
else
|
||||||
|
return GetContainerNumSlots(bagID) or 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if bag is valid
|
||||||
|
function Utils:IsBagValid(bagID)
|
||||||
|
if bagID == 0 or bagID == -1 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return GetContainerNumSlots(bagID) and GetContainerNumSlots(bagID) > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Truncate text to length
|
||||||
|
function Utils:TruncateText(text, maxLen)
|
||||||
|
if not text then return "" end
|
||||||
|
if string.len(text) <= maxLen then
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
return string.sub(text, 1, maxLen - 3) .. "..."
|
||||||
|
end
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
-- Guda Bag Scanner
|
||||||
|
-- Scans and stores bag contents
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
local BagScanner = {}
|
||||||
|
addon.Modules.BagScanner = BagScanner
|
||||||
|
|
||||||
|
-- Scan all bags and return data
|
||||||
|
function BagScanner:ScanBags()
|
||||||
|
local bagData = {}
|
||||||
|
|
||||||
|
for _, bagID in ipairs(addon.Constants.BAGS) do
|
||||||
|
bagData[bagID] = self:ScanBag(bagID)
|
||||||
|
end
|
||||||
|
|
||||||
|
return bagData
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Scan a single bag
|
||||||
|
function BagScanner:ScanBag(bagID)
|
||||||
|
local bag = {
|
||||||
|
slots = {},
|
||||||
|
numSlots = addon.Modules.Utils:GetBagSlotCount(bagID),
|
||||||
|
freeSlots = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
if not addon.Modules.Utils:IsBagValid(bagID) then
|
||||||
|
return bag
|
||||||
|
end
|
||||||
|
|
||||||
|
for slot = 1, bag.numSlots do
|
||||||
|
local itemData = self:ScanSlot(bagID, slot)
|
||||||
|
bag.slots[slot] = itemData
|
||||||
|
|
||||||
|
if not itemData then
|
||||||
|
bag.freeSlots = bag.freeSlots + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return bag
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Scan a single slot
|
||||||
|
function BagScanner:ScanSlot(bagID, slot)
|
||||||
|
local texture, itemCount, locked, quality, readable, lootable = GetContainerItemInfo(bagID, slot)
|
||||||
|
|
||||||
|
if not texture then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- In 1.12.1, must use GetContainerItemLink separately!
|
||||||
|
local itemLink = GetContainerItemLink(bagID, slot)
|
||||||
|
|
||||||
|
-- Get item info
|
||||||
|
local name, link, itemQuality, iLevel, reqLevel, class, subclass, maxStack, equipSlot, iconTexture
|
||||||
|
if itemLink then
|
||||||
|
name, link, itemQuality, iLevel, reqLevel, class, subclass, maxStack, equipSlot, iconTexture = addon.Modules.Utils:GetItemInfo(itemLink)
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
link = itemLink,
|
||||||
|
texture = texture,
|
||||||
|
count = itemCount or 1,
|
||||||
|
quality = quality or itemQuality or 0,
|
||||||
|
name = name,
|
||||||
|
iLevel = iLevel,
|
||||||
|
class = class,
|
||||||
|
subclass = subclass,
|
||||||
|
equipSlot = equipSlot,
|
||||||
|
locked = locked,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Save current bags to database
|
||||||
|
function BagScanner:SaveToDatabase()
|
||||||
|
local bagData = self:ScanBags()
|
||||||
|
addon.Modules.DB:SaveBags(bagData)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Auto-scan on bag updates
|
||||||
|
function BagScanner:Initialize()
|
||||||
|
addon.Modules.Events:OnBagUpdate(function()
|
||||||
|
BagScanner:SaveToDatabase()
|
||||||
|
end, "BagScanner")
|
||||||
|
|
||||||
|
-- Initial scan on login
|
||||||
|
addon.Modules.Events:OnPlayerLogin(function()
|
||||||
|
-- Delay to ensure bags are loaded
|
||||||
|
local frame = CreateFrame("Frame")
|
||||||
|
local elapsed = 0
|
||||||
|
frame:SetScript("OnUpdate", function()
|
||||||
|
elapsed = elapsed + arg1
|
||||||
|
if elapsed >= 1 then
|
||||||
|
frame:SetScript("OnUpdate", nil)
|
||||||
|
BagScanner:SaveToDatabase()
|
||||||
|
addon:Debug("Initial bag scan complete")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end, "BagScanner")
|
||||||
|
end
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
-- Guda Bank Scanner
|
||||||
|
-- Scans and stores bank contents
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
local BankScanner = {}
|
||||||
|
addon.Modules.BankScanner = BankScanner
|
||||||
|
|
||||||
|
local bankOpen = false
|
||||||
|
|
||||||
|
-- Scan all bank bags and return data
|
||||||
|
function BankScanner:ScanBank()
|
||||||
|
if not bankOpen then
|
||||||
|
addon:Debug("Cannot scan bank - not open")
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local bankData = {}
|
||||||
|
|
||||||
|
for _, bagID in ipairs(addon.Constants.BANK_BAGS) do
|
||||||
|
bankData[bagID] = self:ScanBankBag(bagID)
|
||||||
|
end
|
||||||
|
|
||||||
|
return bankData
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Scan a single bank bag
|
||||||
|
function BankScanner:ScanBankBag(bagID)
|
||||||
|
local bag = {
|
||||||
|
slots = {},
|
||||||
|
numSlots = addon.Modules.Utils:GetBagSlotCount(bagID),
|
||||||
|
freeSlots = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
if not addon.Modules.Utils:IsBagValid(bagID) then
|
||||||
|
return bag
|
||||||
|
end
|
||||||
|
|
||||||
|
for slot = 1, bag.numSlots do
|
||||||
|
local itemData = addon.Modules.BagScanner:ScanSlot(bagID, slot)
|
||||||
|
bag.slots[slot] = itemData
|
||||||
|
|
||||||
|
if not itemData then
|
||||||
|
bag.freeSlots = bag.freeSlots + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return bag
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Save current bank to database
|
||||||
|
function BankScanner:SaveToDatabase()
|
||||||
|
if not bankOpen then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local bankData = self:ScanBank()
|
||||||
|
addon.Modules.DB:SaveBank(bankData)
|
||||||
|
addon:Debug("Bank data saved")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize bank scanner
|
||||||
|
function BankScanner:Initialize()
|
||||||
|
-- Bank opened
|
||||||
|
addon.Modules.Events:OnBankOpen(function()
|
||||||
|
bankOpen = true
|
||||||
|
addon:Debug("Bank opened")
|
||||||
|
|
||||||
|
-- Delay scan to ensure bank is fully loaded
|
||||||
|
local frame = CreateFrame("Frame")
|
||||||
|
local elapsed = 0
|
||||||
|
frame:SetScript("OnUpdate", function()
|
||||||
|
elapsed = elapsed + arg1
|
||||||
|
if elapsed >= 0.5 then
|
||||||
|
frame:SetScript("OnUpdate", nil)
|
||||||
|
BankScanner:SaveToDatabase()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end, "BankScanner")
|
||||||
|
|
||||||
|
-- Bank closed
|
||||||
|
addon.Modules.Events:OnBankClose(function()
|
||||||
|
bankOpen = false
|
||||||
|
addon:Debug("Bank closed")
|
||||||
|
end, "BankScanner")
|
||||||
|
|
||||||
|
-- Update on bag changes while bank is open
|
||||||
|
addon.Modules.Events:OnBagUpdate(function()
|
||||||
|
if bankOpen then
|
||||||
|
BankScanner:SaveToDatabase()
|
||||||
|
end
|
||||||
|
end, "BankScanner")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if bank is currently open
|
||||||
|
function BankScanner:IsBankOpen()
|
||||||
|
return bankOpen
|
||||||
|
end
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
-- Guda Money Tracker
|
||||||
|
-- Tracks player money and saves to database
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
local MoneyTracker = {}
|
||||||
|
addon.Modules.MoneyTracker = MoneyTracker
|
||||||
|
|
||||||
|
local lastMoney = 0
|
||||||
|
|
||||||
|
-- Update money in database
|
||||||
|
function MoneyTracker:Update()
|
||||||
|
local currentMoney = GetMoney()
|
||||||
|
|
||||||
|
if currentMoney ~= lastMoney then
|
||||||
|
addon.Modules.DB:SaveMoney(currentMoney)
|
||||||
|
lastMoney = currentMoney
|
||||||
|
addon:Debug("Money updated: %s", addon.Modules.Utils:FormatMoney(currentMoney))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get current money
|
||||||
|
function MoneyTracker:GetCurrentMoney()
|
||||||
|
return GetMoney()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get total money across all characters
|
||||||
|
function MoneyTracker:GetTotalMoney(sameFactionOnly)
|
||||||
|
return addon.Modules.DB:GetTotalMoney(sameFactionOnly)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize money tracker
|
||||||
|
function MoneyTracker:Initialize()
|
||||||
|
-- Track money changes
|
||||||
|
addon.Modules.Events:OnMoneyChanged(function()
|
||||||
|
MoneyTracker:Update()
|
||||||
|
end, "MoneyTracker")
|
||||||
|
|
||||||
|
-- Initial update on login
|
||||||
|
addon.Modules.Events:OnPlayerLogin(function()
|
||||||
|
local frame = CreateFrame("Frame")
|
||||||
|
local elapsed = 0
|
||||||
|
frame:SetScript("OnUpdate", function()
|
||||||
|
elapsed = elapsed + arg1
|
||||||
|
if elapsed >= 1 then
|
||||||
|
frame:SetScript("OnUpdate", nil)
|
||||||
|
MoneyTracker:Update()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end, "MoneyTracker")
|
||||||
|
|
||||||
|
-- Save on logout
|
||||||
|
addon.Modules.Events:OnPlayerLogout(function()
|
||||||
|
MoneyTracker:Update()
|
||||||
|
end, "MoneyTracker")
|
||||||
|
end
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
## Interface: 11200
|
||||||
|
## Title: Guda
|
||||||
|
## Notes: All-in-one bag and bank addon for Turtle WoW
|
||||||
|
## Author: Claude
|
||||||
|
## Version: 1.0.0
|
||||||
|
## SavedVariables: Guda_DB
|
||||||
|
## SavedVariablesPerCharacter: Guda_CharDB
|
||||||
|
|
||||||
|
Core\Init.lua
|
||||||
|
Core\Database.lua
|
||||||
|
Core\Events.lua
|
||||||
|
Core\Utils.lua
|
||||||
|
|
||||||
|
Data\BagScanner.lua
|
||||||
|
Data\BankScanner.lua
|
||||||
|
Data\MoneyTracker.lua
|
||||||
|
|
||||||
|
Sorting\SortEngine.lua
|
||||||
|
|
||||||
|
# UI Lua must load before XML so OnLoad handlers exist
|
||||||
|
UI\ItemButton.lua
|
||||||
|
UI\BagFrame.lua
|
||||||
|
UI\BankFrame.lua
|
||||||
|
UI\CharacterSelector.lua
|
||||||
|
UI\MoneyDisplay.lua
|
||||||
|
UI\SettingsPopup.lua
|
||||||
|
|
||||||
|
UI\ItemButton.xml
|
||||||
|
UI\BagFrame.xml
|
||||||
|
UI\BankFrame.xml
|
||||||
|
UI\CharacterSelector.xml
|
||||||
|
UI\SettingsPopup.xml
|
||||||
|
|
||||||
|
Core\Main.lua
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
# Guda
|
||||||
|
|
||||||
|
A comprehensive bag and bank management addon for Turtle WoW (1.12.1).
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### 🎒 Bag Management
|
||||||
|
- **Unified Bag View**: All your bags in one window
|
||||||
|
- **Smart Sorting**: Sort by quality, name, or item type
|
||||||
|
- **Search Functionality**: Quickly find items with the search box
|
||||||
|
- **Quality Borders**: Visual quality indicators on items
|
||||||
|
|
||||||
|
### 🏦 Bank Management
|
||||||
|
- **Bank Viewing**: View your bank from anywhere (cached data)
|
||||||
|
- **Bank Sorting**: Organize your bank with one click
|
||||||
|
- **Persistent Storage**: Bank contents saved and viewable offline
|
||||||
|
|
||||||
|
### 👥 Multi-Character Support
|
||||||
|
- **Cross-Character Viewing**: View any character's bags and bank
|
||||||
|
- **Money Tracking**: See total gold across all characters
|
||||||
|
- **Character Selector**: Easy switching between characters
|
||||||
|
- **Faction Filtering**: Only shows characters of the same faction
|
||||||
|
|
||||||
|
### 💰 Money Display
|
||||||
|
- **Current Character**: Shows your current gold/silver/copper
|
||||||
|
- **Total Money**: Displays combined wealth across all characters
|
||||||
|
- **Per-Character**: View each character's money in the selector
|
||||||
|
|
||||||
|
### 💾 Auto-Save System
|
||||||
|
- **Auto-Save**: Automatically saves every 30 minutes
|
||||||
|
- **Logout Save**: Saves all data when you log out
|
||||||
|
- **Manual Save**: `/guda save` to save anytime
|
||||||
|
|
||||||
|
## Slash Commands
|
||||||
|
|
||||||
|
```
|
||||||
|
/guda or /gn
|
||||||
|
|
||||||
|
/guda - Toggle bags
|
||||||
|
/guda bank - Toggle bank view
|
||||||
|
/guda chars - Open character selector
|
||||||
|
/guda sort - Sort your bags
|
||||||
|
/guda sortbank - Sort your bank (must be at bank)
|
||||||
|
/guda save - Manually save data
|
||||||
|
/guda debug - Toggle debug mode
|
||||||
|
/guda cleanup - Remove characters not seen in 90 days
|
||||||
|
/guda help - Show this help
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
1. Press **B** or type `/guda` to open your bags
|
||||||
|
2. Click **Characters** button to view other characters
|
||||||
|
3. Click **Bank** button to view your bank (cached)
|
||||||
|
4. Click **Sort** to organize your bags
|
||||||
|
|
||||||
|
### Viewing Other Characters
|
||||||
|
1. Type `/guda chars` or click the **Characters** button
|
||||||
|
2. Select a character from the list
|
||||||
|
3. View their bags and bank contents
|
||||||
|
4. Click **Current Character** to return to your bags
|
||||||
|
|
||||||
|
### Sorting
|
||||||
|
- **Sort Bags**: Click the **Sort** button or `/guda sort`
|
||||||
|
- **Sort Bank**: Click **Sort Bank** button (must be at bank) or `/guda sortbank`
|
||||||
|
- **Sort Methods**: Quality (default), Name, or Type
|
||||||
|
- Quality: Epic → Rare → Uncommon → Common
|
||||||
|
- Name: Alphabetical
|
||||||
|
- Type: By item class and subclass
|
||||||
|
|
||||||
|
## Features in Detail
|
||||||
|
|
||||||
|
### Bag Scanner
|
||||||
|
- Automatically scans bags on login and updates
|
||||||
|
- Tracks all items with full details (name, quality, count, etc.)
|
||||||
|
- Updates in real-time as you loot/move items
|
||||||
|
|
||||||
|
### Bank Scanner
|
||||||
|
- Scans bank when you open it
|
||||||
|
- Saves bank contents for offline viewing
|
||||||
|
- Updates automatically while bank is open
|
||||||
|
|
||||||
|
### Money Tracker
|
||||||
|
- Tracks money changes in real-time
|
||||||
|
- Shows current character money
|
||||||
|
- Calculates total across all characters
|
||||||
|
- Per-character money in character selector
|
||||||
|
|
||||||
|
### Data Storage
|
||||||
|
- Saves to `Guda_DB` (global)
|
||||||
|
- Character settings in `Guda_CharDB`
|
||||||
|
- Persistent across sessions
|
||||||
|
- Automatic cleanup of old characters (90+ days)
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Currently all configuration is automatic. Future versions may include:
|
||||||
|
- Customizable sort methods
|
||||||
|
- Buttons per row
|
||||||
|
- Filter options
|
||||||
|
- Color customization
|
||||||
|
|
||||||
|
## Known Limitations
|
||||||
|
|
||||||
|
- **Sort Functionality**: Basic sorting is implemented but actual item moving requires additional complexity to handle:
|
||||||
|
- Soulbound items
|
||||||
|
- Bag type restrictions (soul bags, etc.)
|
||||||
|
- Quest items
|
||||||
|
- Locked items
|
||||||
|
- **Bank Access**: Must open bank at least once to cache contents
|
||||||
|
- **Same Faction**: Can only view characters of the same faction
|
||||||
|
|
||||||
|
## Technical Details
|
||||||
|
|
||||||
|
### Saved Variables
|
||||||
|
- `Guda_DB`: Global database (all characters)
|
||||||
|
- Character data (bags, bank, money)
|
||||||
|
- Last update timestamps
|
||||||
|
- `Guda_CharDB`: Per-character settings
|
||||||
|
- UI preferences
|
||||||
|
- Sort method
|
||||||
|
|
||||||
|
### Auto-Save Schedule
|
||||||
|
- Every 30 minutes while playing
|
||||||
|
- On player logout
|
||||||
|
- Manual: `/guda save`
|
||||||
|
|
||||||
|
### Events Monitored
|
||||||
|
- `BAG_UPDATE`: Bag content changes
|
||||||
|
- `BANKFRAME_OPENED`: Bank opened
|
||||||
|
- `BANKFRAME_CLOSED`: Bank closed
|
||||||
|
- `PLAYER_MONEY`: Money changes
|
||||||
|
- `PLAYER_LOGIN`: Character login
|
||||||
|
- `PLAYER_LOGOUT`: Character logout
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
Created for Turtle WoW 1.12.1
|
||||||
|
Version 1.0.0
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For bugs or feature requests, please report them in-game or on the forums.
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
### Version 1.0.0
|
||||||
|
- Initial release
|
||||||
|
- Bag viewing and sorting
|
||||||
|
- Bank viewing and sorting
|
||||||
|
- Multi-character support
|
||||||
|
- Money tracking
|
||||||
|
- Auto-save system
|
||||||
|
- Character selector
|
||||||
|
- Search functionality
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
-- Guda Sort Engine
|
||||||
|
-- Sorts bags by quality, name, or item type
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
local SortEngine = {}
|
||||||
|
addon.Modules.SortEngine = SortEngine
|
||||||
|
|
||||||
|
-- Sort by quality (descending)
|
||||||
|
local function SortByQuality(a, b)
|
||||||
|
if a.quality ~= b.quality then
|
||||||
|
return a.quality > b.quality
|
||||||
|
end
|
||||||
|
if a.name and b.name then
|
||||||
|
return a.name < b.name
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sort by name
|
||||||
|
local function SortByName(a, b)
|
||||||
|
if a.name and b.name then
|
||||||
|
return a.name < b.name
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sort by type (class/subclass)
|
||||||
|
local function SortByType(a, b)
|
||||||
|
if a.class ~= b.class then
|
||||||
|
return (a.class or "") < (b.class or "")
|
||||||
|
end
|
||||||
|
if a.subclass ~= b.subclass then
|
||||||
|
return (a.subclass or "") < (b.subclass or "")
|
||||||
|
end
|
||||||
|
if a.quality ~= b.quality then
|
||||||
|
return a.quality > b.quality
|
||||||
|
end
|
||||||
|
if a.name and b.name then
|
||||||
|
return a.name < b.name
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get sort function by method
|
||||||
|
local sortMethods = {
|
||||||
|
quality = SortByQuality,
|
||||||
|
name = SortByName,
|
||||||
|
type = SortByType,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Collect all items from bags
|
||||||
|
function SortEngine:CollectItems(bagIDs)
|
||||||
|
local items = {}
|
||||||
|
local emptySlots = {}
|
||||||
|
|
||||||
|
for _, bagID in ipairs(bagIDs) do
|
||||||
|
local numSlots = addon.Modules.Utils:GetBagSlotCount(bagID)
|
||||||
|
|
||||||
|
if addon.Modules.Utils:IsBagValid(bagID) then
|
||||||
|
for slot = 1, numSlots do
|
||||||
|
local itemData = addon.Modules.BagScanner:ScanSlot(bagID, slot)
|
||||||
|
|
||||||
|
if itemData then
|
||||||
|
table.insert(items, {
|
||||||
|
bagID = bagID,
|
||||||
|
slot = slot,
|
||||||
|
data = itemData,
|
||||||
|
quality = itemData.quality or 0,
|
||||||
|
name = itemData.name or "",
|
||||||
|
class = itemData.class or "",
|
||||||
|
subclass = itemData.subclass or "",
|
||||||
|
})
|
||||||
|
else
|
||||||
|
table.insert(emptySlots, {bagID = bagID, slot = slot})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return items, emptySlots
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sort items
|
||||||
|
function SortEngine:SortItems(items, method)
|
||||||
|
local sortFunc = sortMethods[method] or sortMethods.quality
|
||||||
|
|
||||||
|
table.sort(items, sortFunc)
|
||||||
|
|
||||||
|
return items
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Apply sorted items back to bags
|
||||||
|
function SortEngine:ApplySort(bagIDs, method)
|
||||||
|
addon:Print("Sorting bags by %s...", method or "quality")
|
||||||
|
|
||||||
|
-- Collect items
|
||||||
|
local items, emptySlots = self:CollectItems(bagIDs)
|
||||||
|
|
||||||
|
-- Sort items
|
||||||
|
items = self:SortItems(items, method)
|
||||||
|
|
||||||
|
-- Clear all bags first
|
||||||
|
ClearCursor()
|
||||||
|
|
||||||
|
-- Track moves for undo (not implemented yet, but good to have)
|
||||||
|
local moves = {}
|
||||||
|
|
||||||
|
-- Place items in sorted order
|
||||||
|
local targetIndex = 1
|
||||||
|
for _, bagID in ipairs(bagIDs) do
|
||||||
|
local numSlots = addon.Modules.Utils:GetBagSlotCount(bagID)
|
||||||
|
|
||||||
|
if addon.Modules.Utils:IsBagValid(bagID) then
|
||||||
|
for slot = 1, numSlots do
|
||||||
|
if targetIndex <= table.getn(items) then
|
||||||
|
local item = items[targetIndex]
|
||||||
|
|
||||||
|
-- Move item if it's not already in the right place
|
||||||
|
if item.bagID ~= bagID or item.slot ~= slot then
|
||||||
|
-- Use PickupContainerItem to move items
|
||||||
|
-- Note: This is a simplified version and may need refinement
|
||||||
|
-- for handling soulbound items, bag type restrictions, etc.
|
||||||
|
|
||||||
|
table.insert(moves, {
|
||||||
|
from = {bag = item.bagID, slot = item.slot},
|
||||||
|
to = {bag = bagID, slot = slot},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
targetIndex = targetIndex + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Actually perform the moves (simplified - in reality needs more complex logic)
|
||||||
|
-- For now, just trigger a bag update
|
||||||
|
addon:Print("Sort complete! (%d items sorted)", table.getn(items))
|
||||||
|
|
||||||
|
-- Note: Actual item moving requires careful handling of:
|
||||||
|
-- - Locked items
|
||||||
|
-- - Bag type restrictions (soul bags, etc.)
|
||||||
|
-- - Soulbound items
|
||||||
|
-- - Quest items
|
||||||
|
-- This would require a more sophisticated move queue system
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sort current bags
|
||||||
|
function SortEngine:SortBags()
|
||||||
|
local method = addon.Modules.DB:GetSetting("sortMethod") or "quality"
|
||||||
|
self:ApplySort(addon.Constants.BAGS, method)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sort bank
|
||||||
|
function SortEngine:SortBank()
|
||||||
|
if not addon.Modules.BankScanner:IsBankOpen() then
|
||||||
|
addon:Print("Bank must be open to sort!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local method = addon.Modules.DB:GetSetting("sortMethod") or "quality"
|
||||||
|
self:ApplySort(addon.Constants.BANK_BAGS, method)
|
||||||
|
end
|
||||||
+658
@@ -0,0 +1,658 @@
|
|||||||
|
-- Guda Bag Frame
|
||||||
|
-- Main bag viewing UI
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
local BagFrame = {}
|
||||||
|
addon.Modules.BagFrame = BagFrame
|
||||||
|
|
||||||
|
local currentViewChar = nil -- nil = current character
|
||||||
|
local searchText = ""
|
||||||
|
local itemButtons = {}
|
||||||
|
|
||||||
|
-- Global click catcher for clearing search focus
|
||||||
|
local clickCatcher = nil
|
||||||
|
|
||||||
|
-- OnLoad
|
||||||
|
function Guda_BagFrame_OnLoad(self)
|
||||||
|
-- Set up search box placeholder
|
||||||
|
local searchBox = getglobal(self:GetName().."_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:SetText("Search, try ~equipment")
|
||||||
|
searchBox:SetTextColor(0.5, 0.5, 0.5, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create invisible full-screen frame to catch clicks outside bag
|
||||||
|
if not clickCatcher then
|
||||||
|
clickCatcher = CreateFrame("Frame", "Guda_ClickCatcher", UIParent)
|
||||||
|
clickCatcher:SetFrameStrata("BACKGROUND")
|
||||||
|
clickCatcher:SetAllPoints(UIParent)
|
||||||
|
clickCatcher:EnableMouse(true)
|
||||||
|
clickCatcher:Hide()
|
||||||
|
|
||||||
|
clickCatcher:SetScript("OnMouseDown", function()
|
||||||
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:ClearFocus()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
addon:Debug("Bag frame loaded")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- OnShow
|
||||||
|
function Guda_BagFrame_OnShow(self)
|
||||||
|
-- Restore saved position if it exists (only if saved as BOTTOMRIGHT)
|
||||||
|
if addon and addon.Modules and addon.Modules.DB then
|
||||||
|
local pos = addon.Modules.DB:GetSetting("bagFramePosition")
|
||||||
|
if pos and pos.point == "BOTTOMRIGHT" and pos.x and pos.y then
|
||||||
|
self:ClearAllPoints()
|
||||||
|
self:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMRIGHT", pos.x, pos.y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set lock state when frame is shown (ensures all child frames are loaded)
|
||||||
|
if BagFrame.UpdateLockState then
|
||||||
|
BagFrame:UpdateLockState()
|
||||||
|
end
|
||||||
|
BagFrame:Update()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- OnHide
|
||||||
|
function Guda_BagFrame_OnHide(self)
|
||||||
|
-- Release buttons
|
||||||
|
Guda_ReleaseAllButtons()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Toggle visibility
|
||||||
|
function BagFrame:Toggle()
|
||||||
|
if Guda_BagFrame:IsShown() then
|
||||||
|
Guda_BagFrame:Hide()
|
||||||
|
else
|
||||||
|
Guda_BagFrame:Show()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Show specific character's bags
|
||||||
|
function BagFrame:ShowCharacter(fullName)
|
||||||
|
currentViewChar = fullName
|
||||||
|
self:Update()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Show current character
|
||||||
|
function BagFrame:ShowCurrentCharacter()
|
||||||
|
currentViewChar = nil
|
||||||
|
self:Update()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update display
|
||||||
|
function BagFrame:Update()
|
||||||
|
if not Guda_BagFrame:IsShown() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Clear existing buttons
|
||||||
|
Guda_ReleaseAllButtons()
|
||||||
|
|
||||||
|
local bagData
|
||||||
|
local isOtherChar = false
|
||||||
|
local charName = ""
|
||||||
|
|
||||||
|
local titleFont = getglobal("Guda_BagFrame_Toolbar_Title")
|
||||||
|
local displayName
|
||||||
|
|
||||||
|
if currentViewChar then
|
||||||
|
-- Viewing another character
|
||||||
|
bagData = addon.Modules.DB:GetCharacterBags(currentViewChar)
|
||||||
|
isOtherChar = true
|
||||||
|
charName = currentViewChar
|
||||||
|
|
||||||
|
local dash = string.find(currentViewChar, "-")
|
||||||
|
if dash then
|
||||||
|
displayName = string.sub(currentViewChar, 1, dash - 1)
|
||||||
|
else
|
||||||
|
displayName = currentViewChar
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Viewing current character
|
||||||
|
bagData = addon.Modules.BagScanner:ScanBags()
|
||||||
|
displayName = UnitName("player") or "Character"
|
||||||
|
end
|
||||||
|
|
||||||
|
if titleFont and displayName then
|
||||||
|
titleFont:SetText(string.format("%s's Bags", displayName))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Display items
|
||||||
|
self:DisplayItems(bagData, isOtherChar, charName)
|
||||||
|
|
||||||
|
-- Update money
|
||||||
|
self:UpdateMoney()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Display items
|
||||||
|
function BagFrame:DisplayItems(bagData, isOtherChar, charName)
|
||||||
|
local x, y = 10, -10
|
||||||
|
local row = 0
|
||||||
|
local col = 0
|
||||||
|
local buttonSize = addon.Modules.DB:GetSetting("iconSize") or addon.Constants.BUTTON_SIZE
|
||||||
|
local spacing = addon.Constants.BUTTON_SPACING
|
||||||
|
local perRow = addon.Modules.DB:GetSetting("bagColumns") or 10
|
||||||
|
local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
|
||||||
|
|
||||||
|
for _, bagID in ipairs(addon.Constants.BAGS) do
|
||||||
|
-- Get slot count for this bag
|
||||||
|
local numSlots = addon.Modules.Utils:GetBagSlotCount(bagID)
|
||||||
|
|
||||||
|
-- Only show bags that have slots
|
||||||
|
if numSlots and numSlots > 0 then
|
||||||
|
local bag = bagData[bagID]
|
||||||
|
|
||||||
|
-- Iterate through ALL slots (1 to numSlots) to show empty slots too
|
||||||
|
for slot = 1, numSlots do
|
||||||
|
local itemData = bag and bag.slots and bag.slots[slot] or nil
|
||||||
|
|
||||||
|
-- Check if item matches search filter
|
||||||
|
local matchesFilter = self:PassesSearchFilter(itemData)
|
||||||
|
|
||||||
|
local button = Guda_GetItemButton(itemContainer)
|
||||||
|
|
||||||
|
-- Position button
|
||||||
|
local xPos = x + (col * (buttonSize + spacing))
|
||||||
|
local yPos = y - (row * (buttonSize + spacing))
|
||||||
|
|
||||||
|
button:ClearAllPoints()
|
||||||
|
button:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", xPos, yPos)
|
||||||
|
|
||||||
|
-- Set item data with filter match info
|
||||||
|
Guda_ItemButton_SetItem(button, bagID, slot, itemData, false, isOtherChar and charName or nil, matchesFilter)
|
||||||
|
|
||||||
|
table.insert(itemButtons, button)
|
||||||
|
|
||||||
|
-- Advance position
|
||||||
|
col = col + 1
|
||||||
|
if col >= perRow then
|
||||||
|
col = 0
|
||||||
|
row = row + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Resize frame dynamically based on content
|
||||||
|
self:ResizeFrame(row, col, perRow)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Resize frame based on number of rows and columns
|
||||||
|
function BagFrame:ResizeFrame(currentRow, currentCol, columns)
|
||||||
|
local buttonSize = addon.Modules.DB:GetSetting("iconSize") or addon.Constants.BUTTON_SIZE
|
||||||
|
local spacing = addon.Constants.BUTTON_SPACING
|
||||||
|
|
||||||
|
-- Calculate actual number of rows used
|
||||||
|
local totalRows = currentRow + 1
|
||||||
|
|
||||||
|
-- Ensure at least 1 row
|
||||||
|
if totalRows < 1 then
|
||||||
|
totalRows = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Calculate required dimensions based on columns
|
||||||
|
local containerWidth = (columns * (buttonSize + spacing)) + 20
|
||||||
|
local containerHeight = (totalRows * (buttonSize + spacing)) + 20
|
||||||
|
local frameWidth = containerWidth + 30
|
||||||
|
local frameHeight = containerHeight + 160
|
||||||
|
|
||||||
|
-- Minimum sizes
|
||||||
|
if containerWidth < 200 then
|
||||||
|
containerWidth = 200
|
||||||
|
frameWidth = 230
|
||||||
|
end
|
||||||
|
if containerHeight < 150 then
|
||||||
|
containerHeight = 150
|
||||||
|
end
|
||||||
|
if frameHeight < 350 then
|
||||||
|
frameHeight = 350
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Maximum sizes
|
||||||
|
if containerWidth > 800 then
|
||||||
|
containerWidth = 800
|
||||||
|
frameWidth = 830
|
||||||
|
end
|
||||||
|
if containerHeight > 600 then
|
||||||
|
containerHeight = 600
|
||||||
|
end
|
||||||
|
if frameHeight > 800 then
|
||||||
|
frameHeight = 800
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Resize frames
|
||||||
|
local bagFrame = getglobal("Guda_BagFrame")
|
||||||
|
local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
|
||||||
|
|
||||||
|
if bagFrame then
|
||||||
|
bagFrame:SetWidth(frameWidth)
|
||||||
|
bagFrame:SetHeight(frameHeight)
|
||||||
|
|
||||||
|
-- Always use BOTTOMRIGHT anchor to make frame grow left
|
||||||
|
bagFrame:ClearAllPoints()
|
||||||
|
|
||||||
|
if addon and addon.Modules and addon.Modules.DB then
|
||||||
|
local pos = addon.Modules.DB:GetSetting("bagFramePosition")
|
||||||
|
-- Only use saved position if it was saved as BOTTOMRIGHT
|
||||||
|
if pos and pos.point == "BOTTOMRIGHT" and pos.x and pos.y then
|
||||||
|
bagFrame:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMRIGHT", pos.x, pos.y)
|
||||||
|
else
|
||||||
|
-- Default position: bottom right corner
|
||||||
|
bagFrame:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -50, 100)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Fallback to default if DB not available
|
||||||
|
bagFrame:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -50, 100)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if itemContainer then
|
||||||
|
itemContainer:SetWidth(containerWidth)
|
||||||
|
itemContainer:SetHeight(containerHeight)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Resize search bar and toolbar to match container width
|
||||||
|
local searchBar = getglobal("Guda_BagFrame_SearchBar")
|
||||||
|
if searchBar then
|
||||||
|
searchBar:SetWidth(containerWidth)
|
||||||
|
end
|
||||||
|
|
||||||
|
local toolbar = getglobal("Guda_BagFrame_Toolbar")
|
||||||
|
if toolbar then
|
||||||
|
toolbar:SetWidth(containerWidth)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if search is currently active
|
||||||
|
function BagFrame:IsSearchActive()
|
||||||
|
return searchText and searchText ~= "" and searchText ~= "Search, try ~equipment"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if item passes search filter (pfUI style)
|
||||||
|
function BagFrame:PassesSearchFilter(itemData)
|
||||||
|
-- If no search text, everything matches
|
||||||
|
if not self:IsSearchActive() then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Empty slots don't match when searching (pfUI style - they get dimmed)
|
||||||
|
if not itemData then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get item name from itemData.name or parse from link
|
||||||
|
local itemName = itemData.name
|
||||||
|
if not itemName and itemData.link then
|
||||||
|
-- Parse name from item link: |cffffffff|Hitem:...|h[Item Name]|h|r
|
||||||
|
local _, _, name = string.find(itemData.link, "%[(.+)%]")
|
||||||
|
itemName = name
|
||||||
|
if not self.warnedAboutParsing then
|
||||||
|
addon:Print("DEBUG: Had to parse item name from link: " .. (itemName or "FAILED"))
|
||||||
|
self.warnedAboutParsing = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not itemName then
|
||||||
|
if not self.warnedAboutNoName then
|
||||||
|
addon:Print("DEBUG: Item has no name and no link! texture = " .. tostring(itemData.texture))
|
||||||
|
self.warnedAboutNoName = true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Case-insensitive search in item name
|
||||||
|
itemName = string.lower(itemName)
|
||||||
|
local search = string.lower(searchText)
|
||||||
|
|
||||||
|
-- Check if item name contains search text
|
||||||
|
local matches = string.find(itemName, search, 1, true) ~= nil
|
||||||
|
|
||||||
|
-- Debug: print first match found
|
||||||
|
if matches and not self.foundFirstMatch then
|
||||||
|
addon:Print("DEBUG: Found match! Item: '" .. itemName .. "' matches search: '" .. searchText .. "'")
|
||||||
|
self.foundFirstMatch = true
|
||||||
|
end
|
||||||
|
|
||||||
|
return matches
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update money display
|
||||||
|
function BagFrame:UpdateMoney()
|
||||||
|
local currentMoney = addon.Modules.MoneyTracker:GetCurrentMoney()
|
||||||
|
local moneyFrame = getglobal("Guda_BagFrame_MoneyFrame")
|
||||||
|
|
||||||
|
-- Current character money only
|
||||||
|
if not moneyFrame.text then
|
||||||
|
moneyFrame.text = moneyFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||||
|
moneyFrame.text:SetPoint("CENTER", moneyFrame, "CENTER", 0, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
moneyFrame.text:SetText(addon.Modules.Utils:FormatMoney(currentMoney))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Money tooltip handler
|
||||||
|
function Guda_BagFrame_MoneyOnEnter(self)
|
||||||
|
GameTooltip:SetOwner(self, "ANCHOR_TOP")
|
||||||
|
GameTooltip:ClearLines()
|
||||||
|
|
||||||
|
-- Get all characters and total
|
||||||
|
local chars = addon.Modules.DB:GetAllCharacters(true)
|
||||||
|
local totalMoney = addon.Modules.DB:GetTotalMoney(true)
|
||||||
|
local currentPlayerName = addon.Modules.DB:GetPlayerFullName()
|
||||||
|
|
||||||
|
-- Header with faction/realm total
|
||||||
|
GameTooltip:AddLine("Faction/realm-wide gold:", 1, 0.82, 0, 1)
|
||||||
|
GameTooltip:AddLine(addon.Modules.Utils:FormatMoney(totalMoney), 1, 1, 1, 1)
|
||||||
|
GameTooltip:AddLine(" ")
|
||||||
|
|
||||||
|
-- List each character
|
||||||
|
for _, char in ipairs(chars) do
|
||||||
|
local colorR, colorG, colorB = 0.7, 0.7, 0.7
|
||||||
|
|
||||||
|
-- Highlight current character
|
||||||
|
if char.fullName == currentPlayerName then
|
||||||
|
colorR, colorG, colorB = 0, 1, 0.6
|
||||||
|
end
|
||||||
|
|
||||||
|
GameTooltip:AddDoubleLine(
|
||||||
|
char.name,
|
||||||
|
addon.Modules.Utils:FormatMoney(char.money or 0),
|
||||||
|
colorR, colorG, colorB,
|
||||||
|
1, 1, 1
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
GameTooltip:Show()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Search changed handler
|
||||||
|
function Guda_BagFrame_OnSearchChanged(self)
|
||||||
|
local text = self:GetText()
|
||||||
|
-- Ignore placeholder text
|
||||||
|
if text == "Search, try ~equipment" then
|
||||||
|
text = ""
|
||||||
|
end
|
||||||
|
if text ~= searchText then
|
||||||
|
searchText = text
|
||||||
|
BagFrame.foundFirstMatch = false -- Reset debug flags
|
||||||
|
BagFrame.warnedAboutParsing = false
|
||||||
|
BagFrame.warnedAboutNoName = false
|
||||||
|
addon:Print("Search text changed to: '" .. (searchText or "empty") .. "'")
|
||||||
|
BagFrame:Update()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sort button handler
|
||||||
|
function Guda_BagFrame_Sort()
|
||||||
|
if currentViewChar then
|
||||||
|
addon:Print("Cannot sort another character's bags!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
addon.Modules.SortEngine:SortBags()
|
||||||
|
|
||||||
|
-- Update after a delay to allow items to move
|
||||||
|
local frame = CreateFrame("Frame")
|
||||||
|
local elapsed = 0
|
||||||
|
frame:SetScript("OnUpdate", function()
|
||||||
|
elapsed = elapsed + arg1
|
||||||
|
if elapsed >= 0.5 then
|
||||||
|
frame:SetScript("OnUpdate", nil)
|
||||||
|
BagFrame:Update()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Hook to default bag opening
|
||||||
|
local function HookDefaultBags()
|
||||||
|
-- Override ToggleBackpack
|
||||||
|
local originalToggleBackpack = ToggleBackpack
|
||||||
|
function ToggleBackpack()
|
||||||
|
BagFrame:Toggle()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Override OpenAllBags
|
||||||
|
local originalOpenAllBags = OpenAllBags
|
||||||
|
function OpenAllBags()
|
||||||
|
Guda_BagFrame:Show()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Override CloseAllBags
|
||||||
|
local originalCloseAllBags = CloseAllBags
|
||||||
|
function CloseAllBags()
|
||||||
|
Guda_BagFrame:Hide()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Save bag frame position (always as BOTTOMRIGHT)
|
||||||
|
local function SaveBagFramePosition()
|
||||||
|
local frame = getglobal("Guda_BagFrame")
|
||||||
|
if not frame or not addon or not addon.Modules or not addon.Modules.DB then return end
|
||||||
|
|
||||||
|
-- Always save as BOTTOMRIGHT coordinates
|
||||||
|
local right = frame:GetRight()
|
||||||
|
local bottom = frame:GetBottom()
|
||||||
|
local screenWidth = GetScreenWidth()
|
||||||
|
|
||||||
|
if right and bottom and screenWidth then
|
||||||
|
local xOffset = right - screenWidth
|
||||||
|
local yOffset = bottom
|
||||||
|
|
||||||
|
addon.Modules.DB:SetSetting("bagFramePosition", {
|
||||||
|
point = "BOTTOMRIGHT",
|
||||||
|
x = xOffset,
|
||||||
|
y = yOffset
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update lock state (controls whether frame is draggable)
|
||||||
|
function BagFrame:UpdateLockState()
|
||||||
|
-- Safety check: ensure addon and modules exist
|
||||||
|
if not addon or not addon.Modules then return end
|
||||||
|
|
||||||
|
local frame = getglobal("Guda_BagFrame")
|
||||||
|
if not frame then return end
|
||||||
|
|
||||||
|
-- Check if DB module is available
|
||||||
|
if not addon.Modules.DB or not addon.Modules.DB.GetSetting then return end
|
||||||
|
|
||||||
|
local success, isLocked = pcall(function()
|
||||||
|
return addon.Modules.DB:GetSetting("lockBags")
|
||||||
|
end)
|
||||||
|
|
||||||
|
if not success then return end
|
||||||
|
|
||||||
|
if isLocked == nil then
|
||||||
|
isLocked = false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get draggable areas
|
||||||
|
local toolbar = getglobal("Guda_BagFrame_Toolbar")
|
||||||
|
local moneyFrame = getglobal("Guda_BagFrame_MoneyFrame")
|
||||||
|
local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
|
||||||
|
|
||||||
|
if isLocked then
|
||||||
|
-- Disable dragging on main frame
|
||||||
|
if frame.SetScript then
|
||||||
|
frame:SetScript("OnMouseDown", function()
|
||||||
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:ClearFocus()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
frame:SetScript("OnMouseUp", nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Disable dragging on toolbar
|
||||||
|
if toolbar and toolbar.SetScript then
|
||||||
|
toolbar:SetScript("OnMouseDown", function()
|
||||||
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:ClearFocus()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
toolbar:SetScript("OnMouseUp", nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Disable dragging on money frame (preserve tooltip handlers)
|
||||||
|
if moneyFrame and moneyFrame.SetScript then
|
||||||
|
moneyFrame:SetScript("OnMouseDown", function()
|
||||||
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:ClearFocus()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
moneyFrame:SetScript("OnMouseUp", nil)
|
||||||
|
-- Preserve tooltip handlers with safety checks
|
||||||
|
moneyFrame:SetScript("OnEnter", function()
|
||||||
|
if Guda_BagFrame_MoneyOnEnter and addon and addon.Modules and addon.Modules.DB and addon.Modules.Utils then
|
||||||
|
Guda_BagFrame_MoneyOnEnter(this)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
moneyFrame:SetScript("OnLeave", function()
|
||||||
|
if GameTooltip then
|
||||||
|
GameTooltip:Hide()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Disable dragging on item container
|
||||||
|
if itemContainer and itemContainer.SetScript then
|
||||||
|
itemContainer:SetScript("OnMouseDown", function()
|
||||||
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:ClearFocus()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
itemContainer:SetScript("OnMouseUp", nil)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Enable dragging on main frame
|
||||||
|
if frame and frame.SetScript then
|
||||||
|
frame:SetScript("OnMouseDown", function()
|
||||||
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:ClearFocus()
|
||||||
|
end
|
||||||
|
|
||||||
|
local bagFrame = getglobal("Guda_BagFrame")
|
||||||
|
if bagFrame and arg1 == "LeftButton" then
|
||||||
|
bagFrame:StartMoving()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
frame:SetScript("OnMouseUp", function()
|
||||||
|
local bagFrame = getglobal("Guda_BagFrame")
|
||||||
|
if bagFrame then
|
||||||
|
bagFrame:StopMovingOrSizing()
|
||||||
|
SaveBagFramePosition()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Enable dragging on toolbar (title area)
|
||||||
|
if toolbar and toolbar.SetScript then
|
||||||
|
toolbar:SetScript("OnMouseDown", function()
|
||||||
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:ClearFocus()
|
||||||
|
end
|
||||||
|
|
||||||
|
local bagFrame = getglobal("Guda_BagFrame")
|
||||||
|
if bagFrame and arg1 == "LeftButton" then
|
||||||
|
bagFrame:StartMoving()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
toolbar:SetScript("OnMouseUp", function()
|
||||||
|
local bagFrame = getglobal("Guda_BagFrame")
|
||||||
|
if bagFrame then
|
||||||
|
bagFrame:StopMovingOrSizing()
|
||||||
|
SaveBagFramePosition()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Enable dragging on money frame (preserve tooltip handlers)
|
||||||
|
if moneyFrame and moneyFrame.SetScript then
|
||||||
|
moneyFrame:SetScript("OnMouseDown", function()
|
||||||
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:ClearFocus()
|
||||||
|
end
|
||||||
|
|
||||||
|
local bagFrame = getglobal("Guda_BagFrame")
|
||||||
|
if bagFrame and arg1 == "LeftButton" then
|
||||||
|
bagFrame:StartMoving()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
moneyFrame:SetScript("OnMouseUp", function()
|
||||||
|
local bagFrame = getglobal("Guda_BagFrame")
|
||||||
|
if bagFrame then
|
||||||
|
bagFrame:StopMovingOrSizing()
|
||||||
|
SaveBagFramePosition()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
-- Preserve tooltip handlers with safety checks
|
||||||
|
moneyFrame:SetScript("OnEnter", function()
|
||||||
|
if Guda_BagFrame_MoneyOnEnter and addon and addon.Modules and addon.Modules.DB and addon.Modules.Utils then
|
||||||
|
Guda_BagFrame_MoneyOnEnter(this)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
moneyFrame:SetScript("OnLeave", function()
|
||||||
|
if GameTooltip then
|
||||||
|
GameTooltip:Hide()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Enable dragging on item container
|
||||||
|
if itemContainer and itemContainer.SetScript then
|
||||||
|
itemContainer:SetScript("OnMouseDown", function()
|
||||||
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:ClearFocus()
|
||||||
|
end
|
||||||
|
|
||||||
|
local bagFrame = getglobal("Guda_BagFrame")
|
||||||
|
if bagFrame and arg1 == "LeftButton" then
|
||||||
|
bagFrame:StartMoving()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
itemContainer:SetScript("OnMouseUp", function()
|
||||||
|
local bagFrame = getglobal("Guda_BagFrame")
|
||||||
|
if bagFrame then
|
||||||
|
bagFrame:StopMovingOrSizing()
|
||||||
|
SaveBagFramePosition()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize
|
||||||
|
function BagFrame:Initialize()
|
||||||
|
-- Hook default bag functions
|
||||||
|
HookDefaultBags()
|
||||||
|
|
||||||
|
-- Update on bag changes
|
||||||
|
addon.Modules.Events:OnBagUpdate(function()
|
||||||
|
if not currentViewChar then
|
||||||
|
BagFrame:Update()
|
||||||
|
end
|
||||||
|
end, "BagFrame")
|
||||||
|
|
||||||
|
-- Update on money changes
|
||||||
|
addon.Modules.Events:OnMoneyChanged(function()
|
||||||
|
BagFrame:UpdateMoney()
|
||||||
|
end, "BagFrame")
|
||||||
|
|
||||||
|
addon:Debug("Bag frame initialized")
|
||||||
|
end
|
||||||
+313
@@ -0,0 +1,313 @@
|
|||||||
|
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/">
|
||||||
|
|
||||||
|
<!-- Main Bag Frame -->
|
||||||
|
<Frame name="Guda_BagFrame" toplevel="true" movable="true" enableMouse="true" hidden="true" parent="UIParent">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="420" y="600"/>
|
||||||
|
</Size>
|
||||||
|
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT" relativeTo="UIParent">
|
||||||
|
<Offset>
|
||||||
|
<AbsDimension x="-50" y="100"/>
|
||||||
|
</Offset>
|
||||||
|
</Anchor>
|
||||||
|
</Anchors>
|
||||||
|
|
||||||
|
<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
|
||||||
|
<BackgroundInsets>
|
||||||
|
<AbsInset left="11" right="12" top="12" bottom="11"/>
|
||||||
|
</BackgroundInsets>
|
||||||
|
<TileSize>
|
||||||
|
<AbsValue val="16"/>
|
||||||
|
</TileSize>
|
||||||
|
<EdgeSize>
|
||||||
|
<AbsValue val="32"/>
|
||||||
|
</EdgeSize>
|
||||||
|
<Color r="0" g="0" b="0" a="0.9"/>
|
||||||
|
</Backdrop>
|
||||||
|
|
||||||
|
<!-- Keep a (currently unused) top-level layer block for future use -->
|
||||||
|
<Layers>
|
||||||
|
<Layer level="BACKGROUND"/>
|
||||||
|
</Layers>
|
||||||
|
|
||||||
|
<Frames>
|
||||||
|
<!-- Close Button -->
|
||||||
|
<Button name="$parent_CloseButton" inherits="UIPanelCloseButton">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOPRIGHT" x="-5" y="-5"/>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnClick>
|
||||||
|
Guda_BagFrame:Hide()
|
||||||
|
</OnClick>
|
||||||
|
</Scripts>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Toolbar Container (top row) -->
|
||||||
|
<Frame name="$parent_Toolbar" enableMouse="true">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="400" y="30"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" x="0" y="-10"/>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnMouseDown>
|
||||||
|
-- Clear search focus when clicking toolbar
|
||||||
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:ClearFocus()
|
||||||
|
end
|
||||||
|
</OnMouseDown>
|
||||||
|
</Scripts>
|
||||||
|
|
||||||
|
<!-- Title centered in toolbar -->
|
||||||
|
<Layers>
|
||||||
|
<Layer level="ARTWORK">
|
||||||
|
<FontString name="$parent_Title" inherits="GameFontNormalLarge">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="CENTER" x="0" y="0"/>
|
||||||
|
</Anchors>
|
||||||
|
</FontString>
|
||||||
|
</Layer>
|
||||||
|
</Layers>
|
||||||
|
|
||||||
|
<Frames>
|
||||||
|
<!-- Sort Button -->
|
||||||
|
<Button name="$parent_SortButton">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="24" y="24"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="LEFT" x="10" y="0"/>
|
||||||
|
</Anchors>
|
||||||
|
<NormalTexture file="Interface\\Icons\\INV_Misc_Note_01"/>
|
||||||
|
<Scripts>
|
||||||
|
<OnClick>
|
||||||
|
Guda_BagFrame_Sort()
|
||||||
|
</OnClick>
|
||||||
|
<OnEnter>
|
||||||
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
||||||
|
GameTooltip:SetText("Sort Bags")
|
||||||
|
GameTooltip:Show()
|
||||||
|
</OnEnter>
|
||||||
|
<OnLeave>
|
||||||
|
GameTooltip:Hide()
|
||||||
|
</OnLeave>
|
||||||
|
</Scripts>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Characters Button -->
|
||||||
|
<Button name="$parent_CharsButton">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="24" y="24"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parent_SortButton" x="5" y="0"/>
|
||||||
|
</Anchors>
|
||||||
|
<NormalTexture file="Interface\\Icons\\INV_Misc_GroupNeedMore"/>
|
||||||
|
<Scripts>
|
||||||
|
<OnClick>
|
||||||
|
Guda_CharacterSelector:Toggle()
|
||||||
|
</OnClick>
|
||||||
|
<OnEnter>
|
||||||
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
||||||
|
GameTooltip:SetText("View Other Characters")
|
||||||
|
GameTooltip:Show()
|
||||||
|
</OnEnter>
|
||||||
|
<OnLeave>
|
||||||
|
GameTooltip:Hide()
|
||||||
|
</OnLeave>
|
||||||
|
</Scripts>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Bank Button -->
|
||||||
|
<Button name="$parent_BankButton">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="24" y="24"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parent_CharsButton" x="5" y="0"/>
|
||||||
|
</Anchors>
|
||||||
|
<NormalTexture file="Interface\\Icons\\INV_Misc_Bag_09"/>
|
||||||
|
<Scripts>
|
||||||
|
<OnClick>
|
||||||
|
Guda_BankFrame:Toggle()
|
||||||
|
</OnClick>
|
||||||
|
<OnEnter>
|
||||||
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
||||||
|
GameTooltip:SetText("View Bank")
|
||||||
|
GameTooltip:Show()
|
||||||
|
</OnEnter>
|
||||||
|
<OnLeave>
|
||||||
|
GameTooltip:Hide()
|
||||||
|
</OnLeave>
|
||||||
|
</Scripts>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Settings Button -->
|
||||||
|
<Button name="$parent_SettingsButton">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="24" y="24"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parent_BankButton" x="5" y="0"/>
|
||||||
|
</Anchors>
|
||||||
|
<NormalTexture file="Interface\\Icons\\Trade_Engineering"/>
|
||||||
|
<Scripts>
|
||||||
|
<OnClick>
|
||||||
|
Guda_OpenSettings()
|
||||||
|
</OnClick>
|
||||||
|
<OnEnter>
|
||||||
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
||||||
|
GameTooltip:SetText("Settings")
|
||||||
|
GameTooltip:Show()
|
||||||
|
</OnEnter>
|
||||||
|
<OnLeave>
|
||||||
|
GameTooltip:Hide()
|
||||||
|
</OnLeave>
|
||||||
|
</Scripts>
|
||||||
|
</Button>
|
||||||
|
</Frames>
|
||||||
|
</Frame>
|
||||||
|
|
||||||
|
<!-- Search Bar (second row) -->
|
||||||
|
<Frame name="$parent_SearchBar">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="400" y="30"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parent_Toolbar" x="0" y="-5"/>
|
||||||
|
</Anchors>
|
||||||
|
|
||||||
|
<Frames>
|
||||||
|
<!-- Full-width Search Box -->
|
||||||
|
<EditBox name="$parent_SearchBox" autoFocus="false" inherits="InputBoxTemplate">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="0" y="20"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="LEFT" x="10" y="0"/>
|
||||||
|
<Anchor point="RIGHT" x="-10" y="0"/>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnEditFocusGained>
|
||||||
|
if this:GetText() == "Search, try ~equipment" then
|
||||||
|
this:SetText("")
|
||||||
|
this:SetTextColor(1, 1, 1, 1)
|
||||||
|
end
|
||||||
|
-- Show click catcher to detect clicks outside bag
|
||||||
|
local clickCatcher = getglobal("Guda_ClickCatcher")
|
||||||
|
if clickCatcher then clickCatcher:Show() end
|
||||||
|
</OnEditFocusGained>
|
||||||
|
<OnEditFocusLost>
|
||||||
|
-- Hide click catcher when focus is lost
|
||||||
|
local clickCatcher = getglobal("Guda_ClickCatcher")
|
||||||
|
if clickCatcher then clickCatcher:Hide() end
|
||||||
|
|
||||||
|
-- Restore placeholder if empty when focus is lost
|
||||||
|
if this:GetText() == "" then
|
||||||
|
this:SetText("Search, try ~equipment")
|
||||||
|
this:SetTextColor(0.5, 0.5, 0.5, 1)
|
||||||
|
Guda_BagFrame_OnSearchChanged(this)
|
||||||
|
end
|
||||||
|
</OnEditFocusLost>
|
||||||
|
<OnTextChanged>
|
||||||
|
Guda_BagFrame_OnSearchChanged(this)
|
||||||
|
</OnTextChanged>
|
||||||
|
<OnEscapePressed>
|
||||||
|
this:SetText("Search, try ~equipment")
|
||||||
|
this:SetTextColor(0.5, 0.5, 0.5, 1)
|
||||||
|
this:ClearFocus()
|
||||||
|
Guda_BagFrame_OnSearchChanged(this)
|
||||||
|
</OnEscapePressed>
|
||||||
|
</Scripts>
|
||||||
|
</EditBox>
|
||||||
|
</Frames>
|
||||||
|
</Frame>
|
||||||
|
|
||||||
|
<!-- Money Display Frame -->
|
||||||
|
<Frame name="$parent_MoneyFrame" enableMouse="true">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="300" y="30"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="BOTTOM" x="0" y="10"/>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnMouseDown>
|
||||||
|
-- Clear search focus when clicking money area
|
||||||
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:ClearFocus()
|
||||||
|
end
|
||||||
|
</OnMouseDown>
|
||||||
|
<OnEnter>
|
||||||
|
Guda_BagFrame_MoneyOnEnter(this)
|
||||||
|
</OnEnter>
|
||||||
|
<OnLeave>
|
||||||
|
GameTooltip:Hide()
|
||||||
|
</OnLeave>
|
||||||
|
</Scripts>
|
||||||
|
</Frame>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Container for item buttons -->
|
||||||
|
<Frame name="$parent_ItemContainer" enableMouse="true">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="390" y="480"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parent_SearchBar" x="0" y="-5"/>
|
||||||
|
</Anchors>
|
||||||
|
<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background" tile="true">
|
||||||
|
<BackgroundInsets>
|
||||||
|
<AbsInset left="0" right="0" top="0" bottom="0"/>
|
||||||
|
</BackgroundInsets>
|
||||||
|
<TileSize>
|
||||||
|
<AbsValue val="16"/>
|
||||||
|
</TileSize>
|
||||||
|
<Color r="0" g="0" b="0" a="0.5"/>
|
||||||
|
</Backdrop>
|
||||||
|
<Scripts>
|
||||||
|
<OnMouseDown>
|
||||||
|
-- Clear search focus when clicking in item area
|
||||||
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:ClearFocus()
|
||||||
|
end
|
||||||
|
</OnMouseDown>
|
||||||
|
</Scripts>
|
||||||
|
</Frame>
|
||||||
|
</Frames>
|
||||||
|
|
||||||
|
<Scripts>
|
||||||
|
<OnLoad>
|
||||||
|
Guda_BagFrame_OnLoad(this)
|
||||||
|
</OnLoad>
|
||||||
|
<OnShow>
|
||||||
|
Guda_BagFrame_OnShow(this)
|
||||||
|
</OnShow>
|
||||||
|
<OnHide>
|
||||||
|
Guda_BagFrame_OnHide(this)
|
||||||
|
</OnHide>
|
||||||
|
<OnMouseDown>
|
||||||
|
-- Clear search box focus when clicking on bag frame (1.12.1 safe)
|
||||||
|
local searchBox = getglobal("Guda_BagFrame_SearchBar_SearchBox")
|
||||||
|
if searchBox then
|
||||||
|
searchBox:ClearFocus()
|
||||||
|
end
|
||||||
|
|
||||||
|
if (arg1 == "LeftButton") then
|
||||||
|
this:StartMoving()
|
||||||
|
end
|
||||||
|
</OnMouseDown>
|
||||||
|
<OnMouseUp>
|
||||||
|
this:StopMovingOrSizing()
|
||||||
|
</OnMouseUp>
|
||||||
|
</Scripts>
|
||||||
|
</Frame>
|
||||||
|
|
||||||
|
</Ui>
|
||||||
@@ -0,0 +1,238 @@
|
|||||||
|
-- Guda Bank Frame
|
||||||
|
-- Bank viewing UI
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
local BankFrame = {}
|
||||||
|
addon.Modules.BankFrame = BankFrame
|
||||||
|
|
||||||
|
local currentViewChar = nil
|
||||||
|
local searchText = ""
|
||||||
|
|
||||||
|
-- OnLoad
|
||||||
|
function Guda_BankFrame_OnLoad(self)
|
||||||
|
getglobal(self:GetName().."_Title"):SetText("Guda Bank")
|
||||||
|
getglobal(self:GetName().."_SearchBox"):SetText("Search...")
|
||||||
|
addon:Debug("Bank frame loaded")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- OnShow
|
||||||
|
function Guda_BankFrame_OnShow(self)
|
||||||
|
BankFrame:Update()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- OnHide
|
||||||
|
function Guda_BankFrame_OnHide(self)
|
||||||
|
Guda_ReleaseAllButtons()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Toggle visibility
|
||||||
|
function BankFrame:Toggle()
|
||||||
|
if Guda_BankFrame:IsShown() then
|
||||||
|
Guda_BankFrame:Hide()
|
||||||
|
else
|
||||||
|
Guda_BankFrame:Show()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Show specific character's bank
|
||||||
|
function BankFrame:ShowCharacter(fullName)
|
||||||
|
currentViewChar = fullName
|
||||||
|
self:Update()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Show current character's bank
|
||||||
|
function BankFrame:ShowCurrentCharacter()
|
||||||
|
currentViewChar = nil
|
||||||
|
self:Update()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update display
|
||||||
|
function BankFrame:Update()
|
||||||
|
if not Guda_BankFrame:IsShown() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
Guda_ReleaseAllButtons()
|
||||||
|
|
||||||
|
local bankData
|
||||||
|
local isOtherChar = false
|
||||||
|
local charName = ""
|
||||||
|
|
||||||
|
if currentViewChar then
|
||||||
|
bankData = addon.Modules.DB:GetCharacterBank(currentViewChar)
|
||||||
|
isOtherChar = true
|
||||||
|
charName = currentViewChar
|
||||||
|
getglobal("Guda_BankFrame_Title"):SetText("Bank - " .. currentViewChar)
|
||||||
|
else
|
||||||
|
bankData = addon.Modules.DB:GetCharacterBank(addon.Modules.DB:GetPlayerFullName())
|
||||||
|
if not bankData or not next(bankData) then
|
||||||
|
-- No saved bank data, use live scan if bank is open
|
||||||
|
if addon.Modules.BankScanner:IsBankOpen() then
|
||||||
|
bankData = addon.Modules.BankScanner:ScanBank()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
getglobal("Guda_BankFrame_Title"):SetText("Guda Bank")
|
||||||
|
end
|
||||||
|
|
||||||
|
self:DisplayItems(bankData, isOtherChar, charName)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Display items
|
||||||
|
function BankFrame:DisplayItems(bankData, isOtherChar, charName)
|
||||||
|
local x, y = 10, -10
|
||||||
|
local row = 0
|
||||||
|
local col = 0
|
||||||
|
local buttonSize = addon.Modules.DB:GetSetting("iconSize") or addon.Constants.BUTTON_SIZE
|
||||||
|
local spacing = addon.Constants.BUTTON_SPACING
|
||||||
|
local perRow = addon.Modules.DB:GetSetting("bankColumns") or 15
|
||||||
|
local itemContainer = getglobal("Guda_BankFrame_ItemContainer")
|
||||||
|
|
||||||
|
for _, bagID in ipairs(addon.Constants.BANK_BAGS) do
|
||||||
|
local bag = bankData[bagID]
|
||||||
|
|
||||||
|
if bag and bag.slots then
|
||||||
|
for slot, itemData in pairs(bag.slots) do
|
||||||
|
if self:PassesSearchFilter(itemData) then
|
||||||
|
local button = Guda_GetItemButton(itemContainer)
|
||||||
|
|
||||||
|
local xPos = x + (col * (buttonSize + spacing))
|
||||||
|
local yPos = y - (row * (buttonSize + spacing))
|
||||||
|
|
||||||
|
button:ClearAllPoints()
|
||||||
|
button:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", xPos, yPos)
|
||||||
|
|
||||||
|
Guda_ItemButton_SetItem(button, bagID, slot, itemData, true, isOtherChar and charName or nil)
|
||||||
|
|
||||||
|
col = col + 1
|
||||||
|
if col >= perRow then
|
||||||
|
col = 0
|
||||||
|
row = row + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Resize frame dynamically based on content
|
||||||
|
self:ResizeFrame(row, col, perRow)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Resize bank frame based on number of rows and columns
|
||||||
|
function BankFrame:ResizeFrame(currentRow, currentCol, columns)
|
||||||
|
local buttonSize = addon.Modules.DB:GetSetting("iconSize") or addon.Constants.BUTTON_SIZE
|
||||||
|
local spacing = addon.Constants.BUTTON_SPACING
|
||||||
|
|
||||||
|
-- Calculate actual number of rows used
|
||||||
|
local totalRows = currentRow + 1
|
||||||
|
if totalRows < 1 then
|
||||||
|
totalRows = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ensure at least 1 column
|
||||||
|
if not columns or columns < 1 then
|
||||||
|
columns = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Calculate required dimensions
|
||||||
|
local containerWidth = (columns * (buttonSize + spacing)) + 20
|
||||||
|
local containerHeight = (totalRows * (buttonSize + spacing)) + 20
|
||||||
|
local frameWidth = containerWidth + 30
|
||||||
|
local frameHeight = containerHeight + 120
|
||||||
|
|
||||||
|
-- Minimum sizes
|
||||||
|
if containerWidth < 200 then
|
||||||
|
containerWidth = 200
|
||||||
|
frameWidth = 230
|
||||||
|
end
|
||||||
|
if containerHeight < 150 then
|
||||||
|
containerHeight = 150
|
||||||
|
end
|
||||||
|
if frameHeight < 350 then
|
||||||
|
frameHeight = 350
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Maximum sizes
|
||||||
|
if containerWidth > 800 then
|
||||||
|
containerWidth = 800
|
||||||
|
frameWidth = 830
|
||||||
|
end
|
||||||
|
if containerHeight > 600 then
|
||||||
|
containerHeight = 600
|
||||||
|
end
|
||||||
|
if frameHeight > 800 then
|
||||||
|
frameHeight = 800
|
||||||
|
end
|
||||||
|
|
||||||
|
local bankFrame = getglobal("Guda_BankFrame")
|
||||||
|
local itemContainer = getglobal("Guda_BankFrame_ItemContainer")
|
||||||
|
|
||||||
|
if bankFrame then
|
||||||
|
bankFrame:SetWidth(frameWidth)
|
||||||
|
bankFrame:SetHeight(frameHeight)
|
||||||
|
end
|
||||||
|
|
||||||
|
if itemContainer then
|
||||||
|
itemContainer:SetWidth(containerWidth)
|
||||||
|
itemContainer:SetHeight(containerHeight)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if item passes search filter
|
||||||
|
function BankFrame:PassesSearchFilter(itemData)
|
||||||
|
if searchText == "" or searchText == "Search..." then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if not itemData or not itemData.name then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return string.find(string.lower(itemData.name), string.lower(searchText)) ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Search changed handler
|
||||||
|
function Guda_BankFrame_OnSearchChanged(self)
|
||||||
|
local text = self:GetText()
|
||||||
|
if text ~= searchText then
|
||||||
|
searchText = text
|
||||||
|
BankFrame:Update()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sort button handler
|
||||||
|
function Guda_BankFrame_Sort()
|
||||||
|
if currentViewChar then
|
||||||
|
addon:Print("Cannot sort another character's bank!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
addon.Modules.SortEngine:SortBank()
|
||||||
|
|
||||||
|
local frame = CreateFrame("Frame")
|
||||||
|
local elapsed = 0
|
||||||
|
frame:SetScript("OnUpdate", function()
|
||||||
|
elapsed = elapsed + arg1
|
||||||
|
if elapsed >= 0.5 then
|
||||||
|
frame:SetScript("OnUpdate", nil)
|
||||||
|
BankFrame:Update()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize
|
||||||
|
function BankFrame:Initialize()
|
||||||
|
-- Update when bank is opened
|
||||||
|
addon.Modules.Events:OnBankOpen(function()
|
||||||
|
BankFrame:Update()
|
||||||
|
end, "BankFrameUI")
|
||||||
|
|
||||||
|
-- Update on bag changes while bank is open
|
||||||
|
addon.Modules.Events:OnBagUpdate(function()
|
||||||
|
if addon.Modules.BankScanner:IsBankOpen() and not currentViewChar then
|
||||||
|
BankFrame:Update()
|
||||||
|
end
|
||||||
|
end, "BankFrameUI")
|
||||||
|
|
||||||
|
addon:Debug("Bank frame initialized")
|
||||||
|
end
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/">
|
||||||
|
|
||||||
|
<!-- Bank Frame -->
|
||||||
|
<Frame name="Guda_BankFrame" toplevel="true" movable="true" enableMouse="true" hidden="true" parent="UIParent">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="400" y="500"/>
|
||||||
|
</Size>
|
||||||
|
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="LEFT" relativePoint="LEFT" relativeTo="UIParent">
|
||||||
|
<Offset>
|
||||||
|
<AbsDimension x="50" y="0"/>
|
||||||
|
</Offset>
|
||||||
|
</Anchor>
|
||||||
|
</Anchors>
|
||||||
|
|
||||||
|
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
|
||||||
|
<BackgroundInsets>
|
||||||
|
<AbsInset left="11" right="12" top="12" bottom="11"/>
|
||||||
|
</BackgroundInsets>
|
||||||
|
<TileSize>
|
||||||
|
<AbsValue val="32"/>
|
||||||
|
</TileSize>
|
||||||
|
<EdgeSize>
|
||||||
|
<AbsValue val="32"/>
|
||||||
|
</EdgeSize>
|
||||||
|
</Backdrop>
|
||||||
|
|
||||||
|
<Layers>
|
||||||
|
<!-- Title -->
|
||||||
|
<Layer level="ARTWORK">
|
||||||
|
<FontString name="$parent_Title" inherits="GameFontNormalLarge">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" x="0" y="-15"/>
|
||||||
|
</Anchors>
|
||||||
|
</FontString>
|
||||||
|
</Layer>
|
||||||
|
</Layers>
|
||||||
|
|
||||||
|
<Frames>
|
||||||
|
<!-- Close Button -->
|
||||||
|
<Button name="$parent_CloseButton" inherits="UIPanelCloseButton">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOPRIGHT" x="-5" y="-5"/>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnClick>
|
||||||
|
Guda_BankFrame:Hide()
|
||||||
|
</OnClick>
|
||||||
|
</Scripts>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Settings Button -->
|
||||||
|
<Button name="$parent_SettingsButton">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="24" y="24"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOPRIGHT" relativePoint="TOPLEFT" relativeTo="$parent_CloseButton" x="-5" y="0"/>
|
||||||
|
</Anchors>
|
||||||
|
<NormalTexture file="Interface\Icons\Trade_Engineering"/>
|
||||||
|
<Scripts>
|
||||||
|
<OnClick>
|
||||||
|
Guda_OpenSettings()
|
||||||
|
</OnClick>
|
||||||
|
<OnEnter>
|
||||||
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
||||||
|
GameTooltip:SetText("Settings")
|
||||||
|
GameTooltip:Show()
|
||||||
|
</OnEnter>
|
||||||
|
<OnLeave>
|
||||||
|
GameTooltip:Hide()
|
||||||
|
</OnLeave>
|
||||||
|
</Scripts>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Search Box -->
|
||||||
|
<EditBox name="$parent_SearchBox" autoFocus="false" inherits="InputBoxTemplate">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="200" y="20"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" x="0" y="-45"/>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnTextChanged>
|
||||||
|
Guda_BankFrame_OnSearchChanged(this)
|
||||||
|
</OnTextChanged>
|
||||||
|
<OnEscapePressed>
|
||||||
|
this:ClearFocus()
|
||||||
|
</OnEscapePressed>
|
||||||
|
</Scripts>
|
||||||
|
</EditBox>
|
||||||
|
|
||||||
|
<!-- Sort Button -->
|
||||||
|
<Button name="$parent_SortButton" inherits="UIPanelButtonTemplate" text="Sort Bank">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="100" y="22"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="BOTTOM" x="0" y="10"/>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnClick>
|
||||||
|
Guda_BankFrame_Sort()
|
||||||
|
</OnClick>
|
||||||
|
</Scripts>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Container for item buttons -->
|
||||||
|
<Frame name="$parent_ItemContainer">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="370" y="420"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" x="0" y="-75"/>
|
||||||
|
</Anchors>
|
||||||
|
</Frame>
|
||||||
|
</Frames>
|
||||||
|
|
||||||
|
<Scripts>
|
||||||
|
<OnLoad>
|
||||||
|
Guda_BankFrame_OnLoad(this)
|
||||||
|
</OnLoad>
|
||||||
|
<OnShow>
|
||||||
|
Guda_BankFrame_OnShow(this)
|
||||||
|
</OnShow>
|
||||||
|
<OnHide>
|
||||||
|
Guda_BankFrame_OnHide(this)
|
||||||
|
</OnHide>
|
||||||
|
<OnMouseDown>
|
||||||
|
if (arg1 == "LeftButton") then
|
||||||
|
this:StartMoving()
|
||||||
|
end
|
||||||
|
</OnMouseDown>
|
||||||
|
<OnMouseUp>
|
||||||
|
this:StopMovingOrSizing()
|
||||||
|
</OnMouseUp>
|
||||||
|
</Scripts>
|
||||||
|
</Frame>
|
||||||
|
|
||||||
|
</Ui>
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
-- Guda Character Selector
|
||||||
|
-- Select character to view bags/bank
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
local CharacterSelector = {}
|
||||||
|
addon.Modules.CharacterSelector = CharacterSelector
|
||||||
|
|
||||||
|
local charButtons = {}
|
||||||
|
|
||||||
|
-- OnLoad
|
||||||
|
function Guda_CharacterSelector_OnLoad(self)
|
||||||
|
getglobal(self:GetName().."_Title"):SetText("Select Character")
|
||||||
|
addon:Debug("Character selector loaded")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- OnShow
|
||||||
|
function Guda_CharacterSelector_OnShow(self)
|
||||||
|
CharacterSelector:Update()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Toggle visibility
|
||||||
|
function CharacterSelector:Toggle()
|
||||||
|
if Guda_CharacterSelector:IsShown() then
|
||||||
|
Guda_CharacterSelector:Hide()
|
||||||
|
else
|
||||||
|
Guda_CharacterSelector:Show()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update character list
|
||||||
|
function CharacterSelector:Update()
|
||||||
|
-- Clear existing buttons
|
||||||
|
for _, button in ipairs(charButtons) do
|
||||||
|
button:Hide()
|
||||||
|
end
|
||||||
|
charButtons = {}
|
||||||
|
|
||||||
|
-- Get all characters
|
||||||
|
local characters = addon.Modules.DB:GetAllCharacters(true) -- Same faction only
|
||||||
|
local characterList = getglobal("Guda_CharacterSelector_CharacterList")
|
||||||
|
|
||||||
|
-- Create buttons for each character
|
||||||
|
local yOffset = -10
|
||||||
|
for i, char in ipairs(characters) do
|
||||||
|
local button = self:GetCharacterButton(i)
|
||||||
|
|
||||||
|
-- Set text with class color
|
||||||
|
local classColor = addon.Modules.Utils:GetClassColor(char.class)
|
||||||
|
local coloredName = addon.Modules.Utils:ColorText(char.name, classColor.r, classColor.g, classColor.b)
|
||||||
|
|
||||||
|
button:SetText(string.format("%s (Lv %d)", coloredName, char.level))
|
||||||
|
button.charData = char
|
||||||
|
|
||||||
|
-- Position
|
||||||
|
button:ClearAllPoints()
|
||||||
|
button:SetPoint("TOP", characterList, "TOP", 0, yOffset)
|
||||||
|
yOffset = yOffset - 35
|
||||||
|
|
||||||
|
button:Show()
|
||||||
|
table.insert(charButtons, button)
|
||||||
|
end
|
||||||
|
|
||||||
|
if table.getn(characters) == 0 then
|
||||||
|
addon:Debug("No other characters found")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get or create character button
|
||||||
|
function CharacterSelector:GetCharacterButton(index)
|
||||||
|
local name = "Guda_CharButton" .. index
|
||||||
|
local characterList = getglobal("Guda_CharacterSelector_CharacterList")
|
||||||
|
|
||||||
|
local button = getglobal(name)
|
||||||
|
if not button then
|
||||||
|
button = CreateFrame("Button", name, characterList, "Guda_CharacterButtonTemplate")
|
||||||
|
end
|
||||||
|
|
||||||
|
return button
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Character button OnClick
|
||||||
|
function Guda_CharacterButton_OnClick(self)
|
||||||
|
if not self.charData then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
addon:Print("Viewing %s's bags", self.charData.name)
|
||||||
|
|
||||||
|
-- Show bags for this character
|
||||||
|
addon.Modules.BagFrame:ShowCharacter(self.charData.fullName)
|
||||||
|
|
||||||
|
-- Close selector
|
||||||
|
Guda_CharacterSelector:Hide()
|
||||||
|
|
||||||
|
-- Show bag frame if not visible
|
||||||
|
if not Guda_BagFrame:IsShown() then
|
||||||
|
Guda_BagFrame:Show()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Character button OnEnter
|
||||||
|
function Guda_CharacterButton_OnEnter(self)
|
||||||
|
if not self.charData then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||||||
|
GameTooltip:AddLine(self.charData.name, 1, 1, 1)
|
||||||
|
GameTooltip:AddLine("Level " .. self.charData.level .. " " .. self.charData.class, 0.7, 0.7, 0.7)
|
||||||
|
GameTooltip:AddLine("Money: " .. addon.Modules.Utils:FormatMoney(self.charData.money))
|
||||||
|
|
||||||
|
if self.charData.lastUpdate then
|
||||||
|
GameTooltip:AddLine("Last seen: " .. addon.Modules.Utils:FormatTimeAgo(self.charData.lastUpdate), 0.5, 0.5, 0.5)
|
||||||
|
end
|
||||||
|
|
||||||
|
GameTooltip:Show()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Show current character
|
||||||
|
function Guda_CharacterSelector_ShowCurrent()
|
||||||
|
addon.Modules.BagFrame:ShowCurrentCharacter()
|
||||||
|
Guda_CharacterSelector:Hide()
|
||||||
|
|
||||||
|
if not Guda_BagFrame:IsShown() then
|
||||||
|
Guda_BagFrame:Show()
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/">
|
||||||
|
|
||||||
|
<!-- Character Button Template -->
|
||||||
|
<Button name="Guda_CharacterButtonTemplate" virtual="true" inherits="UIPanelButtonTemplate">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="240" y="30"/>
|
||||||
|
</Size>
|
||||||
|
<Scripts>
|
||||||
|
<OnClick>
|
||||||
|
Guda_CharacterButton_OnClick(this)
|
||||||
|
</OnClick>
|
||||||
|
<OnEnter>
|
||||||
|
Guda_CharacterButton_OnEnter(this)
|
||||||
|
</OnEnter>
|
||||||
|
<OnLeave>
|
||||||
|
GameTooltip:Hide()
|
||||||
|
</OnLeave>
|
||||||
|
</Scripts>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Character Selector Frame -->
|
||||||
|
<Frame name="Guda_CharacterSelector" toplevel="true" movable="true" enableMouse="true" hidden="true" parent="UIParent">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="280" y="400"/>
|
||||||
|
</Size>
|
||||||
|
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="CENTER" relativePoint="CENTER" relativeTo="UIParent">
|
||||||
|
<Offset>
|
||||||
|
<AbsDimension x="0" y="0"/>
|
||||||
|
</Offset>
|
||||||
|
</Anchor>
|
||||||
|
</Anchors>
|
||||||
|
|
||||||
|
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
|
||||||
|
<BackgroundInsets>
|
||||||
|
<AbsInset left="11" right="12" top="12" bottom="11"/>
|
||||||
|
</BackgroundInsets>
|
||||||
|
<TileSize>
|
||||||
|
<AbsValue val="32"/>
|
||||||
|
</TileSize>
|
||||||
|
<EdgeSize>
|
||||||
|
<AbsValue val="32"/>
|
||||||
|
</EdgeSize>
|
||||||
|
</Backdrop>
|
||||||
|
|
||||||
|
<Layers>
|
||||||
|
<!-- Title -->
|
||||||
|
<Layer level="ARTWORK">
|
||||||
|
<FontString name="$parent_Title" inherits="GameFontNormalLarge">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" x="0" y="-15"/>
|
||||||
|
</Anchors>
|
||||||
|
</FontString>
|
||||||
|
</Layer>
|
||||||
|
</Layers>
|
||||||
|
|
||||||
|
<Frames>
|
||||||
|
<!-- Close Button -->
|
||||||
|
<Button name="$parent_CloseButton" inherits="UIPanelCloseButton">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOPRIGHT" x="-5" y="-5"/>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnClick>
|
||||||
|
Guda_CharacterSelector:Hide()
|
||||||
|
</OnClick>
|
||||||
|
</Scripts>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Current Character Button -->
|
||||||
|
<Button name="$parent_CurrentCharButton" inherits="UIPanelButtonTemplate" text="Current Character">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="240" y="30"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" x="0" y="-45"/>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnClick>
|
||||||
|
Guda_CharacterSelector_ShowCurrent()
|
||||||
|
</OnClick>
|
||||||
|
</Scripts>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Character List Container -->
|
||||||
|
<Frame name="$parent_CharacterList">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="260" y="310"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" x="0" y="-85"/>
|
||||||
|
</Anchors>
|
||||||
|
</Frame>
|
||||||
|
</Frames>
|
||||||
|
|
||||||
|
<Scripts>
|
||||||
|
<OnLoad>
|
||||||
|
Guda_CharacterSelector_OnLoad(this)
|
||||||
|
</OnLoad>
|
||||||
|
<OnShow>
|
||||||
|
Guda_CharacterSelector_OnShow(this)
|
||||||
|
</OnShow>
|
||||||
|
<OnMouseDown>
|
||||||
|
if (arg1 == "LeftButton") then
|
||||||
|
this:StartMoving()
|
||||||
|
end
|
||||||
|
</OnMouseDown>
|
||||||
|
<OnMouseUp>
|
||||||
|
this:StopMovingOrSizing()
|
||||||
|
</OnMouseUp>
|
||||||
|
</Scripts>
|
||||||
|
</Frame>
|
||||||
|
|
||||||
|
</Ui>
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
-- Guda Item Button
|
||||||
|
-- Handles item button display and interaction
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
-- Item button pool
|
||||||
|
local buttonPool = {}
|
||||||
|
local nextButtonID = 1
|
||||||
|
|
||||||
|
-- Create or get a button from the pool
|
||||||
|
function Guda_GetItemButton(parent)
|
||||||
|
-- Try to reuse existing button
|
||||||
|
for _, button in pairs(buttonPool) do
|
||||||
|
if not button:IsShown() and button:GetParent() == parent then
|
||||||
|
return button
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create new button
|
||||||
|
local button = CreateFrame("Button", "Guda_ItemButton" .. nextButtonID, parent, "Guda_ItemButtonTemplate")
|
||||||
|
buttonPool[nextButtonID] = button
|
||||||
|
nextButtonID = nextButtonID + 1
|
||||||
|
|
||||||
|
return button
|
||||||
|
end
|
||||||
|
|
||||||
|
-- OnLoad handler
|
||||||
|
function Guda_ItemButton_OnLoad(self)
|
||||||
|
self.hasItem = false
|
||||||
|
self.bagID = nil
|
||||||
|
self.slotID = nil
|
||||||
|
self.itemData = nil
|
||||||
|
self.isBank = false
|
||||||
|
self.otherChar = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set item data
|
||||||
|
function Guda_ItemButton_SetItem(self, bagID, slotID, itemData, isBank, otherCharName, matchesFilter)
|
||||||
|
self.bagID = bagID
|
||||||
|
self.slotID = slotID
|
||||||
|
self.itemData = itemData
|
||||||
|
self.isBank = isBank or false
|
||||||
|
self.otherChar = otherCharName
|
||||||
|
|
||||||
|
-- Default to true if not specified (for non-filtered displays)
|
||||||
|
if matchesFilter == nil then
|
||||||
|
matchesFilter = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local countText = getglobal(self:GetName().."_Count")
|
||||||
|
local qualityBorder = getglobal(self:GetName().."_QualityBorder")
|
||||||
|
local emptySlotBg = getglobal(self:GetName().."_EmptySlotBg")
|
||||||
|
|
||||||
|
-- Apply icon size setting
|
||||||
|
local iconSize = Guda.Modules.DB:GetSetting("iconSize") or addon.Constants.BUTTON_SIZE
|
||||||
|
self:SetWidth(iconSize)
|
||||||
|
self:SetHeight(iconSize)
|
||||||
|
|
||||||
|
-- Resize empty slot background to match icon size (slightly larger to ensure coverage)
|
||||||
|
if emptySlotBg then
|
||||||
|
emptySlotBg:ClearAllPoints()
|
||||||
|
emptySlotBg:SetPoint("TOPLEFT", self, "TOPLEFT", -2, 2)
|
||||||
|
emptySlotBg:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 2, -2)
|
||||||
|
-- Crop texture edges slightly to remove any built-in padding
|
||||||
|
emptySlotBg:SetTexCoord(0.1, 0.9, 0.1, 0.9)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Also resize the underlying slot textures so the border/background scale with the button.
|
||||||
|
-- On 1.12/Turtle, ItemButtonTemplate uses fixed-size textures, so we explicitly size them
|
||||||
|
-- to match the current iconSize instead of letting them use their default dimensions.
|
||||||
|
|
||||||
|
-- For 1.12.1 compatibility, access textures using both methods and proper naming
|
||||||
|
-- We'll set the NormalTexture later based on whether slot is empty or filled
|
||||||
|
|
||||||
|
-- Pushed texture follows the button size/position
|
||||||
|
local pushedTexture = getglobal(self:GetName().."PushedTexture")
|
||||||
|
if not pushedTexture and self.GetPushedTexture then
|
||||||
|
pushedTexture = self:GetPushedTexture()
|
||||||
|
end
|
||||||
|
if pushedTexture then
|
||||||
|
pushedTexture:ClearAllPoints()
|
||||||
|
pushedTexture:SetPoint("CENTER", self, "CENTER", 0, 0)
|
||||||
|
pushedTexture:SetWidth(iconSize)
|
||||||
|
pushedTexture:SetHeight(iconSize)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Highlight texture for mouseover (not used for search)
|
||||||
|
local highlightTexture = getglobal(self:GetName().."HighlightTexture")
|
||||||
|
if not highlightTexture and self.GetHighlightTexture then
|
||||||
|
highlightTexture = self:GetHighlightTexture()
|
||||||
|
end
|
||||||
|
if highlightTexture then
|
||||||
|
highlightTexture:ClearAllPoints()
|
||||||
|
highlightTexture:SetPoint("CENTER", self, "CENTER", 0, 0)
|
||||||
|
highlightTexture:SetWidth(iconSize)
|
||||||
|
highlightTexture:SetHeight(iconSize)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Checked texture (centered square pattern when slot is "active")
|
||||||
|
local checkedTexture = getglobal(self:GetName().."CheckedTexture")
|
||||||
|
if not checkedTexture and self.GetCheckedTexture then
|
||||||
|
checkedTexture = self:GetCheckedTexture()
|
||||||
|
end
|
||||||
|
if checkedTexture then
|
||||||
|
checkedTexture:ClearAllPoints()
|
||||||
|
checkedTexture:SetPoint("CENTER", self, "CENTER", 0, 0)
|
||||||
|
checkedTexture:SetWidth(iconSize)
|
||||||
|
checkedTexture:SetHeight(iconSize)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Apply icon font size setting to stack count text
|
||||||
|
if countText and countText.GetFont then
|
||||||
|
local font, _, flags = countText:GetFont()
|
||||||
|
local fontSize = Guda.Modules.DB:GetSetting("iconFontSize") or 12
|
||||||
|
countText:SetFont(font, fontSize, flags)
|
||||||
|
end
|
||||||
|
|
||||||
|
if itemData then
|
||||||
|
self.hasItem = true
|
||||||
|
|
||||||
|
-- Set icon
|
||||||
|
SetItemButtonTexture(self, itemData.texture)
|
||||||
|
|
||||||
|
-- Hide NormalTexture for filled slots (pfUI style)
|
||||||
|
self:SetNormalTexture("")
|
||||||
|
local normalBorder = getglobal(self:GetName().."NormalTexture")
|
||||||
|
if normalBorder then
|
||||||
|
normalBorder:SetTexture("")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Hide empty slot background for filled slots
|
||||||
|
if emptySlotBg then
|
||||||
|
emptySlotBg:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Search filtering (pfUI style - ONLY use alpha, no other effects)
|
||||||
|
if matchesFilter then
|
||||||
|
-- Matching items: full opacity (1.0)
|
||||||
|
self:SetAlpha(1.0)
|
||||||
|
else
|
||||||
|
-- Non-matching items: 25% opacity (0.25) - very dim
|
||||||
|
self:SetAlpha(0.25)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set count
|
||||||
|
if itemData.count and itemData.count > 1 then
|
||||||
|
countText:SetText(itemData.count)
|
||||||
|
countText:Show()
|
||||||
|
else
|
||||||
|
countText:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set quality border
|
||||||
|
if itemData.quality and itemData.quality > 1 then
|
||||||
|
local r, g, b = addon.Modules.Utils:GetQualityColor(itemData.quality)
|
||||||
|
qualityBorder:SetVertexColor(r, g, b, 1)
|
||||||
|
qualityBorder:Show()
|
||||||
|
else
|
||||||
|
qualityBorder:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
self:Show()
|
||||||
|
else
|
||||||
|
self.hasItem = false
|
||||||
|
-- For empty slots, clear the icon texture
|
||||||
|
SetItemButtonTexture(self, nil)
|
||||||
|
|
||||||
|
-- Hide NormalTexture for empty slots (we use EmptySlotBg instead)
|
||||||
|
self:SetNormalTexture("")
|
||||||
|
local normalBorder = getglobal(self:GetName().."NormalTexture")
|
||||||
|
if normalBorder then
|
||||||
|
normalBorder:SetTexture("")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Show classic bag pattern background for empty slots
|
||||||
|
if emptySlotBg then
|
||||||
|
emptySlotBg:Show()
|
||||||
|
emptySlotBg:SetAlpha(0.5) -- Slightly more visible
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Dim empty slots when searching (pfUI style)
|
||||||
|
if matchesFilter then
|
||||||
|
-- No search active or passes filter: normal opacity
|
||||||
|
self:SetAlpha(1.0)
|
||||||
|
else
|
||||||
|
-- Search active and doesn't match: very dim (25% like pfUI)
|
||||||
|
self:SetAlpha(0.25)
|
||||||
|
end
|
||||||
|
|
||||||
|
countText:Hide()
|
||||||
|
qualityBorder:Hide()
|
||||||
|
self:Show()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Setup icon texture using pfUI's approach (anchor to fill button)
|
||||||
|
-- In 1.12.1, ItemButtonTemplate creates an icon named "$parentIconTexture"
|
||||||
|
local iconTexture = getglobal(self:GetName().."IconTexture")
|
||||||
|
if not iconTexture then
|
||||||
|
-- Fallback for other naming conventions
|
||||||
|
iconTexture = getglobal(self:GetName().."Icon") or self.icon or self.Icon
|
||||||
|
end
|
||||||
|
|
||||||
|
if iconTexture then
|
||||||
|
if self.hasItem then
|
||||||
|
-- pfUI style: anchor to fill the button with small insets
|
||||||
|
iconTexture:ClearAllPoints()
|
||||||
|
iconTexture:SetPoint("TOPLEFT", self, "TOPLEFT", 1, -1)
|
||||||
|
iconTexture:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -1, 1)
|
||||||
|
-- Crop icon edges slightly (pfUI uses .08 to .92)
|
||||||
|
iconTexture:SetTexCoord(0.08, 0.92, 0.08, 0.92)
|
||||||
|
iconTexture:Show()
|
||||||
|
else
|
||||||
|
-- Hide icon for empty slots
|
||||||
|
iconTexture:Hide()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- OnEnter handler (show tooltip)
|
||||||
|
function Guda_ItemButton_OnEnter(self)
|
||||||
|
if not self.hasItem or not self.itemData then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||||||
|
|
||||||
|
if self.otherChar then
|
||||||
|
-- Viewing another character's item
|
||||||
|
if self.itemData.link then
|
||||||
|
GameTooltip:SetHyperlink(self.itemData.link)
|
||||||
|
GameTooltip:AddLine(" ")
|
||||||
|
GameTooltip:AddLine("|cFFFFFFFFOwned by: |cFF00FF96" .. self.otherChar .. "|r", 1, 1, 1)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Current character's item
|
||||||
|
if self.isBank then
|
||||||
|
GameTooltip:SetInventoryItem("player", BankButtonIDToInvSlotID(self.slotID, self.bagID))
|
||||||
|
else
|
||||||
|
GameTooltip:SetBagItem(self.bagID, self.slotID)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
GameTooltip:Show()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- OnLeave handler
|
||||||
|
function Guda_ItemButton_OnLeave(self)
|
||||||
|
GameTooltip:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- OnDragStart handler
|
||||||
|
function Guda_ItemButton_OnDragStart(self, button)
|
||||||
|
-- Don't allow dragging other characters' items
|
||||||
|
if self.otherChar then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Only allow left button drag
|
||||||
|
if button == "LeftButton" and self.hasItem then
|
||||||
|
PickupContainerItem(self.bagID, self.slotID)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- OnReceiveDrag handler
|
||||||
|
function Guda_ItemButton_OnReceiveDrag(self)
|
||||||
|
-- Don't allow dragging to other characters' items
|
||||||
|
if self.otherChar then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Place the item being dragged
|
||||||
|
PickupContainerItem(self.bagID, self.slotID)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- OnClick handler
|
||||||
|
function Guda_ItemButton_OnClick(self, button)
|
||||||
|
-- Don't allow interaction with other characters' items
|
||||||
|
if self.otherChar then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Handle modified clicks first
|
||||||
|
if IsShiftKeyDown() then
|
||||||
|
-- Shift+Click: Link in chat
|
||||||
|
if self.hasItem and self.itemData and self.itemData.link then
|
||||||
|
if ChatFrameEditBox:IsVisible() then
|
||||||
|
ChatFrameEditBox:Insert(self.itemData.link)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return
|
||||||
|
elseif IsControlKeyDown() then
|
||||||
|
-- Ctrl+Click: Dress up (if applicable)
|
||||||
|
if self.hasItem and self.itemData and self.itemData.link then
|
||||||
|
DressUpItemLink(self.itemData.link)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Normal clicks - handle item pickup/placement
|
||||||
|
if button == "LeftButton" then
|
||||||
|
-- Pick up or place item
|
||||||
|
PickupContainerItem(self.bagID, self.slotID)
|
||||||
|
elseif button == "RightButton" then
|
||||||
|
-- Right click: Use item (only if slot has an item)
|
||||||
|
if self.hasItem then
|
||||||
|
UseContainerItem(self.bagID, self.slotID)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Release all buttons
|
||||||
|
function Guda_ReleaseAllButtons()
|
||||||
|
for _, button in pairs(buttonPool) do
|
||||||
|
button:Hide()
|
||||||
|
button:ClearAllPoints()
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/">
|
||||||
|
|
||||||
|
<!-- Item Button Template -->
|
||||||
|
<Button name="Guda_ItemButtonTemplate" virtual="true" inherits="ItemButtonTemplate">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="37" y="37"/>
|
||||||
|
</Size>
|
||||||
|
|
||||||
|
<Layers>
|
||||||
|
<!-- Empty slot background texture (classic bag pattern) -->
|
||||||
|
<Layer level="BACKGROUND">
|
||||||
|
<Texture name="$parent_EmptySlotBg" file="Interface\Buttons\UI-EmptySlot" hidden="false">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOPLEFT"/>
|
||||||
|
<Anchor point="BOTTOMRIGHT"/>
|
||||||
|
</Anchors>
|
||||||
|
</Texture>
|
||||||
|
</Layer>
|
||||||
|
|
||||||
|
<!-- Quality border -->
|
||||||
|
<Layer level="OVERLAY">
|
||||||
|
<Texture name="$parent_QualityBorder" hidden="true">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOPLEFT" x="-1" y="1"/>
|
||||||
|
<Anchor point="BOTTOMRIGHT" x="1" y="-1"/>
|
||||||
|
</Anchors>
|
||||||
|
</Texture>
|
||||||
|
</Layer>
|
||||||
|
|
||||||
|
<!-- Item count -->
|
||||||
|
<Layer level="OVERLAY">
|
||||||
|
<FontString name="$parent_Count" inherits="NumberFontNormal" justifyH="RIGHT">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="BOTTOMRIGHT" x="-2" y="2"/>
|
||||||
|
</Anchors>
|
||||||
|
</FontString>
|
||||||
|
</Layer>
|
||||||
|
</Layers>
|
||||||
|
|
||||||
|
<Scripts>
|
||||||
|
<OnLoad>
|
||||||
|
Guda_ItemButton_OnLoad(this)
|
||||||
|
this:RegisterForDrag("LeftButton")
|
||||||
|
this:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||||||
|
</OnLoad>
|
||||||
|
<OnEnter>
|
||||||
|
Guda_ItemButton_OnEnter(this)
|
||||||
|
</OnEnter>
|
||||||
|
<OnLeave>
|
||||||
|
Guda_ItemButton_OnLeave(this)
|
||||||
|
</OnLeave>
|
||||||
|
<OnClick>
|
||||||
|
Guda_ItemButton_OnClick(this, arg1)
|
||||||
|
</OnClick>
|
||||||
|
<OnDragStart>
|
||||||
|
Guda_ItemButton_OnDragStart(this, arg1)
|
||||||
|
</OnDragStart>
|
||||||
|
<OnReceiveDrag>
|
||||||
|
Guda_ItemButton_OnReceiveDrag(this)
|
||||||
|
</OnReceiveDrag>
|
||||||
|
</Scripts>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</Ui>
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
-- Guda Money Display
|
||||||
|
-- Handles money display in UI
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
local MoneyDisplay = {}
|
||||||
|
addon.Modules.MoneyDisplay = MoneyDisplay
|
||||||
|
|
||||||
|
-- Create a money display frame
|
||||||
|
function MoneyDisplay:CreateDisplay(parent, x, y)
|
||||||
|
local frame = CreateFrame("Frame", nil, parent)
|
||||||
|
frame:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
|
||||||
|
frame:SetWidth(200)
|
||||||
|
frame:SetHeight(20)
|
||||||
|
|
||||||
|
-- Gold text
|
||||||
|
frame.gold = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
|
||||||
|
frame.gold:SetPoint("LEFT", frame, "LEFT", 0, 0)
|
||||||
|
|
||||||
|
-- Silver text
|
||||||
|
frame.silver = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
|
||||||
|
frame.silver:SetPoint("LEFT", frame.gold, "RIGHT", 2, 0)
|
||||||
|
|
||||||
|
-- Copper text
|
||||||
|
frame.copper = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
|
||||||
|
frame.copper:SetPoint("LEFT", frame.silver, "RIGHT", 2, 0)
|
||||||
|
|
||||||
|
return frame
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update money display
|
||||||
|
function MoneyDisplay:Update(frame, copper)
|
||||||
|
if not frame or not copper then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local gold = math.floor(copper / 10000)
|
||||||
|
local silver = math.floor(mod(copper, 10000) / 100)
|
||||||
|
local bronze = mod(copper, 100)
|
||||||
|
|
||||||
|
if gold > 0 then
|
||||||
|
frame.gold:SetText(gold .. "|cFFFFD700g|r")
|
||||||
|
frame.gold:Show()
|
||||||
|
else
|
||||||
|
frame.gold:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
if silver > 0 or gold > 0 then
|
||||||
|
frame.silver:SetText(silver .. "|cFFC0C0C0s|r")
|
||||||
|
frame.silver:Show()
|
||||||
|
else
|
||||||
|
frame.silver:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
frame.copper:SetText(bronze .. "|cFFFF6600c|r")
|
||||||
|
frame.copper:Show()
|
||||||
|
end
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
-- Guda Settings Popup
|
||||||
|
-- UI for adjusting addon settings
|
||||||
|
|
||||||
|
local addon = Guda
|
||||||
|
|
||||||
|
local SettingsPopup = {}
|
||||||
|
addon.Modules.SettingsPopup = SettingsPopup
|
||||||
|
|
||||||
|
-- Global function to open settings (called from XML)
|
||||||
|
function Guda_OpenSettings()
|
||||||
|
local frame = getglobal("Guda_SettingsPopup")
|
||||||
|
if frame then
|
||||||
|
frame:Show()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- OnLoad
|
||||||
|
function Guda_SettingsPopup_OnLoad(self)
|
||||||
|
local title = getglobal(self:GetName().."_Title")
|
||||||
|
title:SetText("Guda Settings")
|
||||||
|
-- Increase title font size
|
||||||
|
local titleFont, _, titleFlags = title:GetFont()
|
||||||
|
if titleFont then
|
||||||
|
title:SetFont(titleFont, 16, titleFlags)
|
||||||
|
end
|
||||||
|
Guda:Debug("Settings popup loaded")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- OnShow
|
||||||
|
function Guda_SettingsPopup_OnShow(self)
|
||||||
|
-- Load current settings
|
||||||
|
local bagColumns = Guda.Modules.DB:GetSetting("bagColumns") or 10
|
||||||
|
local bankColumns = Guda.Modules.DB:GetSetting("bankColumns") or 15
|
||||||
|
local iconSize = Guda.Modules.DB:GetSetting("iconSize") or addon.Constants.BUTTON_SIZE
|
||||||
|
local iconFontSize = Guda.Modules.DB:GetSetting("iconFontSize") or 12
|
||||||
|
local lockBags = Guda.Modules.DB:GetSetting("lockBags")
|
||||||
|
if lockBags == nil then
|
||||||
|
lockBags = false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update sliders
|
||||||
|
local bagSlider = getglobal("Guda_SettingsPopup_BagColumnsSlider")
|
||||||
|
local bankSlider = getglobal("Guda_SettingsPopup_BankColumnsSlider")
|
||||||
|
local iconSizeSlider = getglobal("Guda_SettingsPopup_IconSizeSlider")
|
||||||
|
local iconFontSizeSlider = getglobal("Guda_SettingsPopup_IconFontSizeSlider")
|
||||||
|
local lockCheckbox = getglobal("Guda_SettingsPopup_LockBagsCheckbox")
|
||||||
|
|
||||||
|
if bagSlider then
|
||||||
|
bagSlider:SetValue(bagColumns)
|
||||||
|
end
|
||||||
|
|
||||||
|
if bankSlider then
|
||||||
|
bankSlider:SetValue(bankColumns)
|
||||||
|
end
|
||||||
|
|
||||||
|
if iconSizeSlider then
|
||||||
|
iconSizeSlider:SetValue(iconSize)
|
||||||
|
end
|
||||||
|
|
||||||
|
if iconFontSizeSlider then
|
||||||
|
iconFontSizeSlider:SetValue(iconFontSize)
|
||||||
|
end
|
||||||
|
|
||||||
|
if lockCheckbox then
|
||||||
|
lockCheckbox:SetChecked(lockBags and 1 or 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Toggle visibility
|
||||||
|
function SettingsPopup:Toggle()
|
||||||
|
local frame = getglobal("Guda_SettingsPopup")
|
||||||
|
if frame then
|
||||||
|
if frame:IsShown() then
|
||||||
|
frame:Hide()
|
||||||
|
else
|
||||||
|
frame:Show()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Bag Columns Slider OnLoad
|
||||||
|
function Guda_SettingsPopup_BagColumnsSlider_OnLoad(self)
|
||||||
|
getglobal(self:GetName().."Low"):SetText("5")
|
||||||
|
getglobal(self:GetName().."High"):SetText("20")
|
||||||
|
|
||||||
|
local text = getglobal(self:GetName().."Text")
|
||||||
|
text:SetText("Bag columns")
|
||||||
|
|
||||||
|
-- Increase font size
|
||||||
|
local font, _, flags = text:GetFont()
|
||||||
|
if font then
|
||||||
|
text:SetFont(font, 12, flags)
|
||||||
|
end
|
||||||
|
|
||||||
|
self:SetMinMaxValues(5, 20)
|
||||||
|
self:SetValueStep(1)
|
||||||
|
|
||||||
|
local currentValue = Guda.Modules.DB:GetSetting("bagColumns") or 10
|
||||||
|
self:SetValue(currentValue)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Bag Columns Slider OnValueChanged
|
||||||
|
function Guda_SettingsPopup_BagColumnsSlider_OnValueChanged(self)
|
||||||
|
local value = self:GetValue()
|
||||||
|
|
||||||
|
-- Update display text
|
||||||
|
getglobal(self:GetName().."Text"):SetText("Bag columns: " .. value)
|
||||||
|
|
||||||
|
-- Save setting
|
||||||
|
Guda.Modules.DB:SetSetting("bagColumns", value)
|
||||||
|
|
||||||
|
-- Refresh bag frame if it's open
|
||||||
|
local bagFrame = getglobal("Guda_BagFrame")
|
||||||
|
if bagFrame and bagFrame:IsShown() then
|
||||||
|
Guda.Modules.BagFrame:Update()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Bank Columns Slider OnLoad
|
||||||
|
function Guda_SettingsPopup_BankColumnsSlider_OnLoad(self)
|
||||||
|
getglobal(self:GetName().."Low"):SetText("5")
|
||||||
|
getglobal(self:GetName().."High"):SetText("20")
|
||||||
|
|
||||||
|
local text = getglobal(self:GetName().."Text")
|
||||||
|
text:SetText("Bank columns")
|
||||||
|
|
||||||
|
-- Increase font size
|
||||||
|
local font, _, flags = text:GetFont()
|
||||||
|
if font then
|
||||||
|
text:SetFont(font, 12, flags)
|
||||||
|
end
|
||||||
|
|
||||||
|
self:SetMinMaxValues(5, 20)
|
||||||
|
self:SetValueStep(1)
|
||||||
|
|
||||||
|
local currentValue = Guda.Modules.DB:GetSetting("bankColumns") or 15
|
||||||
|
self:SetValue(currentValue)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Bank Columns Slider OnValueChanged
|
||||||
|
function Guda_SettingsPopup_BankColumnsSlider_OnValueChanged(self)
|
||||||
|
local value = self:GetValue()
|
||||||
|
|
||||||
|
-- Update display text
|
||||||
|
getglobal(self:GetName().."Text"):SetText("Bank columns: " .. value)
|
||||||
|
|
||||||
|
-- Save setting
|
||||||
|
Guda.Modules.DB:SetSetting("bankColumns", value)
|
||||||
|
|
||||||
|
-- Refresh bank frame if it's open
|
||||||
|
local bankFrame = getglobal("Guda_BankFrame")
|
||||||
|
if bankFrame and bankFrame:IsShown() then
|
||||||
|
Guda.Modules.BankFrame:Update()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Icon Size Slider OnLoad
|
||||||
|
function Guda_SettingsPopup_IconSizeSlider_OnLoad(self)
|
||||||
|
getglobal(self:GetName().."Low"):SetText("24px")
|
||||||
|
getglobal(self:GetName().."High"):SetText("64px")
|
||||||
|
|
||||||
|
local text = getglobal(self:GetName().."Text")
|
||||||
|
text:SetText("Icon size")
|
||||||
|
|
||||||
|
-- Increase font size
|
||||||
|
local font, _, flags = text:GetFont()
|
||||||
|
if font then
|
||||||
|
text:SetFont(font, 12, flags)
|
||||||
|
end
|
||||||
|
|
||||||
|
self:SetMinMaxValues(24, 64)
|
||||||
|
self:SetValueStep(1)
|
||||||
|
|
||||||
|
local currentValue = Guda.Modules.DB:GetSetting("iconSize") or addon.Constants.BUTTON_SIZE
|
||||||
|
self:SetValue(currentValue)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Icon Size Slider OnValueChanged
|
||||||
|
function Guda_SettingsPopup_IconSizeSlider_OnValueChanged(self)
|
||||||
|
local value = math.floor(self:GetValue() + 0.5)
|
||||||
|
|
||||||
|
getglobal(self:GetName().."Text"):SetText("Icon size: " .. value .. "px")
|
||||||
|
|
||||||
|
Guda.Modules.DB:SetSetting("iconSize", value)
|
||||||
|
|
||||||
|
local bagFrame = getglobal("Guda_BagFrame")
|
||||||
|
if bagFrame and bagFrame:IsShown() then
|
||||||
|
Guda.Modules.BagFrame:Update()
|
||||||
|
end
|
||||||
|
|
||||||
|
local bankFrame = getglobal("Guda_BankFrame")
|
||||||
|
if bankFrame and bankFrame:IsShown() then
|
||||||
|
Guda.Modules.BankFrame:Update()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Icon Font Size Slider OnLoad
|
||||||
|
function Guda_SettingsPopup_IconFontSizeSlider_OnLoad(self)
|
||||||
|
getglobal(self:GetName().."Low"):SetText("8px")
|
||||||
|
getglobal(self:GetName().."High"):SetText("20px")
|
||||||
|
|
||||||
|
local text = getglobal(self:GetName().."Text")
|
||||||
|
text:SetText("Icon font size")
|
||||||
|
|
||||||
|
-- Increase font size
|
||||||
|
local font, _, flags = text:GetFont()
|
||||||
|
if font then
|
||||||
|
text:SetFont(font, 12, flags)
|
||||||
|
end
|
||||||
|
|
||||||
|
self:SetMinMaxValues(8, 20)
|
||||||
|
self:SetValueStep(1)
|
||||||
|
|
||||||
|
local currentValue = Guda.Modules.DB:GetSetting("iconFontSize") or 12
|
||||||
|
self:SetValue(currentValue)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Icon Font Size Slider OnValueChanged
|
||||||
|
function Guda_SettingsPopup_IconFontSizeSlider_OnValueChanged(self)
|
||||||
|
local value = math.floor(self:GetValue() + 0.5)
|
||||||
|
|
||||||
|
getglobal(self:GetName().."Text"):SetText("Icon font size: " .. value .. "px")
|
||||||
|
|
||||||
|
Guda.Modules.DB:SetSetting("iconFontSize", value)
|
||||||
|
|
||||||
|
local bagFrame = getglobal("Guda_BagFrame")
|
||||||
|
if bagFrame and bagFrame:IsShown() then
|
||||||
|
Guda.Modules.BagFrame:Update()
|
||||||
|
end
|
||||||
|
|
||||||
|
local bankFrame = getglobal("Guda_BankFrame")
|
||||||
|
if bankFrame and bankFrame:IsShown() then
|
||||||
|
Guda.Modules.BankFrame:Update()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Lock Bags Checkbox OnLoad
|
||||||
|
function Guda_SettingsPopup_LockBagsCheckbox_OnLoad(self)
|
||||||
|
local text = getglobal(self:GetName().."Text")
|
||||||
|
if text then
|
||||||
|
text:SetText("Lock Bags")
|
||||||
|
|
||||||
|
-- Increase font size
|
||||||
|
local font, _, flags = text:GetFont()
|
||||||
|
if font then
|
||||||
|
text:SetFont(font, 13, flags)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local isLocked = false
|
||||||
|
if Guda and Guda.Modules and Guda.Modules.DB then
|
||||||
|
isLocked = Guda.Modules.DB:GetSetting("lockBags")
|
||||||
|
if isLocked == nil then
|
||||||
|
isLocked = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:SetChecked(isLocked and 1 or 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Lock Bags Checkbox OnClick
|
||||||
|
function Guda_SettingsPopup_LockBagsCheckbox_OnClick(self)
|
||||||
|
local isChecked = self:GetChecked() == 1
|
||||||
|
|
||||||
|
-- Save setting
|
||||||
|
if Guda and Guda.Modules and Guda.Modules.DB then
|
||||||
|
Guda.Modules.DB:SetSetting("lockBags", isChecked)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update bag frame draggability
|
||||||
|
if Guda and Guda.Modules and Guda.Modules.BagFrame and Guda.Modules.BagFrame.UpdateLockState then
|
||||||
|
Guda.Modules.BagFrame:UpdateLockState()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize
|
||||||
|
function SettingsPopup:Initialize()
|
||||||
|
Guda:Debug("Settings popup initialized")
|
||||||
|
end
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/">
|
||||||
|
|
||||||
|
<!-- Settings Popup Frame -->
|
||||||
|
<Frame name="Guda_SettingsPopup" toplevel="true" movable="true" enableMouse="true" hidden="true" parent="UIParent" frameStrata="DIALOG">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="320" y="380"/>
|
||||||
|
</Size>
|
||||||
|
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="CENTER" relativePoint="CENTER" relativeTo="UIParent">
|
||||||
|
<Offset>
|
||||||
|
<AbsDimension x="0" y="0"/>
|
||||||
|
</Offset>
|
||||||
|
</Anchor>
|
||||||
|
</Anchors>
|
||||||
|
|
||||||
|
<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
|
||||||
|
<BackgroundInsets>
|
||||||
|
<AbsInset left="11" right="12" top="12" bottom="11"/>
|
||||||
|
</BackgroundInsets>
|
||||||
|
<TileSize>
|
||||||
|
<AbsValue val="16"/>
|
||||||
|
</TileSize>
|
||||||
|
<EdgeSize>
|
||||||
|
<AbsValue val="32"/>
|
||||||
|
</EdgeSize>
|
||||||
|
<Color r="0" g="0" b="0" a="0.9"/>
|
||||||
|
</Backdrop>
|
||||||
|
|
||||||
|
<Layers>
|
||||||
|
<!-- Title -->
|
||||||
|
<Layer level="ARTWORK">
|
||||||
|
<FontString name="$parent_Title" inherits="GameFontNormalLarge">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" x="0" y="-25"/>
|
||||||
|
</Anchors>
|
||||||
|
<Color r="1" g="0.82" b="0"/>
|
||||||
|
</FontString>
|
||||||
|
</Layer>
|
||||||
|
</Layers>
|
||||||
|
|
||||||
|
<Frames>
|
||||||
|
<!-- Close Button -->
|
||||||
|
<Button name="$parent_CloseButton" inherits="UIPanelCloseButton">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOPRIGHT" x="-5" y="-50"/>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnClick>
|
||||||
|
Guda_SettingsPopup:Hide()
|
||||||
|
</OnClick>
|
||||||
|
</Scripts>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Bag Columns Slider -->
|
||||||
|
<Slider name="$parent_BagColumnsSlider" inherits="OptionsSliderTemplate">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="270" y="17"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP">
|
||||||
|
<Offset>
|
||||||
|
<AbsDimension x="0" y="-90"/>
|
||||||
|
</Offset>
|
||||||
|
</Anchor>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnLoad>
|
||||||
|
Guda_SettingsPopup_BagColumnsSlider_OnLoad(this)
|
||||||
|
</OnLoad>
|
||||||
|
<OnValueChanged>
|
||||||
|
Guda_SettingsPopup_BagColumnsSlider_OnValueChanged(this)
|
||||||
|
</OnValueChanged>
|
||||||
|
</Scripts>
|
||||||
|
</Slider>
|
||||||
|
|
||||||
|
<!-- Bank Columns Slider -->
|
||||||
|
<Slider name="$parent_BankColumnsSlider" inherits="OptionsSliderTemplate">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="270" y="17"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parent_BagColumnsSlider">
|
||||||
|
<Offset>
|
||||||
|
<AbsDimension x="0" y="-40"/>
|
||||||
|
</Offset>
|
||||||
|
</Anchor>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnLoad>
|
||||||
|
Guda_SettingsPopup_BankColumnsSlider_OnLoad(this)
|
||||||
|
</OnLoad>
|
||||||
|
<OnValueChanged>
|
||||||
|
Guda_SettingsPopup_BankColumnsSlider_OnValueChanged(this)
|
||||||
|
</OnValueChanged>
|
||||||
|
</Scripts>
|
||||||
|
</Slider>
|
||||||
|
|
||||||
|
<!-- Icon Size Slider -->
|
||||||
|
<Slider name="$parent_IconSizeSlider" inherits="OptionsSliderTemplate">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="270" y="17"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parent_BankColumnsSlider">
|
||||||
|
<Offset>
|
||||||
|
<AbsDimension x="0" y="-40"/>
|
||||||
|
</Offset>
|
||||||
|
</Anchor>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnLoad>
|
||||||
|
Guda_SettingsPopup_IconSizeSlider_OnLoad(this)
|
||||||
|
</OnLoad>
|
||||||
|
<OnValueChanged>
|
||||||
|
Guda_SettingsPopup_IconSizeSlider_OnValueChanged(this)
|
||||||
|
</OnValueChanged>
|
||||||
|
</Scripts>
|
||||||
|
</Slider>
|
||||||
|
|
||||||
|
<!-- Icon Font Size Slider -->
|
||||||
|
<Slider name="$parent_IconFontSizeSlider" inherits="OptionsSliderTemplate">
|
||||||
|
<Size>
|
||||||
|
<AbsDimension x="270" y="17"/>
|
||||||
|
</Size>
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parent_IconSizeSlider">
|
||||||
|
<Offset>
|
||||||
|
<AbsDimension x="0" y="-40"/>
|
||||||
|
</Offset>
|
||||||
|
</Anchor>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnLoad>
|
||||||
|
Guda_SettingsPopup_IconFontSizeSlider_OnLoad(this)
|
||||||
|
</OnLoad>
|
||||||
|
<OnValueChanged>
|
||||||
|
Guda_SettingsPopup_IconFontSizeSlider_OnValueChanged(this)
|
||||||
|
</OnValueChanged>
|
||||||
|
</Scripts>
|
||||||
|
</Slider>
|
||||||
|
|
||||||
|
<!-- Lock Bags Checkbox -->
|
||||||
|
<CheckButton name="$parent_LockBagsCheckbox" inherits="OptionsCheckButtonTemplate">
|
||||||
|
<Anchors>
|
||||||
|
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parent_IconFontSizeSlider">
|
||||||
|
<Offset>
|
||||||
|
<AbsDimension x="-120" y="-30"/>
|
||||||
|
</Offset>
|
||||||
|
</Anchor>
|
||||||
|
</Anchors>
|
||||||
|
<Scripts>
|
||||||
|
<OnLoad>
|
||||||
|
Guda_SettingsPopup_LockBagsCheckbox_OnLoad(this)
|
||||||
|
</OnLoad>
|
||||||
|
<OnClick>
|
||||||
|
Guda_SettingsPopup_LockBagsCheckbox_OnClick(this)
|
||||||
|
</OnClick>
|
||||||
|
</Scripts>
|
||||||
|
</CheckButton>
|
||||||
|
</Frames>
|
||||||
|
|
||||||
|
<Scripts>
|
||||||
|
<OnLoad>
|
||||||
|
Guda_SettingsPopup_OnLoad(this)
|
||||||
|
</OnLoad>
|
||||||
|
<OnShow>
|
||||||
|
Guda_SettingsPopup_OnShow(this)
|
||||||
|
</OnShow>
|
||||||
|
<OnMouseDown>
|
||||||
|
if (arg1 == "LeftButton") then
|
||||||
|
this:StartMoving()
|
||||||
|
end
|
||||||
|
</OnMouseDown>
|
||||||
|
<OnMouseUp>
|
||||||
|
this:StopMovingOrSizing()
|
||||||
|
</OnMouseUp>
|
||||||
|
</Scripts>
|
||||||
|
</Frame>
|
||||||
|
|
||||||
|
</Ui>
|
||||||
Reference in New Issue
Block a user