Context Menu Maker

Create a drop down menu at your leisure and show it when you're ready. This is a very basic context menu, nothing advanced.

Usage
local menu = MenuClass:New menu:AddItem('Do Something', function   SendChatMessage("Hello Bob!", "WHISPER", "Common", "Bob") end) menu:AddItem('Close', function   -- do nothing, just close. end)

local f = SomeClickableFrame f:SetScript('OnClick', function(self, button)   menu:Show end)

Properties

 * .menuItems : Table. Stores the menu items.
 * .anchor : String. The anchor.
 * .x : The x offset
 * .y : The y offset
 * .displayMode : The display mode.
 * .autoHideDelay : The time it takes for the menu to automatically hide.
 * .menuFrame : The menu frame.
 * .uniqueID : A self incrementing number used to ensure that the generic menu frame is unique.
 * .isTitle : Is this menu item a header? 1 if yes, nil if no.

Methods

 * &#58;Activate : Creates the menu frame if it has not already been set with :SetMenuFrame.
 * &#58;AddItem( text, func, isTitle) : Add a menu item with text text that does func. Requires at least 1.
 * &#58;GetAttribute( text,  attribute) : Gets an attribute for the given menu item.
 * &#58;New : Allocate memory for the new menu and set the defaults. Required. Returns the menu.
 * &#58;RemoveItem( text) : Remove the first menu item that matches text
 * &#58;SetAnchor( anchor) : Set the anchor. Optional. Default: "cursor"
 * &#58;SetAttribute( text,  attribute,  value) : Sets an attribute for the given menu item.
 * &#58;SetDisplayMode( displayMode) : Set the displayMode. Optional. Default: "MENU"
 * &#58;SetAutoHideDelay( autoHideDelay) : Set the autoHideDelay. Optional. Default: nil (does not auto close)
 * &#58;SetMenuFrame( menuFrame) : Set the menuFrame. Optional. Default: self generating menuFrame. If set, this must be a frame that inherits UIDropDownMenuTemplate.
 * &#58;SetX( x[, save]) : Set the x offset. Optional. Default: nil (0 if anchor is not "cursor"). If save resolves to true, x will be added to rather than replaced.
 * &#58;SetY( y[, save]) : Set the y offset. Optional. Default: nil (0 if anchor is not "cursor"). If save resolves to true, y will be added to rather than replaced.
 * &#58;Show : Show the menu.

Code
-- Set to false to use file-scoped variables or true to use the new addon-scoped variables local useAddonScope = true local addonName, MenuClass

if useAddonScope then addonName, MenuClass = ... else addonName, MenuClass = "--your addon's name--", {} end

function MenuClass:New local ret = {} -- set the defaults ret.menuList = {} ret.anchor = 'cursor'; -- default at the cursor ret.x = nil; ret.y = nil; ret.displayMode = 'MENU'; -- default ret.autoHideDelay = nil; ret.menuFrame = nil; -- If not defined, :Show will create a generic menu frame ret.uniqueID = 1

-- import the functions for k,v in pairs(self) do       ret[k] = v    end -- return a copy of the class return ret end

--   Return the index where "text" lives.    ; text : The text to search for. -- function MenuClass:GetItemByText(text) for k,v in pairs(self.menuList) do       if v.text == text then return k       end end end

--   Add menu items    ; text : The display text.    ; func : The function to execute OnClick.    ; isTitle : 1 if this is a header (usually the first one)    ; otherAttributes : table - { ["attribute"] = value, }    returns the last index of the menu item that was just added. -- function MenuClass:AddItem(text, func, isTitle, otherAttributes) local info = {} info["text"] = text info["isTitle"] = isTitle info["func"] = func if type(otherAttributes) == "table" then for attribute, value in pairs(otherAttributes) do           info[attribute] = value end end

table.insert(self.menuList, info) return #self.menuList end

--   Set an attribute for the menu item.    Valid attributes are found in the FrameXML\UIDropDownMenu.lua file with their valid values.    Arbitrary non-official attributes are allowed, but are only useful if you plan to access them with :GetAttribute.    ; text : The text of the menu item or index of the menu item.    ; attribute : Set this attribute to "value".    ; value : The value to set the attribute to. -- function MenuClass:SetAttribute(text, attribute, value) self.menuList[self:GetItemByText(text) or (self.menuList[text] and text) or 1][attribute or "uniqueID"] = value end

--   Get an attribute for the menu item.    Valid attributes are found in the FrameXML\UIDropDownMenu.lua file with their valid values or any arbitrary attribute set with :SetAttribute.    ; text : The text of the menu item or index of the menu item.    ; attribute : Get this attribute. -- function MenuClass:GetAttribute(text, attribute) return self.menuList[self:GetItemByText(text) or (self.menuList[text] and text) or 1][attribute or "uniqueID"] end

--   Remove the first item matching "text"    ; text : The text to search for. -- function MenuClass:RemoveItem(text) table.remove(self.menuList, self:GetItemByText(text)) end

--   ; anchor : Set the anchor point. -- function MenuClass:SetAnchor(anchor) if anchor ~= 'cursor' then self.x = 0 self.y = 0 end self.anchor = anchor end

--   ; displayMode : "MENU" -- function MenuClass:SetDisplayMode(displayMode) self.displayMode = displayMode end

--   ; autoHideDelay : How long, without a click, before the menu goes away. -- function MenuClass:SetAutoHideDelay(autoHideDelay) self.autoHideDelay = tonumber(autoHideDelay) end

--   ; menuFrame : Should inherit a Drop Down Menu template. -- function MenuClass:SetMenuFrame(menuFrame) self.menuFrame = menuFrame end

function MenuClass:GetMenuList return self.menuList end

--   ; x : X position    ; save : When not nil, will add to the current value rather than replace it -- function MenuClass:SetX(x, save) if save then self.x = self.x + x   else self.x = x   end end

--   ; y : Y position    ; save : When not nil, will add to the current value rather than replace it -- function MenuClass:SetY(y, save) if save then self.y = self.y + y   else self.y = y   end end

function MenuClass:Activate if not self.menuFrame then while _G['GenericMenuClassFrame'..self.uniqueID] do -- ensure that there's no namespace collisions self.uniqueID = self.uniqueID + 1 end -- the frame must be named for some reason self.menuFrame = CreateFrame('Frame', 'GenericMenuClassFrame'..self.uniqueID, UIParent, "UIDropDownMenuTemplate") end self.menuFrame.menuList = self.menuList end

--   Show the menu. -- function MenuClass:Show self:Activate EasyMenu(self.menuList, self.menuFrame, self.anchor, self.x, self.y, self.displayMode, self.autoHideDelay) end

-- If you're not using the addon-scoped variables, you must have a global variable in order to use this menu. if not useAddonScope then _G[addonName.."Menu"] = MenuClass end