Quantcast

- Examples : Update PluginDoc; Example plugin; Example LDB

urnati [02-06-24 - 20:45]
- Examples : Update PluginDoc; Example plugin; Example LDB
- Titan : Add additional .registry (optional) to routine for right click menu explicit - used in example plugin
Filename
Titan/TitanPluginDoc.lua
Titan/TitanTemplate.lua
Titan/TitanUtils.lua
TitanExampleLDB/StarterLDB.lua
TitanExamplePlugin/TitanStarter.lua
diff --git a/Titan/TitanPluginDoc.lua b/Titan/TitanPluginDoc.lua
index 2471c3e..606d6a5 100644
--- a/Titan/TitanPluginDoc.lua
+++ b/Titan/TitanPluginDoc.lua
@@ -5,13 +5,13 @@ DESC: This file contains documentation of Titan to assist a developer.
 --]]
 --[[ API
 NAME: Titan API overview for developers
-DESC: Updated Dec 2011
+DESC: Updated Feb 2024

 This documentation is intended for addon developers that wish to create a Titan plugin.

 Terms:
 Throughout the documentation and naming of routines and variables there are some terms that are used interchangably.
-- Plugin / button / frame
+- Plugin / button which are frames using TitanTemplates.xml
 - Character / player / toon
 - Plugin ID / plugin name
 Over time we desire to consolidate terms but it may take time.
@@ -20,25 +20,31 @@ Plugin Types:
 Titan allows two types of plugins:
 - Titan native
 - LDB enabled addons
-See http://code.google.com/p/titanpanel/downloads/list to download examples.
+Titan release has an example of each : TitanExamplePlugin and TitanExampleLDB.

-Titan Plugin Recognition:
+Titan Plugin Creation:
 Titan native plugins must use one of the Titan templates found in TitanPanelTemplates.xml.
+On the creation of a Titan plugin frame the Onload places the plugin in a holding table until the "Player Entering World" (PEW) event is fired.

-LDB Plugin Recognition:
+LDB Plugin Creation:
 LDB enabled addons only need to adhere to the LDB (Lib Data Broker) 1.1 spec.
-Titan uses the callback feature ("LibDataBroker_DataObjectCreated") to recognize LDB addons.
+Titan uses the callback feature ("LibDataBroker_DataObjectCreated") to recognize LDB addons.
+Titan creates a Titan plugin using the LDB plugin data.
 At player_login Titan registers the call back.
 It then loops through the LDB objects using :DataObjectIterator().
 When any LDB object is found Titan will attempt to create a Titan native plugin for display.

 Registration Steps:
-Titan attempts to register each plugin it recognizes. Registration for Titan is a two step process.
-Step one: On the creation of a Titan plugin frame place the plugin in a holding table until the "Player Entering World" (PEW) event is fired.
-Step two: Once Titan is initialized it will take each plugin from this table and attempt to register it for display. The attempt uses a protected call (pcall) to protect the Titan core and (hopefully) prevents Titan from crashing.
+On PLAYER_LOGIN event, Titan loops through the holding LDB plugins creating Titan plugins. It will sync the saved variables.
+On PLAYER_ENTERING_WORLD (PEW) event, Titan loops through the holding table registering plugins. It will sync the saved variables.
+Titan attempts to register each plugin ensuring:
+- Each attempt is protected (pcall) so Titan does not crash (hopefully!)
+- The .registry has required values and is reasonable.
+- Sync of control and saved variables.
+- All attempts are recorded. These can be seen in Titan Config > Attempts

 Registration Attempts:
-Each plugin attempt is placed in an 'attempted' table along with the results of the registration. This attempted table is accessible to the user in the Titan "Attempted" options. The developer can see what happened and users can report issues using that data.
+Each attempt can be seen in Titan Config > Attempts with the results of the registration. The developer can see what happened and users can report issues using that data.

 Registry Table of Each Plugin:
 Each plugin must contain a table called "registry".
@@ -47,9 +53,9 @@ Each plugin must contain a table called "registry".
 The registry table must have a unique id across all Titan plugins that are loaded.
    self.registry = {id = "MyPlugin"}
 This is all that is required for successful registration. It will register but will be a rather dull plugin.
-It is strongly recommended that you download the TitanStarter plugin example(see the link above). The example explains all the elements of the registry that Titan uses. The example is based on TitanBags so you can play with the code and compare it to a supported plugin.
+It is strongly recommended that you utilize the Titan plugin example. The example is based on TitanBags so you can play with the code and compare it to a supported plugin.

 Titan API:
-The functions that Titan offers to the plugin developer are in a separate document. Within the Titan files you can recognize an API routine by the comment just before the function declaration. The comment block will have "API" as part of the starting block.
+Within the Titan files you can recognize an API routine by the comment just before the function declaration. The comment block will have "API" as part of the starting block.
 :DESC
 --]]
\ No newline at end of file
diff --git a/Titan/TitanTemplate.lua b/Titan/TitanTemplate.lua
index 875f604..0ef8258 100644
--- a/Titan/TitanTemplate.lua
+++ b/Titan/TitanTemplate.lua
@@ -264,7 +264,20 @@ local function TitanPanelButton_SetTooltip(self, id)
 			self.tooltipCustomFunction = plugin.tooltipCustomFunction;
 			TitanTooltip_SetPanelTooltip(self, id);
 		elseif ( plugin.tooltipTitle ) then
-			local tooltipTextFunc = _G[plugin.tooltipTextFunction];
+--			local tooltipTextFunc = _G[plugin.tooltipTextFunction];
+			local tooltipTextFunc = {}
+			local tt_func = plugin.tooltipTextFunction
+
+			if type(tt_func) == 'string' then
+				-- Function MUST be in global namespace
+				tooltipTextFunc = _G[tt_func]
+			elseif type(tt_func) == 'function' then
+				-- Can be global or local to the plugin
+				tooltipTextFunc = tt_func
+			else
+				return -- silently leave...
+			end
+
 			if ( tooltipTextFunc ) then

 				if ok then  -- display the tooltip
@@ -614,23 +627,6 @@ function TitanPanelDetectPluginMethod(id, isChildButton)
 			TitanPanelButton_OnDragStop(self);
 		end
 	end)
---[[
-	-- Set the key down script - for modifiers
-	TitanPluginframe:SetScript("OnKeyDown", function(self)
-		if IsModifierKeyDown() then
-			TitanPanelButton_SetTooltip(self, id)
-		end
-	end)
-
-	-- Set the key up script - for modifiers
-	TitanPluginframe:SetScript("OnKeyUp", function(self)
-		if IsModifierKeyDown() then
-			-- ? do nothing
-		else
-			GameTooltip:Hide()
-		end
-	end)
---]]
 end

 --[[ API
@@ -823,13 +819,43 @@ NOTE:
 :NOTE
 --]]
 local format_with_label = { [0] = "" }
-for idx = 1, 4 do format_with_label[idx] = "%s%s" .. (TITAN_PANEL_LABEL_SEPARATOR .. "%s%s"):rep(idx - 1) end
+for idx = 1, 4 do
+	format_with_label[idx] = "%s%s"..(TITAN_PANEL_LABEL_SEPARATOR.."%s%s"):rep(idx - 1)
+end
 local function TitanPanelButton_SetButtonText(id)
-	if not (id and TitanUtils_IsPluginRegistered(id)) then return end
+	if (id and TitanUtils_IsPluginRegistered(id)) then
+		-- seems valid, registered plugin
+	else
+		-- return silently; The plugin is not registered!
+		-- output here could be a lot and really annoy the user...
+		return
+	end
+
+	local pdata = TitanUtils_GetPlugin(id) -- get plugin data

-	local buttonTextFunction = _G[TitanUtils_GetPlugin(id).buttonTextFunction];
+	local bFunction = pdata.buttonTextFunction
+	local buttonTextFunction = {}
+	if type(bFunction) == 'string' then
+		-- Function MUST be in global namespace
+		buttonTextFunction = _G[bFunction]
+	elseif type(bFunction) == 'function' then
+		-- Can be global or local to the plugin
+		buttonTextFunction = bFunction
+	else
+		return -- silently leave...
+	end
+--[[
+print("B text"
+.." "..tostring(id)..""
+.." "..tostring(type(bFunction))..""
+.." '"..tostring(bFunction).."'"
+.." '"..tostring(buttonTextFunction).."'"
+)
+--]]
+
+--	buttonTextFunction = bFunction
 	if not buttonTextFunction then return end
-	local button = TitanUtils_GetButton(id);
+	local button = TitanUtils_GetButton(id)  -- get plugin frame
 	local buttonText = _G[button:GetName()..TITAN_PANEL_TEXT];

 	local newfont = media:Fetch("font", TitanPanelGetVar("FontName"))
diff --git a/Titan/TitanUtils.lua b/Titan/TitanUtils.lua
index de26799..a4207a8 100644
--- a/Titan/TitanUtils.lua
+++ b/Titan/TitanUtils.lua
@@ -269,8 +269,8 @@ end
 -- Plugin button search & manipulation routines
 --
 --[[ API
-NAME: TitanUtils_GetButton
-DESC: Create thebutton name from plugin id.
+NAME: TitanUtils_ButtonName
+DESC: Create the button name from plugin id.
 VAR: id - is the id of the plugin
 OUT: string - The button / frame name
 --]]
@@ -391,6 +391,9 @@ function TitanUtils_GetButtonIDFromMenu(self)
 				,"error")
 			end
 		end
+	else
+		TitanDebug("Could not determine Titan ID from menu. "
+		,"error")
 	end

 	return ret
@@ -1552,7 +1555,7 @@ function TitanUtils_StopFrameCounting(frame)
 	frame.isCounting = nil;
 end

---[[ Titan Plugins AND Titan
+--[[ Titan Plugins AND Bars
 NAME: TitanUtils_CloseAllControlFrames
 DESC: Remove all timer flags on plugin control frames. Used for plugin Shift+Left and within Titan
 VAR:  None
@@ -1690,14 +1693,6 @@ function TitanUtils_PluginToRegister(self, isChildButton)
 		notes = notes,
 	}

-	--[[ For updated menu lib (Dec 2018)
-	Old way was to use the XML file to declare the frame, now it needs to be in Lua
-	--]]
-	local f = CreateFrame("Frame",
-		self:GetName()..TITAN_PANEL_CLICK_MENU_SUFFIX,
-		self or nil,
-		"UIDropDownMenuTemplate")
-
 	-- Debug
 	if Titan_Panel.debug.plugin_register then
 		TitanDebug("Queue Plugin"
@@ -1880,6 +1875,11 @@ local function TitanUtils_RegisterPluginProtected(plugin)
 						-- Override the type with the LDB type
 						ptype = "LDB: '"..self.registry.ldb.."'"
 					end
+					-- === Right click menu
+					local f = CreateFrame("Frame",
+						self:GetName()..TITAN_PANEL_CLICK_MENU_SUFFIX,
+						self or nil,
+						"UIDropDownMenuTemplate")
 				end
 				notes = (self.registry.notes or "")

@@ -2044,7 +2044,7 @@ function TitanUtils_IsPluginRegistered(id)
 end

 --------------------------------------------------------------
--- Right click menu routines for Titan Panel bars
+-- Right click menu routines for Titan Panel bars and plugins

 --[[ Titan
 NAME: TitanUtils_CloseRightClickMenu
@@ -2097,61 +2097,81 @@ end

 --[[ local
 NAME: TitanRightClickMenu_OnLoad
-DESC: Prepare the plugin right click menu using the function given by the plugin =or Titan bar.
+DESC: Prepare the plugin right click menu using the function given by the plugin or Titan bar.
 VAR:
-- plugin - frame of the plugin (must be a Titan template)
+- self - menu frame of the plugin as created when the plugin was successfully registered.
 OUT:  None
 NOTE:
-- The function to be called is assumed to be "TitanPanelRightClickMenu_Prepare"..plugin_id.."Menu".
 - This routine handles Titan plugins and the Titan bars.
+- UIDropDownMenu_Initialize appears to be 'safe'. Any error is returned rather than propagated.
+- The function to create the menu is either
+1. set in registry in .menuTextFunction
+: New in 2024 Feb to make the routine explicit
+: If a function then the routine can be local or in the global namespace
+: If a string then the routine MUST be in the global namespace.
+2. assumed to be "TitanPanelRightClickMenu_Prepare"..plugin_id.."Menu" : This is the way Titan was written
 - TitanUtils_GetButtonIDFromMenu returns a generic "Bar" when the user clicks on a Titan bar.
-  This works because every Titan bar uses the same menu; allows one routine to be reused.
+  This works because every Titan bar uses the same menu allowing one routine to be reused.
 --]]
 local function TitanRightClickMenu_OnLoad(self)
-	local id = TitanUtils_GetButtonIDFromMenu(self);
+	local id = TitanUtils_GetButtonIDFromMenu(self) -- "Bar" if self is any Titan bar
+	local err = ""
 	if id then
-		local prepareFunction = _G["TitanPanelRightClickMenu_Prepare"..id.."Menu"]
-		if prepareFunction and type(prepareFunction) == "function" then
-			UIDropDownMenu_Initialize(self, prepareFunction, "MENU");
+		local frame = TitanUtils_GetPlugin(id) -- get plugin frame
+--[[
+print("RC* _OnLoad"
+.." "..tostring(id)..""
+.." "..tostring(self:GetName())..""
+.." "..tostring(frame)..""
+--.." "..tostring(frame.menuTextFunction)..""
+)
+--]]
+		local prepareFunction = {} -- function to call
+
+		if frame and frame.menuTextFunction then
+			prepareFunction = frame.menuTextFunction -- Newer method 2024 Feb
+		else
+			-- If 'bar' then routine for ALL Titan bars
+			prepareFunction = "TitanPanelRightClickMenu_Prepare"..id.."Menu"
+		end
+
+		if type(prepareFunction) == 'string' then
+			-- Function MUST be in global namespace
+			-- Becomes nil if not found
+			prepareFunction = _G[prepareFunction]
+		elseif type(prepareFunction) == 'function' then
+			-- Can be global or local to the plugin
+		else
+			-- Invalid type, do not even try...
+			prepareFunction = nil
+		end
+
+		if prepareFunction then
+			UIDropDownMenu_Initialize(self, prepareFunction, "MENU")
+		else
+			err = "Could not display tooltip. "
+				.."No function for '"..tostring(id).."' "
+				.."["..tostring(type(prepareFunction)).."] "
+				.."["..tostring(prepareFunction).."] "
+				..". "
 		end
 	else
-		if Titan_Panel.debug.tool_tips then
-			TitanDebug("Could not display tooltip. "
-			.."Could not determine Titan ID for "
+		err = "Could not display tooltip. "
+			.."Unknown Titan ID for "
 			.."'"..(self:GetName() or "?").."'. "
-			,"error")
-		end
 	end

+	if Titan_Panel.debug.tool_tips then
+		if err == "" then
+			-- all is good
+		else
+			TitanDebug(err, "error")
+		end
+	end
 	-- Under the cover the menu is built as DropDownList1
 	return DropDownList1, DropDownList1:GetHeight(), DropDownList1:GetWidth()
 end

---[[ local Classic
-NAME: TitanDisplayRightClickMenu_OnLoad
-DESC: Prepare the Titan bar right click menu using the given function.
-VAR:
-- self - frame of the Titan bar
-- func - function to create the menu
-OUT:  None
-NOTE:
-- This routine is for Titan bar. There is a similar routine for the Titan plugins.
---]]
-local function TitanDisplayRightClickMenu_OnLoad(self, func)
-	local prepareFunction = _G[func];
-	if prepareFunction and type(prepareFunction) == "function" then
-		-- Nasty "hack", load Blizzard_Calendar if not loaded,
-		-- for it to secure init 24 dropdown menu buttons,
-		-- to avoid action blocked by tainting
---		if not IsAddOnLoaded("Blizzard_Calendar") then
---			LoadAddOn("Blizzard_Calendar")
---		end
-		-- not good practice but there seems to be no other way to get
-		-- the actual bar (frame parent) to the dropdown implementation
-		TitanPanel_DropMenu = self
-		L_UIDropDownMenu_Initialize(self, prepareFunction, "MENU");
-	end
-end
 --[[ Titan
 NAME: TitanPanelRightClickMenu_Toggle
 DESC: Call the routine to build the plugin menu then place it properly.
diff --git a/TitanExampleLDB/StarterLDB.lua b/TitanExampleLDB/StarterLDB.lua
index 800039b..5bb5e18 100644
--- a/TitanExampleLDB/StarterLDB.lua
+++ b/TitanExampleLDB/StarterLDB.lua
@@ -171,6 +171,11 @@ local function LDB_OnTooltipShow(tooltip)
 	tooltip = tooltip or GameTooltip
 	local tt_str = ""

+---[[
+print("LDB OTS"
+.." "..tostring(id)..""
+)
+--]]
 	tt_str =
 		GREEN_FONT_COLOR_CODE
 		..id.." Info"
diff --git a/TitanExamplePlugin/TitanStarter.lua b/TitanExamplePlugin/TitanStarter.lua
index e559856..8634f8b 100644
--- a/TitanExamplePlugin/TitanStarter.lua
+++ b/TitanExamplePlugin/TitanStarter.lua
@@ -5,23 +5,19 @@
 -- * 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!

-If running this example, it shows up in the Titan right click menu > Information > Starter
-
-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 in 'Folder Structure'.
-
 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.
@@ -84,7 +80,7 @@ The other routines will be modified to impement your idea.
 --]]

 --[[ Code flow
-NOTE: The .toc states Titan or TitanClassic is required [## Dependencies: Titan].
+NOTE: The .toc states Titan is required [## Dependencies: Titan].
 WoW insures Titan is loaded BEFORE this addon.

 First step: ==== Starting WoW
@@ -199,14 +195,21 @@ 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.
-	NOTE : Titan builds the function name rather than it being listed in the registery.
-	It is expected to be global and named "TitanPanelRightClickMenu_Prepare"<id>"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.
@@ -289,6 +292,7 @@ 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
@@ -489,7 +493,84 @@ end
 	return L["TITAN_BAG_BUTTON_LABEL"], bagRichText
 end

-function TitanPanelBagButton_GetTooltipText()
+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 = "";

@@ -592,10 +673,11 @@ local function OnLoad(self)
 		id = TITAN_PLUGIN,
 		category = "Information",
 		version = VERSION,
-		menuText = TITAN_PLUGIN,
-		buttonTextFunction = "TitanPanelBagButton_GetButtonText",
+		menuText = L["TITAN_BAG_MENU_TEXT"],
+		menuTextFunction = CreateMenu,
+		buttonTextFunction = GetButtonText,
 		tooltipTitle = L["TITAN_BAG_TOOLTIP"],
-		tooltipTextFunction = "TitanPanelBagButton_GetTooltipText",
+		tooltipTextFunction = GetTooltipText,
 		icon = artwork_path.."TitanStarter",
 		iconWidth = 16,
 		notes = notes,
@@ -677,83 +759,6 @@ local function OnClick(self, button)
 	end
 end

-function TitanPanelBagButton_GetButtonText(id)
-	local strA, strB = GetBagData(id)
-	return strA, strB
-end
-
-function TitanPanelRightClickMenu_PrepareStarterMenu()
-	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 OnShow(self)
 	if trace then
 		TitanDebug("TS OnShow"
@@ -841,3 +846,7 @@ local function Create_Frames()
 end

 Create_Frames() -- do the work
+
+-- ====== 3 routines required to be in the global namespace
+
+-- ======