--[[ -- ************************************************************************** -- * TitanStarter.lua -- * -- * By: The Titan Panel Development Team -- ************************************************************************** --]] --[[ Example This is an example Titan (Titen Panel) plugin based on Titan Bag. It is intended to introduce Titan plugin essentials by using a basic addon with a lot of comments. This can be run as is then changed to implement your great idea! NOTE: The terms addon and plugin are essentially the same. Here plugin is used when the addon is displayed by Titan. --]] --[[ Folder Structure NOTE: Before running this addon, the folder and file prefix must be the same to be considered for loading into WoW! For example to just run this as is, remove the 'Example' from the folder name then start or reload WoW. This is explained in more detail below. This plugin folder must be added to the Addon folder to be considered for loading into WoW. Inside this folder you will notice : - three .toc files - one .lua file - one .tga file. There are sites (wowhead or wow wiki as examples) that have deeper explainations on addon development. Please use these sites for more general addon information. === .toc The folder and the .toc files MUST have the same name! Sort of... the name prior to the underscore(_) must be the same. The name after that (postfix) has meaning to WoW. WoW has three versions represented by the three postix values. _Mainline : current retail version _Wrath : Wrath of the Lich King version. _Vanilla : Classic Era version These values may change as the versions evolve, say Cata is added to Wrath. Or they may not :). Years from now we may wonder why Wrath represents Dragonflight! If your plugin is only for Classic Era then delete or rename the 'mainline' and 'wrath' .toc files. Changing the filename will prevent WoW from loading the addon into that version of the game. Titan uses this method. Notice Titan folder has no 'wrath' or 'vanilla' .toc. TitanClassic has has both 'wrath' and 'vanilla' .toc but no 'mainline' .toc. This allows Titan plugins intended for Classic versions to run without change. NOTE: The ## Interface value should match the current interface value of the coorsponding WoW version. In BattleNet this typcially shown below the 'Play' button. DragonFlight 10.02.05 is represented without dots - 100205 - in the .toc. If the interface value is close (but lower) WoW will complain that you are running 'older' addons. If WoW finds a Classic Era value (say 11500) in a 'mainline' .toc, it will just ignore it (not load). The reverse (a higher value) is true as well. === .lua This is the code for the plugin - and this file. === .tga This file is the icon used by the plugin. It is specified in the .registry used by Titan. WoW can use several different types of icons. This discussion is outside the scope of this example. Anyone can extract the code and art from WoW. This can be handy to get code examples. And to grab icons to use for a plugin. My undestanding 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. --]] --[[ Editting This example may seem daunting at first. We decided to leave Bag as is to give plenty of coding examples. GetBagData will be replaced by your code. It uses IsProfessionBagID. ToggleBags is called from OnClick. This will be replaced by your code. TitanPanelRightClickMenu_PrepareStarterMenu will need its name changed. The other routines will be modified to impement your idea. --]] --[[ Code flow NOTE: The .toc states Titan is required [## Dependencies: Titan]. WoW insures Titan is loaded BEFORE this addon. First step: ==== Starting WoW Wow will 'load' this addon. Any code outside the Lua functions will be run. - 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 - TITAN_BUTTON - and call local OnLoad. Create_Frames also sets the event scripts for the addon. This is how WoW and Titan interact with this addon. NOTE: The frame is created using a Titan template. This template handles some frame processing. OnLoad does two important things 1) Sets the .registry of the addon - See the .registry comment block 2) Registers for PLAYER_ENTERING_WORLD NOTE: OnLoad should be small and not assume data is ready yet. 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 OnEvent. When processing PLAYER_ENTERING_WORLD only register for events and access local data. Titan also receives the PLAYER_ENTERING_WORLD event. There is NO guarantee this plugin receives the event before or after Titan! Titan then processes its own data and saved variables. Titan will process and set any saved variables specified in the .registry of this plugin! Then Titan starts registering plugins using each addon .registry. It also loads any LDB plugins found. Next: ==== Still waiting for WoW Titan shows the user requested bars with plugins. OnShow is called by Titan when placing this plugin on a bar or the user requests the plugin to be shown. Technically Titan calls the now registered frame - TITAN_BUTTON - :Show then WoW calls the frame script :OnShow eventually calling OnShow in this addon set by Create_Frames. NOTE: Do not assume any saved variables in .registry are ready until OnShow! OnShow now does all processing to set up this plugin properly. Once done it calls TitanPanelButton_UpdateButton. Now the plugin is ready for the user. Next: ==== Ready to play WoW The plugin is now 'idle' until : - Titan calls TitanPanelButton_UpdateButton(TITAN_PLUGIN) to (re)display this plugin - Any registered event is received - A timer or callback calls the routine - via Titan or this plugin code TitanPanelButton_UpdateButton(TITAN_PLUGIN) called when: - User does a reload or user action - via Titan - User changes a plugin option using Titan menu - User changes a plugin option using Titan configuration - A Titan timer expires such as auto hide bar is active or pet battle or ... Events occur when: - User clicks on this plugin to take an action or show menu - OnClick - User mouses over this plugin to display tool tip - OnEnter - Any registered event is received - OnEvent - Your timer expires - be very careful here! :) - Your callback happens such as waiting for WoW server info OnClick is the TITAN_BUTTON frame script. Left click is procssed by this plugin. Right click is handled by the Titan template to invoke plugin menu (TitanPanelRightClickMenu_PrepareStarterMenu) OnEnter and OnLeave are the TITAN_BUTTON frame scripts. OnEnter is handled by the Titan template to show the tool tip (.registry.tooltipTextFunction). OnLeave is handled by the Titan template to hide the tool tip. Next: ==== The above step continues until: - User hides the plugin - The user logs out the character or exits WoW Either action causes OnHide to be called. OnHide should : - Do any cleanup - Stop any timers - Unregister any events These steps keep processing to a minimum and reduces the chance of errors to the user. NOTE: Any saved variables - in .registry or specific to this plugin - are saved by WoW on logout or exit. No specific actions are required. --]] --[[ Structure The plugin starts with local constants used throughout. Then local variables; then functions. The design uses local functions sa much as practical. Mainly for clarity and a small speed increase. Titan specific details will be noted and explained. The comments will specify where names are important. Any local routine or variable with 'bag' in the name can be changed to your design or deleted. Suggested path is start with Create_Frames at the bottom of the file. It is where the magic starts. Note: Feel free to look at Titan code. Pay attention to the comments. Any routine labeled as API can be used by a plugin. 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). Of course feel free to reach out on our Discord site with any questions or suggestions! --]] --[[ .registry This is the GUTS of a Titan plugin. The .registry on the frame contains all the info to register / create a plugin. Every registry with an id should appear in Titan > Configuration > Attempts. Info is shown there along with pass / fail. If the plugin failed to register, the error is shown there. NOTE: Titan expects 3 routines to be in the global namespace: - Routine that updates the plugin : .buttonTextFunction - Routine that creates the tool tip : .tooltipTextFunction - Routine that creates the options : .menuTextFunction OR "TitanPanelRightClickMenu_Prepare"<id>"Menu" Attributes: .id : Required : must be unique across plugins. If there are duplicates, the first one 'wins'. .category : The list is in TITAN_PANEL_BUTTONS_PLUGIN_CATEGORY (TitanGlobal.lua) "Built-ins" is reserved for plugins that Titan releases. .version : plugin version sown in menus and config. .menuText : Used by as the title for the right click menu. .menuTextFunction : This is called for the right click menu. NOTE : This is the newer, prefered method which makes the options menu routine explicit. OLD METHOD: Still supported! Titan builds the function name as "TitanPanelRightClickMenu_Prepare"<id>"Menu" TitanPanelRightClickMenu_PrepareStarterMenu in this example. .buttonTextFunction : This is called whenever the button is to be updated - TitanPanelButton_UpdateButton(TITAN_PLUGIN) This is called from within the the plugin and from Titan core. The specified routine is expected to be global. It is called securely (pcall) so a plugin will not crash Titan (hopefully). Titan will usually show "<?>" if the routine dies. If this occurs and you need to see the error, search for this attribute in Titan folder and uncomment the print of the error message. .tooltipTitle : Used as the title for the tool tip .tooltipTextFunction : This is called when OnEnter of the plugin frame is triggered. It is expected to be global. It is called securely (pcall) so a plugin will not crash Titan (hopefully). Titan will usually show part of the error in the tool tip if the routine dies. .icon : Allowed path to the icon to be used. It is recommended to store the icon in the plugin folder, even if copied from WoW folder. .iconWidth : Best left at 16... .notes : This is shown in Titan > Config > Plugins when this plugin is selected. .controlVariables : This list is used by TitanPanelRightClickMenu_AddControlVars(TITAN_PLUGIN) true : Will be included in the menu false : Will not be included in the menu .savedVariables : These are the variables stored in Titan saved variables. The initial values are used only if that particular is 'new' to that character (new Titan install, new character). If a value is removed then it is removed from the saved variables as Titan is run for each character. --]] -- ******************************** Constants ******************************* local add_on = ... local _G = getfenv(0); local artwork_path = "Interface\\AddOns\\TitanPlugin\\" -- NOTE: This is the plugin id which should 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 = 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 }, } local updateTable = {TITAN_PLUGIN, TITAN_PANEL_UPDATE_BUTTON}; -- ******************************** Variables ******************************* local AceTimer = LibStub("AceTimer-3.0") local L = LibStub("AceLocale-3.0"):GetLocale(TITAN_ID, true) local BagTimer 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 ******************************* 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 = "" 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 = GetItemInfoInstant(info) style = subclassID --[[ TitanDebug("T isP 0:" .." "..tostring(slot).."" .." "..tostring(itemId).."" .." '"..tostring(itemType).."'" .." '"..tostring(itemSubType).."'" .." "..tostring(itemEquipLoc).."" .." '"..tostring(itemTexture).."'" .." "..tostring(classID).."" .." "..tostring(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 TitanDebug("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...) if bag_name == UNKNOWN then -- name not available yet else end -- 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 trace then TitanDebug("T Bag...:" .." "..tostring(bag_slot).."" .." "..tostring(is_prof_bag).."" .." '"..tostring(style).."'" .." "..tostring(itemClassID).."" .." "..tostring(itemSubClassID).."" ) end --]] 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 TitanDebug("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 local function CreateMenu() if trace then TitanDebug("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 local function GetButtonText(id) local strA, strB = GetBagData(id) return strA, strB end local function GetTooltipText() local totalSlots, usedSlots, availableSlots; local returnstring = ""; if trace then TitanDebug("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; --[[ TitanDebug("T Bag: TT" .." "..tostring(bag).."" .." "..tostring(bag_data[bag].has_bag).."" .." "..tostring(bag_data[bag].name).."" .." "..tostring(bag_data[bag].maxi_slots).."" .." "..tostring(bag_data[bag].used_slots).."" .." "..tostring(bag_data[bag].free_slots).."" ) --]] 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 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", } }; if TITAN_ID == "Titan" then -- 10.* / Retail -- for taint issue self.registry.savedVariables.OpenBags = false else -- does not taint so default to open bags on click self.registry.savedVariables.OpenBags = true end self:RegisterEvent("PLAYER_ENTERING_WORLD"); if trace then TitanDebug("TS OnLoad" .." complete" ) end end local function OnEvent(self, event, a1, a2, ...) if trace then TitanDebug("TS event" .." "..tostring(event).."" .." "..tostring(a1).."" ) end if event == "PLAYER_ENTERING_WORLD" then if a1 == true and TITAN_ID == "Titan" then -- 10.* / Retail -- initial login TitanPrint(L["TITAN_BAG_TAINT_TEXT"], "warning") else -- either Classic version local open = TitanGetVar(TITAN_PLUGIN, "OpenBagsClassic") if open == "new_install" then -- -- set to default behavior of opening bag on left click TitanSetVar(TITAN_PLUGIN, "OpenBags", true) TitanSetVar(TITAN_PLUGIN, "OpenBagsClassic", "processed") -- don't do again else -- already processed... end end end if event == "BAG_UPDATE" then -- update the plugin text TitanPanelButton_UpdateButton(TITAN_PLUGIN); end end local function OnClick(self, button) if trace then TitanDebug("TS click" .." "..tostring(button).."" ) end if (button == "LeftButton") then ToggleBags(); end end local function OnShow(self) if trace then TitanDebug("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 TitanDebug("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 TitanDebug("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 visible 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 -- ====== 3 routines required to be in the global namespace -- ======