diff --git a/TitanLDB/Artwork/Bag_Blue.blp b/TitanLDB/Artwork/Bag_Blue.blp deleted file mode 100644 index 5e7bde1..0000000 Binary files a/TitanLDB/Artwork/Bag_Blue.blp and /dev/null differ diff --git a/TitanLDB/Artwork/Bag_Red.blp b/TitanLDB/Artwork/Bag_Red.blp deleted file mode 100644 index 31579e7..0000000 Binary files a/TitanLDB/Artwork/Bag_Red.blp and /dev/null differ diff --git a/TitanLDB/Artwork/Starter.tga b/TitanLDB/Artwork/Starter.tga deleted file mode 100644 index 6a7ddda..0000000 Binary files a/TitanLDB/Artwork/Starter.tga and /dev/null differ diff --git a/TitanLDB/DevReadMe.lua b/TitanLDB/DevReadMe.lua deleted file mode 100644 index 8ec059d..0000000 --- a/TitanLDB/DevReadMe.lua +++ /dev/null @@ -1,156 +0,0 @@ ---[[ Example -This example is intended to introduce LDB (LibDataBroker) essentials by using an example loosely based on Titan Bag. -A display addon is needed to show this addon. Titan is recommended :). - -This example is intended to be small and light for easy understanding and editting. - -Important notes are denoted with ***: -*** The 'official' LDB spec is here : https://github.com/tekkub/libdatabroker-1-1 . -*** This example is provided as is and without restrictions. -*** Timers are outside the scope of this example. -- Titan built-in addons use timers (AceTimer). -*** Localized strings are outside the scope of this example. -- Titan and built-in plugins use localized strings (AceLocale). - -There are sites that have deeper explanations about addon development such as wowhead or wow wiki (warcraft.wiki.gg). -Please use these or other sites for more detailed addon information. ---]] - ---[[ Folder Structure -This addon folder must be added to the Addon folder to be considered for loading into WoW. -Inside this folder you will notice : -- Artwork folder : icon(s) used by the addon -- libs folder -- .toc files -- one .lua file : for your great idea -- This read me file - -=== .toc -The folder and the .toc files MUST have the same name! -Sort of... the name prior to the underscore(_) must be the same as the folder name. -The name after that (postfix) has meaning to the WoW addon loader. -https://warcraft.wiki.gg/wiki/TOC_format : Contains the full list and A LOT more detail about .toc files - -If your addon is only for Classic Era leave <addon>_Vanilla. Delete (or rename) the other .toc files. - -*** The ## Interface value should match the current interface value of the corresponding WoW version. -If the interface value is higher or lower, WoW will complain that you are running 'out of date' addons. -In the BattleNet app this typically shown below the 'Play' button. -- DragonFlight 10.2.7 is represented without dots - 100207 - in the .toc file. -- Cataclysm 4.4.0 is represented without dots - 40401 - in the .toc file. - -=== Artwork folder: icons and artwork -Anyone can extract the Blizzard UI code and art from WoW. This can be handy to get code examples. -My understanding is any WoW icon can be used within an addon without violating the ToS (Terms of Service). -Wowhead has a searchable list of WoW icons : https://www.wowhead.com/icons - -WoW icons tend to be .blp files. These files are NOT easy to look at or manipulate!! -BLPView (Windows only) from wowinterface is light and easy to view blp files as thumbnails in File Explorer. -You will need to research third party tools to manipulate .blp files. My advice is convert .blp to another format. - -=== libs folder -*** The libraries required for a LDB addon are in the LDB/libs folder. -- WoW does not guarentee the load order of addons. -- If the LDB addon were loaded before the display addon, the loader would throw errors if the libs were not found. -- If the LDB addon requires additional libraries, please include them in libs folder and update the .toc appropriately. - ---]] - ---[[ LDB attributes -The list of required attributes depend on the type of LDB being created. - -Attributes used in this addon: -.type : Required : data source | launcher -.icon : Path to the icon to be used. Place the icon in the addon folder, even if copied from WoW folder. -.label : The label for the addon text -.text : The addon text to display -.OnTooltipShow : The function to use for the tool tip, if any -.OnClick : The function to to handle mouse clicks, if any - - -Available Titan extensions: -.category : The general grouping this addon is in. -- Titan attempts to grab X-Category from the addon TOC first. -- The complete category list is in -- TITAN_PANEL_BUTTONS_PLUGIN_CATEGORY (TitanGlobal.lua) "Built-ins" is reserved for addons that Titan releases! -.version : Addon version shown in Titan menus and config. -- Titan attempts to grab Version from the addon TOC first. -.OnDoubleClick : Implemented by orig dev, not sure this is used by any addon. - -The three data elements are: -- icon -- label -- text - -When any of these are changed, the LDB lib initiates a callback to the display addon. -The display addon registers for these callbacks and creates any frame(s) it needs to display the LDB addon data. ---]] - ---[[ Editing -Before you start changing this example it is HIGHLY recommended to install the following addons: -- BugGrabber : Grabs errors and stores them -- BugSack : The visual part of BugGrabber -- WowLua : Allows you to try Lua code directly in WoW. - -It is recommended you make small changes then check your coding. -When testing just start or /reload WoW. All versions now check and load new files on reload. - -Routines: -GetBagSlotInfo will be replaced by your code. - -Button_OnEvent will be changed to react to any events your addon needs. -- All events registered for should be handled here. -- The display addon is not directly involved in any event handling of this addon. ---]] - ---[[ Code flow within WoW -First step: ==== Starting WoW -Wow will load addons in the Addons folder. -Order is not guaranteed, however dependencies (## Dependencies) are honored. - -When this addon is loaded any code outside the Lua functions will be run. -Examples: -- local VERSION = GetAddOnMetadata(add_on, "Version") will set VERSION -- ... -- Create_Frames is called - -Create_Frames will create the addon frame StarterLDBExample. -- All created frames will be in the global namespace. -- All created frames are forever – they are not touched by the Lua garbage collection. - -Then Create_frames sets the frame OnEvent script handler. This is the only handler required in this addon. - -Then local LDB_Init will initialize the required LDB object. -This routine should be small : -- Set the LDB object -- Set required local variables -- Register for PLAYER_ENTERING_WORLD -- *** DO NOT rely on any saved variables (## SavedVariables) being ready here - -Next: ==== Waiting for WoW -WoW fires a bunch of events as addons are loaded. - -Eventually the game and all addons are loaded and addons receive the PLAYER_ENTERING_WORLD event via the frame script OnEvent. -When processing PLAYER_ENTERING_WORLD, register for additional events your addon requires. -Any saved variables should be ready. - -Next: ==== Still waiting for WoW -The display addon (such as Titan) shows the user requested bars with the user requested addons. - -The addon is now ready for the user. - -Next: ==== Ready to play WoW! Yeah! -The addon is 'idle' until one of the following occur: -- Any registered event is received - OnEvent -- User clicks on this addon - OnClick via display addon -- User mouses over addon - OnTooltipShow via display addon -- User mouse leaves addon - OnLeave via display addon - -Next: ==== -The above steps continues until: -- The user logs out the character or exits WoW or reloads UI - Onhide - -On logout or exit any saved variables are saved to the local system. -No additional actions are required. - ---]] diff --git a/TitanLDB/StarterLDB.lua b/TitanLDB/StarterLDB.lua deleted file mode 100644 index c0ceadb..0000000 --- a/TitanLDB/StarterLDB.lua +++ /dev/null @@ -1,253 +0,0 @@ ---[[ StarterLDB.lua -By: The Titan Panel Development Team ---]] - - --- Intended for Intellisense if an IDE supports and is used --- Lines starting with triple dash are usually Intellisense ----@class Frame WoW frame to get events ----@field obj table For LDB object - --- ******************************** Constants ******************************* -local ADDON_NAME = ... --- Set the name we want in the global name space. Ensure the name is unique across all addons. -StarterLDB = {} - --- NOTE: The 'id' and the 'addon' name are different! --- Typically they are the same to reduce user confusion but they do not need to be the same. -local id = "LDBStarter"; -- Name the user dhould see in the display addon -local addon = ADDON_NAME -- addon name / folder name / toc name - --- Localized strings are outside the scope of this example. - ---[[ -The artwork path must start with Interface\\AddOns -Then the name of the plugin -Then any additional folder(s) to your artwork / icons. -Double backslash will for for Windows; forward slash works fine. ---]] -local artwork_path = "Interface/AddOns/TitanLDB/Artwork/" ----@diagnostic disable-next-line: deprecated, undefined-global -local GetAddOnMetadata = C_AddOns.GetAddOnMetadata or GetAddOnMetadata - --- Get data from the TOC file. -local version = tostring(GetAddOnMetadata(addon, "Version")) or "Unknown" -local author = GetAddOnMetadata(addon, "Author") or "Unknown" --- NOTE: GetAddOnMetadata expects the addon name : --- The addon folder name or .toc name needs to be the same. - --- ******************************** Variables ******************************* -local trace = false -- toggle to show / hide debug statements in this addon - --- ******************************** Functions ******************************* - ----Output a debug statement to Chat with timestamp. ----@param debug_message string ----@param debug_type string -local function Debug(debug_message, debug_type) - if trace then - local dtype = "" - local time_stamp = "" - local msg = "" - if debug_type == "error" then - dtype = "Error: " - elseif debug_type == "warning" then - dtype = "Warning: " - end - time_stamp = date("%H:%M:%S") .. ": " - - msg = - tostring(addon) .. ": " - .. time_stamp - .. dtype - .. debug_message - - _G["DEFAULT_CHAT_FRAME"]:AddMessage(msg) - else - -- not requested - end - --date("%m/%d/%y %H:%M:%S") -end - ---- Calculate bag space then return text and icon to display ----@return string bagText display text ----@return string icon path to -local function GetBagSlotInfo() - local totalSlots, usedSlots, availableSlots, icon - totalSlots = 0; - usedSlots = 0; - for bag = 0, 4 do - local size = C_Container.GetContainerNumSlots(bag); - if (size and size > 0) then - totalSlots = totalSlots + size; - local free = C_Container.GetContainerNumFreeSlots(bag) - local used = size - free - usedSlots = usedSlots + used; - end - end - availableSlots = totalSlots - usedSlots; - - local i, r = math.modf(availableSlots / 2) - -- Simple example of changing the icon : even blue - odd red - -- wowhead.com/icons was searched and these selected - -- The art was extracted : ../_retail_/BliizardInterfaceArt - -- These were found in /Interface/ICONS of the extracted folder by the name used on wowhead - -- Copied into /Artwork in case Blizz ever renames or removes these icons. - if (r == 0) then - icon = artwork_path .. "Bag_Blue.blp" - else - icon = artwork_path .. "Bag_Red.blp" - end - - local bagText - bagText = format("%d/%d", availableSlots, totalSlots); - - bagText = HIGHLIGHT_FONT_COLOR_CODE .. bagText .. FONT_COLOR_CODE_CLOSE - - return bagText, icon -end - ---- Create the tooltip ----@param tooltip GameTooltip From display addon -local function LDB_OnTooltipShow(tooltip) - tooltip = tooltip or GameTooltip -- for safety - local tt_str = "" - - tt_str = - GREEN_FONT_COLOR_CODE - .. id .. " Info" - .. FONT_COLOR_CODE_CLOSE - tooltip:AddLine(tt_str) - - local text, icon = GetBagSlotInfo() - tt_str = "Available bag slots" - .. " " .. text .. "\n" - .. "\n" .. "Hint: Left-click to open all bags." - - tooltip:AddLine(tt_str) -end - ---- Initialize the LDB obj and initial set up ----@param LDB_frame Frame Addon frame -local function LDB_Init(LDB_frame) - Debug(id .. " Init ...", "normal"); - --[[ - Initialize the Data Broker 'button'. - This is the heart of a LDB plugin. It determines how the display addon is to treat this addon. - - Setting the type is required so the LDB lib and display addon know what to do. See the LDB spec. - - id will be the name Titan uses for the plugin. You can find it in the Titan Config or Titan right click menu. - --]] - - LDB_frame.obj = - LibStub("LibDataBroker-1.1"):NewDataObject(id, -- Name used within Titan - { - type = "data source", -- required - -- LDB spec: The two options are: - -- "data source" - Expected to show some type of info - -- "launcher" - Expected to open another window or perform some action - icon = artwork_path .. "Starter.tga", -- The icon to display on the display addon - label = id, -- label for the text - text = "nyl", -- will be updated as needed by this plugin - OnTooltipShow = function(tooltip) - LDB_OnTooltipShow(tooltip) - end, - OnClick = function(self, button) - if (button == "LeftButton") then - -- Just a simple action to illustrate an LDB addon. - ToggleAllBags(); - elseif (button == "RightButton") then - -- There is no action to take in this example. - --[[ Add code here if your addon needs to do something on right click. - Typically an options menu which is outside the scope of this example. - --]] - end - end, - -- Titan specific!! - category = "Information", -- Otherwise defaults to General : TITAN_PANEL_BUTTONS_PLUGIN_CATEGORY - }) - - -- After player entering world it is safe - -- - to look at any saved variables - -- - register for more events; registering here may cause errors if data is not ready - LDB_frame:RegisterEvent("PLAYER_ENTERING_WORLD"); - - Debug(id .. " Init fini.", "normal"); -end - ---- Update the Bags Data Broker 'button' ----@param LDB_frame Frame -local function LDB_Update(LDB_frame) - local text, icon = GetBagSlotInfo() - LDB_frame.obj.text = text - LDB_frame.obj.icon = icon -end - ---- Parse events registered events and act on them ----@param self Button ----@param event string ----@param ... any -local function Button_OnEvent(self, event, ...) - -- https://warcraft.wiki.gg/wiki/UIHANDLER_OnEvent - - Debug("OnEvent" - .. " " .. tostring(event) .. "" - , "normal") - if (event == "PLAYER_ENTERING_WORLD") then - -- Do any additional set up needed - -- - -- Now that events have settled, register the one(s) we really want. - -- Registering here may reduce churn and possible timing issues wrt data being ready - self:RegisterEvent("BAG_UPDATE"); - - -- Unregister events no longer needed. - -- Good practice to avoid init again - this is fired on /reload - self:UnregisterEvent("PLAYER_ENTERING_WORLD"); - - -- Update the text (bag numbers) - LDB_Update(self) - - end - if event == "BAG_UPDATE" then - LDB_Update(self) - end -end - ---- Create needed frames -local function Create_Frames() - -- general container frame to get events from WoW. - -- The display addon will create frame(s) needed to display data set by this addon. - local window = CreateFrame("Frame", "StarterLDBExample", UIParent) - -- window:Hide() - - -- Set strata as desired - window:SetFrameStrata("FULLSCREEN") - -- https://warcraft.wiki.gg/wiki/Frame_Strata - - window:SetScript("OnEvent", function(self, event, ...) - Button_OnEvent(self, event, ...) - end) - -- https://warcraft.wiki.gg/wiki/API_ScriptObject_SetScript - - -- Using SetScript("OnLoad", does not work - LDB_Init(window) - - -- shamelessly print a load message to chat window - DEFAULT_CHAT_FRAME:AddMessage( - GREEN_FONT_COLOR_CODE - .. addon .. id .. " " .. version - .. " by " - .. FONT_COLOR_CODE_CLOSE - .. "|cFFFFFF00" .. author .. FONT_COLOR_CODE_CLOSE); -end - -Create_Frames() -- Create WoW frames to get events - ---[[ -print("" - .." "..tostring(id).."" - .." "..tostring(version).."" - .." by "..tostring(author).."" - ) ---]] diff --git a/TitanLDB/TitanLDB.toc b/TitanLDB/TitanLDB.toc deleted file mode 100644 index 94e79e1..0000000 --- a/TitanLDB/TitanLDB.toc +++ /dev/null @@ -1,13 +0,0 @@ -## Interface: 110000 -## Title: StarterLDB -## Notes: LDB example -## Author: Titan Dev Team -## DefaultState: Enabled -## SavedVariables: -## OptionalDeps: -## Dependencies: -## Version: 1.1 -## X-Child-Of: -libs/CallbackHandler-1.0/CallbackHandler-1.0.xml -libs/LibDataBroker-1.1.lua -StarterLDB.lua diff --git a/TitanLDB/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua b/TitanLDB/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua deleted file mode 100644 index 01287bd..0000000 --- a/TitanLDB/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua +++ /dev/null @@ -1,202 +0,0 @@ ---[[ $Id: CallbackHandler-1.0.lua 1298 2022-12-12 15:10:10Z nevcairiel $ ]] -local MAJOR, MINOR = "CallbackHandler-1.0", 8 -local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR) - -if not CallbackHandler then return end -- No upgrade needed - -local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end} - --- Lua APIs -local securecallfunction, error = securecallfunction, error -local setmetatable, rawget = setmetatable, rawget -local next, select, pairs, type, tostring = next, select, pairs, type, tostring - - -local function Dispatch(handlers, ...) - local index, method = next(handlers) - if not method then return end - repeat - securecallfunction(method, ...) - index, method = next(handlers, index) - until not method -end - --------------------------------------------------------------------------- --- CallbackHandler:New --- --- target - target object to embed public APIs in --- RegisterName - name of the callback registration API, default "RegisterCallback" --- UnregisterName - name of the callback unregistration API, default "UnregisterCallback" --- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API. - -function CallbackHandler.New(_self, target, RegisterName, UnregisterName, UnregisterAllName) - - RegisterName = RegisterName or "RegisterCallback" - UnregisterName = UnregisterName or "UnregisterCallback" - if UnregisterAllName==nil then -- false is used to indicate "don't want this method" - UnregisterAllName = "UnregisterAllCallbacks" - end - - -- we declare all objects and exported APIs inside this closure to quickly gain access - -- to e.g. function names, the "target" parameter, etc - - - -- Create the registry object - local events = setmetatable({}, meta) - local registry = { recurse=0, events=events } - - -- registry:Fire() - fires the given event/message into the registry - function registry:Fire(eventname, ...) - if not rawget(events, eventname) or not next(events[eventname]) then return end - local oldrecurse = registry.recurse - registry.recurse = oldrecurse + 1 - - Dispatch(events[eventname], eventname, ...) - - registry.recurse = oldrecurse - - if registry.insertQueue and oldrecurse==0 then - -- Something in one of our callbacks wanted to register more callbacks; they got queued - for event,callbacks in pairs(registry.insertQueue) do - local first = not rawget(events, event) or not next(events[event]) -- test for empty before. not test for one member after. that one member may have been overwritten. - for object,func in pairs(callbacks) do - events[event][object] = func - -- fire OnUsed callback? - if first and registry.OnUsed then - registry.OnUsed(registry, target, event) - first = nil - end - end - end - registry.insertQueue = nil - end - end - - -- Registration of a callback, handles: - -- self["method"], leads to self["method"](self, ...) - -- self with function ref, leads to functionref(...) - -- "addonId" (instead of self) with function ref, leads to functionref(...) - -- all with an optional arg, which, if present, gets passed as first argument (after self if present) - target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]]) - if type(eventname) ~= "string" then - error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2) - end - - method = method or eventname - - local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. - - if type(method) ~= "string" and type(method) ~= "function" then - error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2) - end - - local regfunc - - if type(method) == "string" then - -- self["method"] calling style - if type(self) ~= "table" then - error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2) - elseif self==target then - error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2) - elseif type(self[method]) ~= "function" then - error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2) - end - - if select("#",...)>=1 then -- this is not the same as testing for arg==nil! - local arg=select(1,...) - regfunc = function(...) self[method](self,arg,...) end - else - regfunc = function(...) self[method](self,...) end - end - else - -- function ref with self=object or self="addonId" or self=thread - if type(self)~="table" and type(self)~="string" and type(self)~="thread" then - error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2) - end - - if select("#",...)>=1 then -- this is not the same as testing for arg==nil! - local arg=select(1,...) - regfunc = function(...) method(arg,...) end - else - regfunc = method - end - end - - - if events[eventname][self] or registry.recurse<1 then - -- if registry.recurse<1 then - -- we're overwriting an existing entry, or not currently recursing. just set it. - events[eventname][self] = regfunc - -- fire OnUsed callback? - if registry.OnUsed and first then - registry.OnUsed(registry, target, eventname) - end - else - -- we're currently processing a callback in this registry, so delay the registration of this new entry! - -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency - registry.insertQueue = registry.insertQueue or setmetatable({},meta) - registry.insertQueue[eventname][self] = regfunc - end - end - - -- Unregister a callback - target[UnregisterName] = function(self, eventname) - if not self or self==target then - error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2) - end - if type(eventname) ~= "string" then - error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2) - end - if rawget(events, eventname) and events[eventname][self] then - events[eventname][self] = nil - -- Fire OnUnused callback? - if registry.OnUnused and not next(events[eventname]) then - registry.OnUnused(registry, target, eventname) - end - end - if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then - registry.insertQueue[eventname][self] = nil - end - end - - -- OPTIONAL: Unregister all callbacks for given selfs/addonIds - if UnregisterAllName then - target[UnregisterAllName] = function(...) - if select("#",...)<1 then - error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2) - end - if select("#",...)==1 and ...==target then - error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2) - end - - - for i=1,select("#",...) do - local self = select(i,...) - if registry.insertQueue then - for eventname, callbacks in pairs(registry.insertQueue) do - if callbacks[self] then - callbacks[self] = nil - end - end - end - for eventname, callbacks in pairs(events) do - if callbacks[self] then - callbacks[self] = nil - -- Fire OnUnused callback? - if registry.OnUnused and not next(callbacks) then - registry.OnUnused(registry, target, eventname) - end - end - end - end - end - end - - return registry -end - - --- CallbackHandler purposefully does NOT do explicit embedding. Nor does it --- try to upgrade old implicit embeds since the system is selfcontained and --- relies on closures to work. - diff --git a/TitanLDB/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml b/TitanLDB/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml deleted file mode 100644 index a5b22a7..0000000 --- a/TitanLDB/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml +++ /dev/null @@ -1,4 +0,0 @@ -<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/ -..\FrameXML\UI.xsd"> - <Script file="CallbackHandler-1.0.lua"/> -</Ui> diff --git a/TitanLDB/libs/LibDataBroker-1.1.lua b/TitanLDB/libs/LibDataBroker-1.1.lua deleted file mode 100644 index 4182f2e..0000000 --- a/TitanLDB/libs/LibDataBroker-1.1.lua +++ /dev/null @@ -1,90 +0,0 @@ - -assert(LibStub, "LibDataBroker-1.1 requires LibStub") -assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0") - -local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4) -if not lib then return end -oldminor = oldminor or 0 - - -lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib) -lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {} -local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks - -if oldminor < 2 then - lib.domt = { - __metatable = "access denied", - __index = function(self, key) return attributestorage[self] and attributestorage[self][key] end, - } -end - -if oldminor < 3 then - lib.domt.__newindex = function(self, key, value) - if not attributestorage[self] then attributestorage[self] = {} end - if attributestorage[self][key] == value then return end - attributestorage[self][key] = value - local name = namestorage[self] - if not name then return end - callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self) - callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self) - callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self) - callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self) - end -end - -if oldminor < 2 then - function lib:NewDataObject(name, dataobj) - if self.proxystorage[name] then return end - - if dataobj then - assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table") - self.attributestorage[dataobj] = {} - for i,v in pairs(dataobj) do - self.attributestorage[dataobj][i] = v - dataobj[i] = nil - end - end - dataobj = setmetatable(dataobj or {}, self.domt) - self.proxystorage[name], self.namestorage[dataobj] = dataobj, name - self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj) - return dataobj - end -end - -if oldminor < 1 then - function lib:DataObjectIterator() - return pairs(self.proxystorage) - end - - function lib:GetDataObjectByName(dataobjectname) - return self.proxystorage[dataobjectname] - end - - function lib:GetNameByDataObject(dataobject) - return self.namestorage[dataobject] - end -end - -if oldminor < 4 then - local next = pairs(attributestorage) - function lib:pairs(dataobject_or_name) - local t = type(dataobject_or_name) - assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)") - - local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name - assert(attributestorage[dataobj], "Data object not found") - - return next, attributestorage[dataobj], nil - end - - local ipairs_iter = ipairs(attributestorage) - function lib:ipairs(dataobject_or_name) - local t = type(dataobject_or_name) - assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)") - - local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name - assert(attributestorage[dataobj], "Data object not found") - - return ipairs_iter, attributestorage[dataobj], 0 - end -end diff --git a/TitanPlugin/Artwork/TitanStarter.tga b/TitanPlugin/Artwork/TitanStarter.tga deleted file mode 100644 index 6a7ddda..0000000 Binary files a/TitanPlugin/Artwork/TitanStarter.tga and /dev/null differ diff --git a/TitanPlugin/DevReadMe.lua b/TitanPlugin/DevReadMe.lua deleted file mode 100644 index c0a438d..0000000 --- a/TitanPlugin/DevReadMe.lua +++ /dev/null @@ -1,539 +0,0 @@ ---[[ Titan Example with Explanation - -This example will introduce Titan plugin essentials using a Titan plugin loosely based on Titan Bag. -The intent is to clarify what may appear to be a daunting experience. - -We suggest you grab your favorite beverage, read this doc, and relax! -Many of Titan mysteries will be explained. Helping you create a tool your audience will enjoy. 🙂 - -The Titan team and its users are available to answer questions. -The two most used ways are : -- The Titan Discord community - https://discord.gg/e93sxuSPwC -- Curse comments under Titan Panel addon - -Using a text editor with code folding features will make this file easier to read and find information. -Notepad++ is a popular Windows code editor. -Visual Studio Code with a couple extensions can be used to develop WoW addons. ---]] - ---[[ Titan Panel Notes: -- Use the current version of Titan to ensure no errors. -- You may freely use this example for addon development and publish it on WoW addon sites like Curseforge. If published, please add the Titan tag for users. -- The terms addon and plugin are essentially the same. Within this document, plugin is used when the addon is displayed by Titan. -- Titan includes several libraries under the Titan/libs folder. You are free to use these. -If you require additional libraries, please include them within your addon. - -=== Out of Scope Notes: -- A discussion on Lua syntax. A basic understanding of Lua is assumed. -- Timers are outside the scope of this example. See other Titan built-in plugins that use timers (AceTimer) such as TitanClock. -- Localization of strings presented to the user. Titan uses AceLocale; other addons use different schemes. -- Ace library information. Titan includes the Ace libraries it uses - not the entire library. (https://www.wowace.com) -- The API for LDB (LibDataBroker) : (https://github.com/tekkub/libdatabroker-1-1) -- WoW images : Some image type info (https://warcraft.wiki.gg/wiki/API_TextureBase_SetTexture) ---]] - ---[[ “Best Practices” When Creating Your Addon/Plugin -=== Naming Convention -When publishing your addon/plugin please use this naming convention : - -Titan Panel [Name] - -Using this naming format, most Titan users will understand this plugin is intended for Titan Panel. -They should know to contact you first instead of the Titan Panel team. -The Titan team does receive comments and errors from time to time. We usually tell them to contact the plugin developer. - -=== Additional Help For You -A good Lua resource is https://www.lua.org/docs.html -NOTE: WoW uses Lua version 5.1 as its base. -NOTE: WoW does restrict, add, or even remove some Lua features. For example the file routines and many OS routines are not available to an addon. - -There are sites that have deeper explanations about addon development, such as -- Wowhead.com -- Warcraft wiki (Warcraft.Wiki.gg). -Please use these or other sites for more detailed addon and API information. The API information changes over time for several reasons. ---]] - ---[[ Running right now! -The folder and .toc file prefix MUST be the same to be considered for loading into WoW! -See the .toc section under Example Folder Structure. - -=== Steps needed to run this example: -- Unzip this example to your WoW installation: ../World of Warcraft/_retail_/Interface/AddOns -- Ensure the folder name is TitanPlugin -- Start or reload WoW - -That is it! -You should see another Titan Bag icon in any version of WoW you are running. -You are now ready to start changing code. ---]] - ---[[ Example Folder Structure -Inside this folder you will notice : -- Artwork folder : with one .tga file - the icon used by the plugin -- libs : empty, ready for any library routines you may need -- three .toc files -- one .lua file – for your great idea -- a ReadMe file - This file - -=== .toc - -The folder and the .toc files MUST have the same name! -Sort of... the name prior to the underscore(_) must be the same as the folder name. -The part after (postfix) has meaning to the WoW addon loader. -https://warcraft.wiki.gg/wiki/TOC_format : Contains the full list and A LOT more detail about .toc files - -If your addon is only for Classic Era leave <addon>_Vanilla. Delete (or rename) the other .toc files. -Titan uses this TOC method. Notice TitanAmmo and TitanRegen. -This allows Titan to load differently so plugins (built-in or 3rd party) intended for Classic versions can run without change. - -=== .toc internals -NOTE: The ## Interface value should match the current interface value of the corresponding WoW version. -In BattleNet this is typically shown below the 'Play' button. -DragonFlight 10.02.05 is represented without dots - 100207 - in the .toc. - -If the interface value is higher or lower, WoW will complain that you are running 'out of date' addons. - -== .lua - -This is the code for the plugin. - -Titan specific details will be noted and explained within the Lua file. -The comments will specify where names are important. - -The plugin starts with local constants used throughout. -Then local variables; then functions. - -Suggestion is start with Create_Frames routine at the bottom of the file. It is where the magic starts. - -NOTES: -- Titan locale strings (using AceLocale) were left in the code so the example will run as is. Please use your own strings - localized or not. -- Feel free to look at Titan code for Lua examples. -- Any routine marked with ---API can be used by a plugin. -Titan API routines will be maintained and the functionality expected to remain stable. -Any parameter or functionality changes to API will be 'broadcast' on delivery sites and our sites (Discord, our web page). - -=== .tga - -This file is the icon used by the plugin. -This file is also specified in the .registry of the Lua file – detailed later in this doc. ---]] - ---[[ Start editing - -Before you start changing this example, it is HIGHLY recommended to install the following WoW addons: -- BugGrabber : Grabs errors and stores them -- BugSack : The visual part of BugGrabber -- WowLua : This allows you to try Lua code directly in WoW. - -Install a code / text editor. Notepad++ is a very popular editor. - -Small changes are recommended; then test your coding. -When testing, just start or /reload WoW. All versions now check and load new files on reload. - -First Routines to change: -- GetBagData will be replaced by your code. It uses the local function IsProfessionBagID. -- ToggleBags is called from OnClick. This will be replaced by your code that handles mouse clicks. -- CreateMenu will be changed to implement your right click menu, if one is needed. - -Other routines may be modified to implement your idea. - ---]] - ---[[ Addon code flow - -First step: ==== Starting WoW -Wow will load this addon after Titan is loaded. - -NOTE: The .toc states Titan is required [## Dependencies: Titan]. -WoW will load Titan BEFORE this addon. - -Any code outside the Lua functions will be run. -Examples: -- local VERSION = GetAddOnMetadata(add_on, "Version") will run GetAddOnMetadata -- bag_info will be populated -- ... -- Create_Frames is called - -Create_Frames will create the addon frame and name it the string in TITAN_BUTTON. -All created frames will be in the global namespace. -All created frames are forever – they are not touched by the Lua garbage collection. - -Then local OnLoad is called when WoW loads the frame into memory. - -OnLoad does two important things -1) Sets the .registry of the addon - See the .registry comment block -2) Registers for event PLAYER_ENTERING_WORLD - -NOTE: OnLoad should : -- Be small -- NOT assume plugin saved variable data are ready / loaded yet - -Then Create_frames sets the frame scripts for the addon. See Frame Scripts block. - -Next: ==== Waiting for WoW -WoW fires a bunch of events as this and other addons are loaded. - -Eventually the game and all addons are loaded and this plugin receives the PLAYER_ENTERING_WORLD event via the frame script OnEvent. -When processing PLAYER_ENTERING_WORLD, only register for events and access local data this plugin needs. -Do NOT assume saved variables from the registry or any server data are ready. - -Titan also receives the PLAYER_ENTERING_WORLD event. -It is best to assume there is NO guarantee this plugin receives the event before or after Titan! - -Titan then processes its own data, creates Titan bars, registers Titan plugins and LDB addons, and syncs plugin saved variables. -Titan will process any saved variables specified in the .registry of this plugin! - -Next: ==== Still waiting for WoW -Titan shows the user requested bars with the user requested plugins. -OnShow is called by Titan only if the user has requested the plugin to be shown. -It is best to assume any saved variables in .registry are NOT ready until OnShow! - -OnShow now does the processing to set up this plugin and its data properly. -Lastly OnShow needs to call TitanPanelButton_UpdateButton to update the plugin text. -The plugin is now ready for the user. - -Next: ==== Ready to play WoW, Yeah! -The plugin will be 'idle' until one of the following occur: -- Titan needs to (re)display this plugin - TitanPanelButton_UpdateButton -- User selects to show this plugin via Titan Config or menu - TitanPanelButton_UpdateButton -- User changes a plugin option using the Titan plugin menu : TitanPanelButton_UpdateButton -- User clicks on this plugin - Right click .menuTextFunction; any other OnClick -- Any registered event is received - OnEvent -- User mouses over plugin - OnEnter -- User mouse leaves plugin - OnLeave -- A timer or callback calls a plugin routine – AceTimer - -Next: ==== -The above steps continue until: -- User hides the plugin - OnHide -- The user logs out the character or exits WoW or reloads UI - Onhide - -On logout or exit the saved variables are saved to the local system - .registry.savedVariables . -No additional actions are required. - -==== Using OnShow to set up this addon is good practice : -It should: -- Register any events the plugin will react to -- Process any saved variable data such as user options -- Create any timers -- Set the initial plugin - icon, label, text - -This ensures: -- All saved variable data is set and ready -- Less processing if the user never selects the plugin - -==== Using OnHide to clean up is good practice : -It should: -- Unregister any events the plugin registered for -- Cancel any timers -- Cleanup any plugin specific data or objects - -This ensures: -- Less processing after the user clicks Hide - -==== TitanPanelButton_UpdateButton(TITAN_PLUGIN) should be called by this plugin whenever the plugin text could change : -- On processing an event registered for -- On user left click – some action taken -- On user right click – plugin menu - -NOTE: TitanPanelButton_UpdateButton expects label - value pairs (up to 4). -TitanPerformance uses and shows multiple label - value pairs, based on user selection. - -Titan uses ShowLabelText to control showing the label or not. This plugin only returns the expected label(s). - -==== OnEnter and OnLeave -NOTE: The Titan template handles OnEnter and OnLeave to show or hide the tooltip. -Titan calls the specified routine to show the tooltip – .registry.tooltipTextFunction. -Titan expects a formatted string as the return from the function. - -==== Additional saved variables specific to this addon must be handled by this addon and are outside the scope of this example. -Titan Gold is a Titan plugin that has its own saved variables. ---]] - ---[[ Frame Scripts - -The frame scripts are how WoW and Titan interact with this addon. -NOTE: The creation of the frame also creates scripts handlers. This is a bit hidden by the 'inherits' "TitanPanelComboTemplate" below. - local window = CreateFrame("Button", TITAN_BUTTON, f, "TitanPanelComboTemplate") -TitanTemplate.xml defines TitanPanelButtonTemplate as the base for each of its plugin types - Combo / Text / Icon. -TitanPanelButtonTemplate sets OnLoad / OnShow / OnClick / OnEnter / OnLeave where each calls TitanPanelButton_On*. -If the script is overriden in the plugin, it should call the appropriate TitanPanelButton_On* routine as shown below. -In a few cases, the default is not called because the plugin replaces what Titan would do. -TitanPerformance, for example overrides OnClick to create a custom right click menu. - -==== OnShow script : -This is triggered when this plugin (frame) is shown. -Technically : -- WoW calls the now registered plugin frame - TITAN_BUTTON:OnShow() as set in Create_Frames -- Which calls the local OnShow to init the plugin -- Then calls TitanPanelButton_OnShow to update the plugin button text - -==== OnClick script : -This is triggered when this plugin (frame) has been clicked by the mouse. -Technically : -- WoW calls the now registered plugin frame - TITAN_BUTTON:OnClick() as set in Create_Frames -- Which calls the local OnClick to handle left click (or any click / mod-click other than right click) -- Then calls TitanPanelButton_OnClick to handle right click (plugin menu) – see ‘Right Click’ below - -== Right click: -TitanPanelButton_OnClick is called to handle right click generically because it will -- Close any open control frame -- Close any tooltip -- Position the menu relative to the plugin on whatever Titan bar it is on -- Call the plugin routine to create the actual menu content - -The plugin routine here is local CreateMenu. - -The plugin can inform Titan of the routine in one of two ways: -1) Specify in .registry.menuTextFunction - preferred -2) Named routine in the global namespace with the expected name of - TitanPanelRightClickMenu_Prepare<id>Menu -- For this plugin the name would be TitanPanelRightClickMenu_PrepareStarterMenu -Titan will use the registry over the created routine. It will not use both. - -==== OnEnter script : -OnEnter is handled by the Titan template to show the tooltip next to the plugin wherever it may be. -It calls the routine specified in .registry.tooltipTextFunction. -This routine is expected to return a formatted string to be shown inthe tooltip. - -==== OnLeave script : -OnLeave is handled by the Titan template to hide the tooltip. - -==== OnHide script : -This is triggered when this plugin (frame) has been hidden by the user : -- via the plugin menu -- via Titan config -- On exit or logout or /reload -Technically : -- WoW calls the now registered plugin frame - TITAN_BUTTON:OnHide() as set in Create_Frames -- Which calls the local OnHide -The local OnHide should : -- Do any cleanup your plugin needs -- Stop any timers -- Unregister any events -These steps keep processing to a minimum and reduce the chance of errors to the user. - -==== OnEvent script : -This is triggered when any event this plugin (frame) has registered for is fired. -Technically : -- WoW calls the now registered plugin frame - TITAN_BUTTON:OnEvent() as set in Create_Frames -- Which calls the local OnEvent to handle all registered events - -Titan Bag uses PLAYER_ENTERING_WORLD to handle a difference between Retail and Classic versions when opening bags via the addon. - -BAG_UPDATE just updates the text (count) whenever this event is fired. -NOTE: The event also fires when moving items within the bag... ---]] - ---[[ .registry attributes -This is the GUTS of a Titan plugin. The .registry table on the frame contains all the information to register the plugin for display. - -Every plugin registry with an id should appear in Titan > Configuration > Attempts. -Information about the plugin is shown there along with pass / fail. -If the plugin failed to register, the error is shown there. - -NOTE: Titan looks for 3 routines. See .registry Routines. - -Attributes: -.id : Required : must be unique across Titan plugins. If there are duplicates, the first one 'wins'. -.category : The general grouping this plugin is in. - The complete category list is in TITAN_PANEL_BUTTONS_PLUGIN_CATEGORY (TitanGlobal.lua) - "Built-ins" is reserved for plugins that Titan releases. -.version : plugin version shown in menus and config. -.menuText : Used as the title for the right click menu. -.menuTextFunction : See .registry Routines. -.buttonTextFunction : See .registry Routines. -.tooltipTitle : Used as the title for the tool tip -.tooltipTextFunction : See .registry Routines. -.icon : Allowed path to the icon to be used. - It is recommended to store the icon in the plugin folder, even if exists within WoW. -.iconWidth : Best left at 16... -.notes : This is shown in Titan > Config > Plugins when this plugin is selected. -.controlVariables : This list is controls whether the variable is shown. See below. -.savedVariables : These are the variables stored in Titan saved variables. - The initial values are used only if that particular entry is 'new' to - that character (new Titan install, new character, character new to Titan). - If a value is removed then it is removed from the saved variables as Titan is run for each character. - -== .controlVariables -These are used to show or hide 'controls' in the Titan config or Titan right click menu. -- ShowIcon -- ShowLabelText -- ShowColoredText -- DisplayOnRightSide -- ShowRegularText (LDB only) -If true, the control is shown to the user. -If false, the control is not shown to the user. ---]] - ---[[ .registry Saved Variables - -All saved variables for this plugin are listed within savedVariables -- ShowUsedSlots = 1, -- ShowDetailedInfo = false, -- CountProfBagSlots = false, -- ShowIcon = 1, -- ShowLabelText = 1, -- ShowColoredText = 1, -- DisplayOnRightSide = false, -- OpenBags = false, -- OpenBagsClassic = "new_install", - -Plugin variables : -- ShowUsedSlots : Show used versus available slots -- ShowDetailedInfo : Show bag details in the tooltip -- CountProfBagSlots : Whether to include, or not, profession bags in the counts -- OpenBags : Whether to open bags on left click or not. Included due to a taint issue introduced by WoW -- OpenBagsClassic : Used to determine a new install / new character (to Titan or just created) - -Titan uses the below to control display of the plugin : -- ShowIcon : Whether the icon,if specified is shown -- ShowLabelText : Whether the labels returned by buttonTextFunction are shown -- ShowColoredText : Whether the text is 'colored' or not -- DisplayOnRightSide : Put this plugin in the right side of the Titan bar - -ShowColoredText is plugin specific. Generally used to indicate a range such as your bags are empty (green) to nearly full (red). -If the plugin does not need this then please set controlVariables > ShowColoredText to false to prevent the user from seeing -the option and potentially getting confused. - -NOTE: Titan routines have used 1 as true since inception so be careful on 'true checks'. -"if ShowUsedSlots then " *should* work fine if ShowUsedSlots is true or 1 - -=== Where are these saved variables????? -The saved variables are specified in the Titan toc : -## SavedVariables: TitanAll, TitanSettings, TitanSkins, ServerTimeOffsets, ServerHourFormat - -TitanSettings contains all the plugin saved variables. -Titan uses the single table structure to store the saved variables across a user account. -This makes the setup code rather cumbersome and not straight forward - just warning... - -The saved variables can be found here: .../World of Warcraft/_retail_/WTF/Account/(account name>/SavedVariables/Titan.lua -There is a Titan.lua.bak which is the prior save (logout / exit / reload). - -It is HIGHLY recommended opening the saved variables file in an editor with code folding features! -This file could be quite large with many lines. -I have 20+ characters on one server. Even though I do not use many addons, I do test with addons on some characters. -A plugin such as Titan Panel [Reputation] can create 100+ plugins. My file is nearly 90,000 lines long! - -Say we want to find a character named Embic on Staghelm being used for testing to examine the saved variables. -This would under -TitanSettings = { - ["Players"] = { - ["Embic@Staghelm"] = { - ["Panel"] = { - -- Holds all the Titan settings for this character - } - ["BarVars"] = { - -- Holds all the Titan bar settings for this character - } - ["Plugins"] = { - -- Each registered plugin will be here - ["Starter"] = { - ["notes"] = "Adds bag and free slot information to Titan Panel.\n", - ["menuTextFunction"] = nil, - ["id"] = "Starter", - ["menuText"] = "Bag", - ["iconWidth"] = 16, - ["savedVariables"] = { - ["ShowColoredText"] = 1, - ["CustomLabel3Text"] = "", - ["ShowIcon"] = 1, - ["OpenBags"] = false, - ["CustomLabel3TextShow"] = false, - ["CustomLabelTextShow"] = false, - ["CustomLabel4Text"] = "", - ["CustomLabel2Text"] = "", - ["OpenBagsClassic"] = "new_install", - ["ShowLabelText"] = 1, - ["CustomLabel4TextShow"] = false, - ["CountProfBagSlots"] = false, - ["ShowUsedSlots"] = 1, - ["DisplayOnRightSide"] = false, - ["ShowDetailedInfo"] = false, - ["CustomLabel2TextShow"] = false, - ["CustomLabelText"] = "", - }, - ["controlVariables"] = { - ["DisplayOnRightSide"] = true, - ["ShowColoredText"] = true, - ["ShowIcon"] = true, - ["ShowLabelText"] = true, - }, - ["version"] = "1.0.0", - ["category"] = "Information", - ["buttonTextFunction"] = nil , - ["tooltipTextFunction"] = nil , - ["icon"] = "Interface\\AddOns\\TitanPlugin\\Artwork\\TitanStarter", - ["tooltipTitle"] = "Bags Info", - }, - } - ["Adjust"] = { - -- Holds offsets for frames the user may adjust - Retail and Classic have different list of frames - } - ["Register"] = { - -- Holds data as each plugin and LDB is attempted to be registered. - -- There may be helpful debug data here under your plugin name if the plugin is not shown as expected. - -- Titan > Configuration > Attempts shows some of this data, including errors. - } - -NOTES: -- "Starter" index under Plugins is also .registry.id !! -- This lists the last saved contents of .registry - NOT what is in memory! -- This file contains all the tables specified in the Titan .toc file. - ---]] ---[[ .registry Routines - -Titan looks for 3 routines specified in the .registry : -- .buttonTextFunction : Routine that updates the plugin text. -- .tooltipTextFunction : Routine that generates the tool tip text. -- .menuTextFunction : Routine that creates the options for the menu (right click) OR "TitanPanelRightClickMenu_Prepare"<id>"Menu" - -.menuTextFunction : This is the routine called by Titan on right click so the plugin can create its menu. - 1) This is the newer, preferred method which makes the options menu routine explicit (changed 2024 Feb). - If found, this will be used over the older method - both will not be used. - NOTE: Routine can be specified : - --- As a string, it MUST be in the global namespace. Strings were the only method for a long time. - --- As a function, it may be in the global namespace but could be local. This example uses a local routine which is preferred. - - 2) The older method is still supported! - Titan builds the expected routine name as "TitanPanelRightClickMenu_Prepare"<id>"Menu". - In this example it would be : TitanPanelRightClickMenu_PrepareStarterMenu - -.buttonTextFunction : This is called whenever the button is to be updated. - This is called from within the plugin and from Titan by calling TitanPanelButton_UpdateButton(TITAN_PLUGIN) . - Titan will usually return "<?>" if the routine dies. - If you need to see the error, search for this attribute in the Titan folder and uncomment the print of the error message. - This may generate a LOT of messages! -.tooltipTextFunction : This is called when the mouse enters the plugin frame is triggered. - The Titan templates set the OnEnter script for the plugin frame. - On a tooltip error, Titan will usually show part of the error in the tool tip. - If you need to see the full error, search for this attribute in the Titan folder and uncomment the print of the error message. - -NOTE: The .registry routines are called securely using pcall to protect Titan. -These routines are expected to have NO parameters. Handling parameters was not implemented in any version of Titan. ---]] ---[[ Special Icons and Artwork - -Anyone can extract the Blizzard UI code and art from WoW. This can be handy to get code examples. -And to grab icons to use for a plugin. My understanding is any icon can be used within WoW without violating the ToS. -WoW icons tend to be .blp files. These files are NOT easy to look at or manipulate!! -You will need to research third party tools to manipulate .blp files. -BLPView (Windows only) from wowinterface is light and easy to view blp files as thumbnail pics in File Explorer. - -==== Extracting art and code -Add the switch -console when starting WoW. -In BattleNet click the Settings (next to Play) then Game Settintgs. Add as an additional command line argument. - -Start WoW but stay on the character screen. -Hit the ~ (tilde) key to open a text console which will appear from the top of the screen. -Type exportInterfaceFiles (can tab to auto fill) with parameter code or art -exportInterfaceFiles code -exportInterfaceFiles art - -These must be run separately. Code should take a second or so; art may take some time and appear to hang the game. - -For retail, the result will be here : -.../World of Warcraft/_retail_/BlizzardInterfaceCode -.../World of Warcraft/_retail_/BlizzardInterfaceArt ---]] - diff --git a/TitanPlugin/TitanPlugin.toc b/TitanPlugin/TitanPlugin.toc deleted file mode 100644 index 7b177cd..0000000 --- a/TitanPlugin/TitanPlugin.toc +++ /dev/null @@ -1,9 +0,0 @@ -## Interface: 110000 -## Title: Titan Starter -## Version: 1.0.0 -## Notes: Adds bag and free slot information to Titan Panel -## Author: Titan Panel Development Team (http://www.titanpanel.org) -## SavedVariables: -## Dependencies: Titan -## DefaultState: Enabled -TitanStarter.lua diff --git a/TitanPlugin/TitanStarter.lua b/TitanPlugin/TitanStarter.lua deleted file mode 100644 index c8edc4b..0000000 --- a/TitanPlugin/TitanStarter.lua +++ /dev/null @@ -1,569 +0,0 @@ ----@diagnostic disable: duplicate-set-field ---[[ --- ************************************************************************** --- * TitanStarter.lua --- * --- * By: The Titan Panel Development Team --- ************************************************************************** ---]] --- ******************************** Constants ******************************* -local add_on = ... -local _G = _G --getfenv(0); -local artwork_path = "Interface\\AddOns\\TitanPlugin\\Artwork\\" --- NOTE: The plugin id needs be unique across Titan plugins --- It does not need to match the addon id. -local TITAN_PLUGIN = "Starter" --- NOTE: The convention is TitanPanel<id>Button -local TITAN_BUTTON = "TitanPanel" .. TITAN_PLUGIN .. "Button" -local VERSION = C_AddOns.GetAddOnMetadata(add_on, "Version") - -local TITAN_BAG_THRESHOLD_TABLE = { - Values = { 0.5, 0.75, 0.9 }, - Colors = { HIGHLIGHT_FONT_COLOR, NORMAL_FONT_COLOR, ORANGE_FONT_COLOR, RED_FONT_COLOR }, -} - --- ******************************** Variables ******************************* -local L = LibStub("AceLocale-3.0"):GetLocale(TITAN_ID, true) - -local bag_info = { -- itemType : warcraft.wiki.gg/wiki/itemType - [1] = -- Soul bag - { color = { r = 0.96, g = 0.55, b = 0.73 } }, -- PINK - [2] = -- HERBALISM = - { color = { r = 0, g = 1, b = 0 } }, -- GREEN - [3] = -- ENCHANTING = - { color = { r = 0, g = 0, b = 1 } }, -- BLUE - [4] = -- ENGINEERING = - { color = { r = 1, g = 0.49, b = 0.04 } }, -- ORANGE - [5] = -- JEWELCRAFTING = - { color = { r = 1, g = 0, b = 0 } }, -- RED - [6] = -- MINING = - { color = { r = 1, g = 1, b = 1 } }, -- WHITE - [7] = -- LEATHERWORKING = - { color = { r = 0.78, g = 0.61, b = 0.43 } }, -- TAN - [8] = -- INSCRIPTION = - { color = { r = 0.58, g = 0.51, b = 0.79 } }, -- PURPLE - [9] = -- FISHING = - { color = { r = 0.41, g = 0.8, b = 0.94 } }, -- LIGHT_BLUE - [10] = -- COOKING = - { color = { r = 0.96, g = 0.55, b = 0.73 } }, -- PINK - -- These are Classic arrow or bullet bags - [22] = -- Classic arrow - { color = { r = 1, g = .4, b = 0 } }, -- copper - [23] = -- Classic bullet - { color = { r = 0.8, g = 0.8, b = 0.8 } }, -- silver -} - -local trace = false -- true / false Make true when debug output is needed. - -local MIN_BAGS = 0 -local MAX_BAGS = Constants.InventoryConstants.NumBagSlots -local bag_data = {} -- to hold the user bag data - --- ******************************** Functions ******************************* ----@diagnostic disable-next-line: deprecated -local GetInstant = C_Item.GetItemInfoInstant or GetItemInfoInstant - -local function IsProfessionBagID(slot) - -- The info needed is available using GetItemInfoInstant; only the bag / item id is required - -- itemType : warcraft.wiki.gg/wiki/itemType - local res = false - local style = 0 - local info, itemId, itemType, itemSubType, itemEquipLoc, itemTexture, classID, subclassID - local inv_id = C_Container.ContainerIDToInventoryID(slot) - - if inv_id == nil then - -- Only works on bag and bank bags NOT backpack! - else - info = GetInventoryItemLink("player", inv_id) - itemId, itemType, itemSubType, itemEquipLoc, itemTexture, classID, subclassID = GetInstant(info) - style = subclassID - - if classID == 1 then -- is a container / bag - if subclassID >= 1 then - -- profession bag of some type [2 - 10] Jan 2024 (DragonFlight / Wrath / Classic Era) - -- OR soul bag [1] - res = true - else - -- is a arrow or bullet; only two options - end - elseif classID == 6 then -- is a 'projectile' holder - res = true - -- is a ammo bag or quiver; only two options - elseif classID == 11 then -- is a 'quiver'; Wrath and CE - res = true - -- is a ammo pouch or quiver; only two options - style = subclassID + 20 -- change to get local color for name - else - -- not a bag - end - end - - if trace then - TitanPluginDebug(TITAN_PLUGIN, "T isP:" - .. " " .. tostring(res) .. "" - .. " " .. tostring(style) .. "" - .. " " .. tostring(itemId) .. "" - .. " " .. tostring(classID) .. "" - .. " " .. tostring(subclassID) .. "" - .. " " .. tostring(inv_id) .. "" - ) - end - - return res, style -end - -local function ToggleBags() - if TitanGetVar(TITAN_PLUGIN, "OpenBags") then - ToggleAllBags() - else - end -end - ---[[ -Where the magic happens! -It is good practice - and good memory - to document the 'why' the code does what it does. -And give details that are not obvious to the reader who did not write the code. ---]] -local function GetBagData(id) - --[[ - The bag name is not always available when player entering world - Grabbing the total slots is available though to determine if a bag exists. - The user may see bag name as UNKNOWN until an event triggers a bag check AND the name is available. - --]] - - local total_slots = 0 - local total_free = 0 - local total_used = 0 - - local count_prof = TitanGetVar(TITAN_PLUGIN, "CountProfBagSlots") - - for bag_slot = MIN_BAGS, MAX_BAGS do -- assuming 0 (Backpack) will not be a profession bag - local slots = C_Container.GetContainerNumSlots(bag_slot) - - -- Ensure a blank structure exists - bag_data[bag_slot] = { - has_bag = false, - name = "", - maxi_slots = 0, - free_slots = 0, - used_slots = 0, - style = "", - color = "", - } - - if slots > 0 then - bag_data[bag_slot].has_bag = true - - local bag_name = (C_Container.GetBagName(bag_slot) or UNKNOWN) - bag_data[bag_slot].name = bag_name - bag_data[bag_slot].maxi_slots = slots - - local free = C_Container.GetContainerNumFreeSlots(bag_slot) - local used = slots - free - bag_data[bag_slot].free_slots = free - bag_data[bag_slot].used_slots = used - - -- some info is not known until the name is available... - -- The API requires name to get the bag ID. - local bag_type = "none" - local color = { r = 0, g = 0, b = 0 } -- black (should never be used...) - - -- Jan 2024 : Moved away from named based to an id based. Allows name to come later from server - local is_prof_bag, style = IsProfessionBagID(bag_slot) - - if is_prof_bag then - color = bag_info[style].color - bag_type = "profession" - else - bag_type = "normal" - end - bag_data[bag_slot].style = bag_type - bag_data[bag_slot].color = color - - -- add to total - if bag_data[bag_slot].style == "profession" then - if count_prof then - total_slots = total_slots + slots - total_free = total_free + free - total_used = total_used + used - else - -- ignore in totals - end - else - total_slots = total_slots + slots - total_free = total_free + free - total_used = total_used + used - end - else - bag_data[bag_slot].has_bag = false - end - - if trace then - TitanPluginDebug(TITAN_PLUGIN, "T info" - .. " " .. tostring(bag_slot) .. "" - .. " ?:" .. tostring(bag_data[bag_slot].has_bag) .. "" - .. " max: " .. tostring(bag_data[bag_slot].maxi_slots) .. "" - .. " used: " .. tostring(bag_data[bag_slot].used_slots) .. "" - .. " free: " .. tostring(bag_data[bag_slot].free_slots) .. "" - .. " type: " .. tostring(bag_data[bag_slot].style) .. "" - .. " count: " .. tostring(count_prof) .. "" - .. " '" .. tostring(bag_data[bag_slot].name) .. "'" - ) - end - end - - bag_data.total_slots = total_slots - bag_data.total_free = total_free - bag_data.total_used = total_used - - local bagText = "" - if (TitanGetVar(TITAN_PLUGIN, "ShowUsedSlots")) then - bagText = format(L["TITAN_BAG_FORMAT"], total_used, total_slots); - else - bagText = format(L["TITAN_BAG_FORMAT"], total_free, total_slots); - end - - local bagRichText = "" - if (TitanGetVar(TITAN_PLUGIN, "ShowColoredText")) then - local color = "" - color = TitanUtils_GetThresholdColor(TITAN_BAG_THRESHOLD_TABLE, total_used / total_slots); - bagRichText = TitanUtils_GetColoredText(bagText, color); - else - bagRichText = TitanUtils_GetHighlightText(bagText); - end - - bagRichText = - bagRichText --..bagRichTextProf[1]..bagRichTextProf[2]..bagRichTextProf[3]..bagRichTextProf[4]..bagRichTextProf[5]; - - return L["TITAN_BAG_BUTTON_LABEL"], bagRichText -end - --- Create the right click menu for this plugin -local function CreateMenu() - if trace then - TitanPluginDebug(TITAN_PLUGIN, "TS event" - .. " " .. tostring(TitanPanelRightClickMenu_GetDropdownLevel()) .. "" - .. " '" .. tostring(TitanPanelRightClickMenu_GetDropdMenuValue()) .. "'" - ) - end - local info = {} - -- level 2 - if TitanPanelRightClickMenu_GetDropdownLevel() == 2 then - if TitanPanelRightClickMenu_GetDropdMenuValue() == "Options" then - TitanPanelRightClickMenu_AddTitle(L["TITAN_PANEL_OPTIONS"], TitanPanelRightClickMenu_GetDropdownLevel()) - info = {}; - info.text = L["TITAN_BAG_MENU_SHOW_USED_SLOTS"]; - info.func = function() - TitanSetVar(TITAN_PLUGIN, "ShowUsedSlots", 1); - TitanPanelButton_UpdateButton(TITAN_PLUGIN); - end - info.checked = TitanGetVar(TITAN_PLUGIN, "ShowUsedSlots"); - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - - info = {}; - info.text = L["TITAN_BAG_MENU_SHOW_AVAILABLE_SLOTS"]; - info.func = function() - TitanSetVar(TITAN_PLUGIN, "ShowUsedSlots", nil); - TitanPanelButton_UpdateButton(TITAN_PLUGIN); - end - info.checked = TitanUtils_Toggle(TitanGetVar(TITAN_PLUGIN, "ShowUsedSlots")); - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - - info = {}; - info.text = L["TITAN_BAG_MENU_SHOW_DETAILED"]; - info.func = function() - TitanToggleVar(TITAN_PLUGIN, "ShowDetailedInfo"); - end - info.checked = TitanGetVar(TITAN_PLUGIN, "ShowDetailedInfo"); - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - - info = {}; - info.text = L["TITAN_BAG_MENU_OPEN_BAGS"] - info.func = function() - TitanToggleVar(TITAN_PLUGIN, "OpenBags") - end - info.checked = TitanGetVar(TITAN_PLUGIN, "OpenBags"); - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - end - return - end - - -- level 1 - TitanPanelRightClickMenu_AddTitle(TitanPlugins[TITAN_PLUGIN].menuText); - - info = {}; - info.notCheckable = true - info.text = L["TITAN_PANEL_OPTIONS"]; - info.value = "Options" - info.hasArrow = 1; - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - - TitanPanelRightClickMenu_AddSpacer(); - info = {}; - info.text = L["TITAN_BAG_MENU_IGNORE_PROF_BAGS_SLOTS"]; - info.func = function() - TitanToggleVar(TITAN_PLUGIN, "CountProfBagSlots"); - TitanPanelButton_UpdateButton(TITAN_PLUGIN); - end - info.checked = not TitanGetVar(TITAN_PLUGIN, "CountProfBagSlots") - TitanPanelRightClickMenu_AddButton(info, TitanPanelRightClickMenu_GetDropdownLevel()); - - TitanPanelRightClickMenu_AddControlVars(TITAN_PLUGIN) -end - --- Grab the button text to display -local function GetButtonText(id) - local strA, strB = GetBagData(id) - return strA, strB -end - --- Create the tooltip string -local function GetTooltipText() - local returnstring = ""; - - if trace then - TitanPluginDebug(TITAN_PLUGIN, "TS tool tip" - .. " detail " .. tostring(TitanGetVar(TITAN_PLUGIN, "ShowDetailedInfo")) .. "" - .. " used " .. tostring(TitanGetVar(TITAN_PLUGIN, "ShowUsedSlots")) .. "" - .. " prof " .. tostring(TitanGetVar(TITAN_PLUGIN, "CountProfBagSlots")) .. "" - .. " color " .. tostring(TitanGetVar(TITAN_PLUGIN, "ShowColoredText")) .. "" - .. " open " .. tostring(TitanGetVar(TITAN_PLUGIN, "OpenBags")) .. "" - ) - end - - if TitanGetVar(TITAN_PLUGIN, "ShowDetailedInfo") then - returnstring = "\n"; - if TitanGetVar(TITAN_PLUGIN, "ShowUsedSlots") then - returnstring = returnstring .. TitanUtils_GetNormalText(L["TITAN_BAG_MENU_TEXT"]) - .. ":\t" .. TitanUtils_GetNormalText(L["TITAN_BAG_USED_SLOTS"]) .. ":\n"; - else - returnstring = returnstring .. TitanUtils_GetNormalText(L["TITAN_BAG_MENU_TEXT"]) - .. ":\t" .. TitanUtils_GetNormalText(L["TITAN_BAG_FREE_SLOTS"]) .. ":\n"; - end - - for bag = MIN_BAGS, MAX_BAGS do - local bagText, bagRichText, color; - - if bag_data[bag] and bag_data[bag].has_bag then - if (TitanGetVar(TITAN_PLUGIN, "ShowUsedSlots")) then - bagText = format(L["TITAN_BAG_FORMAT"], bag_data[bag].used_slots, bag_data[bag].maxi_slots); - else - bagText = format(L["TITAN_BAG_FORMAT"], bag_data[bag].free_slots, bag_data[bag].maxi_slots); - end - - if bag_data[bag].style == "profession" - and not TitanGetVar(TITAN_PLUGIN, "CountProfBagSlots") - then - bagRichText = "|cffa0a0a0" .. bagText .. "|r" -- show as gray - elseif (TitanGetVar(TITAN_PLUGIN, "ShowColoredText")) then - if bag_data[bag].maxi_slots == 0 then - color = TitanUtils_GetThresholdColor(TITAN_BAG_THRESHOLD_TABLE, 1); - else - color = TitanUtils_GetThresholdColor(TITAN_BAG_THRESHOLD_TABLE, - bag_data[bag].used_slots / bag_data[bag].maxi_slots); - end - bagRichText = TitanUtils_GetColoredText(bagText, color); - else - -- use without color - bagRichText = TitanUtils_GetHighlightText(bagText); - end - - local name_text = bag_data[bag].name - if bag_data[bag].style == "profession" - then - name_text = TitanUtils_GetColoredText(name_text, bag_data[bag].color) - else - -- use without color - end - returnstring = returnstring .. name_text .. "\t" .. bagRichText .. "\n"; - else - returnstring = returnstring .. NONE .. "\n"; - end - end - returnstring = returnstring .. "\n"; - end - - if TitanGetVar(TITAN_PLUGIN, "ShowUsedSlots") then - local xofy = "" .. tostring(bag_data.total_used) - .. "/" .. tostring(bag_data.total_slots) .. "\n" - returnstring = returnstring .. TitanUtils_GetNormalText(L["TITAN_BAG_USED_SLOTS"]) - .. ":\t" .. xofy - else - local xofy = "" .. tostring(bag_data.total_free) - .. "/" .. tostring(bag_data.total_slots) .. "\n" - returnstring = returnstring .. TitanUtils_GetNormalText(L["TITAN_BAG_USED_SLOTS"]) - .. ":\t" .. xofy - end - - -- Add Hint - if TitanGetVar(TITAN_PLUGIN, "OpenBags") then - returnstring = returnstring .. TitanUtils_GetGreenText(L["TITAN_BAG_TOOLTIP_HINTS"]) - else - -- nop - end - return returnstring -end - --- Create the .registry for Titan so it can register and place the plugin -local function OnLoad(self) - local notes = "" - .. "Adds bag and free slot information to Titan Panel.\n" - -- .."- xxx.\n" - self.registry = { - id = TITAN_PLUGIN, - category = "Information", - version = VERSION, - menuText = L["TITAN_BAG_MENU_TEXT"], - menuTextFunction = CreateMenu, - buttonTextFunction = GetButtonText, - tooltipTitle = L["TITAN_BAG_TOOLTIP"], - tooltipTextFunction = GetTooltipText, - icon = artwork_path .. "TitanStarter", - iconWidth = 16, - notes = notes, - controlVariables = { - ShowIcon = true, - ShowLabelText = true, - ShowColoredText = true, - DisplayOnRightSide = true, - }, - savedVariables = { - ShowUsedSlots = 1, - ShowDetailedInfo = false, - CountProfBagSlots = false, - ShowIcon = 1, - ShowLabelText = 1, - ShowColoredText = 1, - DisplayOnRightSide = false, - OpenBags = false, - OpenBagsClassic = "new_install", - } - }; - - self:RegisterEvent("PLAYER_ENTERING_WORLD"); - - if trace then - TitanPluginDebug(TITAN_PLUGIN, "TS OnLoad" - .. " complete" - ) - end -end - --- Parse and react to registered events -local function OnEvent(self, event, a1, a2, ...) - if trace then - TitanPluginDebug(TITAN_PLUGIN, "TS event" - .. " " .. tostring(event) .. "" - .. " " .. tostring(a1) .. "" - ) - end - - if event == "PLAYER_ENTERING_WORLD" then - end - - if event == "BAG_UPDATE" then - -- update the plugin text - TitanPanelButton_UpdateButton(TITAN_PLUGIN); - end -end - --- Handle mouse clicks; here L click opens all bags -local function OnClick(self, button) - if trace then - TitanPluginDebug(TITAN_PLUGIN, "TS click" - .. " " .. tostring(button) .. "" - ) - end - - if (button == "LeftButton") then - ToggleBags(); - end -end - -local function OnShow(self) - if trace then - TitanPluginDebug(TITAN_PLUGIN, "TS OnShow" - .. " register" - ) - end - -- Register for bag updates and update the plugin text - self:RegisterEvent("BAG_UPDATE") - TitanPanelButton_UpdateButton(TITAN_PLUGIN); -end - -local function OnHide(self) - if trace then - TitanPluginDebug(TITAN_PLUGIN, "TS OnShow" - .. " unregister" - ) - end - self:UnregisterEvent("BAG_UPDATE") -end - --- ====== Create needed frames -local function Create_Frames() - if _G[TITAN_BUTTON] then - return -- if already created - end - - if trace then - TitanPluginDebug(TITAN_PLUGIN, "TS frames" - .. " '" .. tostring(TITAN_BUTTON) .. "'" - ) - end - - -- general container frame - local f = CreateFrame("Frame", nil, UIParent) - -- f:Hide() - - -- Titan plugin button - --[[ - The plugin frame is created here. The typical plugin is a 'combo' which includes - - an icon (can be shown or hidden) - - label - value pair where the label can be turned off - There can be multiple label - value pairs; TitanPerformance uses this scheme. - - The frame is 'forever' as are most of WoW game frames. - --]] - local window = CreateFrame("Button", TITAN_BUTTON, f, "TitanPanelComboTemplate") - window:SetFrameStrata("FULLSCREEN") - -- Using SetScript to set "OnLoad" does not work - -- - -- This routine sets the guts of the plugin - the .registry - OnLoad(window); - - --[[ - Below are the frame 'events' that need to be processed. - A couple have Titan routines that ensure the plugin is properly on / off a Titan bar. - - The combined Titan changed design to register for events when the user places the plugin - on the bar (OnShow) and unregister events when the user hids the plugin (OnHide). - This reduces cycles the plugin uses when the user does not want the plugin. - - NOTE: If a Titan bar is hidden, the plugins on it will still run. - NOTE: Titan plugins are NOT child frames!! Meaning plugins are not automatically hidden when the - bar they are on is hidden! - --]] - window:SetScript("OnShow", function(self) - OnShow(self) - -- This routine ensures the plugin is put where the user requested it. - -- Titan saves the bar the plugin was on. It does not save the relative order. - TitanPanelButton_OnShow(self); - end) - window:SetScript("OnHide", function(self) - OnHide(self) - -- We use the Blizzard frame hide to visually remove the frame - end) - window:SetScript("OnEvent", function(self, event, ...) - -- Handle any events the plugin is interested in - OnEvent(self, event, ...) - end) - window:SetScript("OnClick", function(self, button) - -- Typically this routine handles actions on left click - OnClick(self, button); - -- Typically this routine handles the menu creation on right click - TitanPanelButton_OnClick(self, button); - end) -end - -Create_Frames() -- do the work