You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

563 lines
18 KiB

local MAJOR, MINOR = "LibElv-UIButtons-1.0", 3
local lib, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not lib then return end
local E, L, V, P, G = unpack(ElvUI)
local S = E.Skins
local TT = E.Tooltip
--GLOBALS: CreateFrame
local _G = _G
local pairs, type, tinsert = pairs, type, tinsert
local UnitName = UnitName
local GameTooltip = GameTooltip
local GetAddOnEnableState = GetAddOnEnableState
--Upon creation menu.db does not account for values missing in E.db = being default.
--We are using this to fix it.
local function EqualizeDB(db, default)
for key, value in pairs(default) do
if not db[key] and type(default[key]) ~= 'table' then
db[key] = default[key]
elseif type(default[key]) == 'table' then
EqualizeDB(db[key], default[key])
end
end
end
--Sets the size of menu's mover
local function MoverSize(menu)
local db = menu.db
if db.orientation == 'vertical' then
menu:SetWidth(db.size + 2 + E.Spacing*2)
menu:SetHeight((db.size*menu.NumBut)+((db.spacing + E.Spacing*2)*(menu.NumBut-1))+2)
elseif db.orientation == 'horizontal' then
menu:SetWidth((db.size*menu.NumBut)+((db.spacing + E.Spacing*2)*(menu.NumBut-1))+2)
menu:SetHeight(db.size + 2 + E.Spacing*2)
end
end
--Creates a mover for the menu
local function SetupMover(menu, name, own)
local exist = false
for i = 1, #E.ConfigModeLayouts do
if E.ConfigModeLayouts[i] == 'UIButtons' then
exist = true
break
end
end
if not exist then --Create a new config group for movers
tinsert(E.ConfigModeLayouts, #(E.ConfigModeLayouts)+1, 'UIButtons')
E.ConfigModeLocalizedStrings['UIButtons'] = L["UI Buttons"]
end
E:CreateMover(menu, menu:GetName()..'Mover', name, nil, nil, nil, own and own..',UIButtons' or 'ALL,UIButtons')
end
--A function to toggle dropdown categories to show/hide then on button click
local function ToggleCats(menu)
for i = 1, #menu.ToggleTable do
if menu.ToggleTable[i].opened then
menu.HoldersTable[i]:Show()
else
menu.HoldersTable[i]:Hide()
end
end
end
local function OnEnter(menu)
menu:SetAlpha(1)
end
local function OnLeave(menu)
if menu.db.mouse then
menu:SetAlpha(0)
end
end
--Creating main buttons to execute stuff in classic mode and toggle categories n dropdown
local function CreateCoreButton(menu, name, text, onClick)
if _G[menu:GetName()..'_Core_'..name] then return end
local button, holder
if menu.style == 'classic' then
menu[name] = CreateFrame('Button', menu:GetName()..'_Core_'..name, menu, 'BackdropTemplate')
button = menu[name]
if onClick then
button:SetScript('OnClick', onClick)
end
elseif menu.style == 'dropdown' then
menu[name] = CreateFrame('Frame', menu:GetName()..'_Core_'..name, menu)
menu[name].Toggle = CreateFrame('Button', menu:GetName()..'_Core_'..name..'Toggle', menu, 'BackdropTemplate')
holder = menu[name]
holder.width = 0
holder:CreateBackdrop('Transparent')
button = menu[name].Toggle
if not menu[name..'Table'] then
menu[name..'Table'] = {}
end
menu:ToggleSetup(button, holder)
tinsert(menu.HoldersTable, holder)
tinsert(menu.GroupsTable, name)
else
lib:CustomStyleCoreButton(menu, name, text)
end
button:SetScript('OnEnter', function(self) menu:OnEnter() end)
button:SetScript('OnLeave', function(self) menu:OnLeave() end)
-- button:SetSize(17, 17) --For testing purposes
button.text = button:CreateFontString(nil, 'OVERLAY')
button.text:SetPoint('CENTER', button, 'CENTER', 0, 0)
if menu.transparent == 'Transparent' then
button:CreateBackdrop('Transparent')
elseif menu.transparent == 'Default' then
S:HandleButton(button)
end
if text then
local t = button:CreateFontString(nil, 'OVERLAY')
t:FontTemplate()
t:SetPoint('CENTER', button, 'CENTER', 0, -1)
t:SetJustifyH('CENTER')
t:SetText(text)
button:SetFontString(t)
end
tinsert(menu.ToggleTable, button)
menu.NumBut = menu.NumBut + 1
end
--Creating buttons to populate dropdowns
local function CreateDropdownButton(menu, core, name, text, tooltip1, tooltip2, click, addon, always)
if addon then --Check if addon specified as dependancy is enabled to load (not loaded cause it can start to load way after our code is executed)
local enabled = GetAddOnEnableState(menu.myname, addon)
if enabled == 0 then return end
end
if _G[menu:GetName()..'_Core_'..core..name] or not menu[core..'Table'] then return end
menu[core][name] = CreateFrame('Button', menu:GetName()..'_Core_'..core..name, menu[core], 'BackdropTemplate')
local b = menu[core][name]
local toggle = menu[core].Toggle
b:SetScript('OnClick', function(self)
click()
toggle.opened = false
menu:ToggleCats()
end)
if tooltip1 then
b:SetScript('OnEnter', function(self)
menu:OnEnter()
GameTooltip:SetOwner(self)
GameTooltip:AddLine(tooltip1, 1, .96, .41, .6, .6, 1)
if tooltip2 then GameTooltip:AddLine(tooltip2, 1, 1, 1, 1, 1, 1) end
GameTooltip:Show()
end)
b:SetScript('OnLeave', function(self)
menu:OnLeave()
GameTooltip:Hide()
end)
else
b:SetScript('OnEnter', function(self) menu:OnEnter() end)
b:SetScript('OnLeave', function(self) menu:OnLeave() end)
end
if menu.transparent == 'Transparent' then
b:CreateBackdrop('Transparent')
elseif menu.transparent == 'Default' then
S:HandleButton(b)
end
if text and type(text) == 'string' then
b.text = b:CreateFontString(nil, 'OVERLAY')
b.text:FontTemplate()
b.text:SetPoint('CENTER', b, 'CENTER', 0, -1)
b.text:SetJustifyH('CENTER')
b.text:SetText(text)
b:SetFontString(b.text)
end
tinsert(menu[core..'Table'], b)
end
--Creating separator frame
local function CreateSeparator(menu, core, name, size, space)
if _G[menu:GetName()..'_Core_'..core..name..'_Separator'] or not menu[core..'Table'] then return end
menu[core][name] = CreateFrame('Frame', menu:GetName()..'_Core_'..core..name..'_Separator', menu[core], 'BackdropTemplate')
local f = menu[core][name]
f.isSeparator = true
f.size = size or 1
f.space = space or 2
f:CreateBackdrop('Transparent')
f:SetScript('OnEnter', function(self) menu:OnEnter() end)
f:SetScript('OnLeave', function(self) menu:OnLeave() end)
tinsert(menu[core..'Table'], f)
end
--Setup for core buttons in dropdown mode to act like toggles
local function ToggleSetup(menu, button, holder)
local db = menu.db
button.opened = false
holder:Hide()
button:SetScript('OnClick', function(self, button, down)
if button == 'LeftButton' then
if self.opened then
self.opened = false
else
self.opened = true
for i = 1, #menu.ToggleTable do
if menu.ToggleTable[i] ~= self then menu.ToggleTable[i].opened = false end
end
end
menu:ToggleCats()
end
end)
holder:SetScript('OnEnter', function(self) menu:OnEnter() end)
holder:SetScript('OnLeave', function(self) menu:OnLeave() end)
end
--Updating the positioning and order of dropdown category
local function UpdateDropdownLayout(menu, group)
local count = -1
local sepS, sepC = 0, 0
local header = menu[group]
local db = menu.db
header:ClearAllPoints()
header:SetPoint(db.point, header.Toggle, db.anchor, db.xoffset, db.yoffset)
local T = menu[group..'Table']
for i = 1, #T do
local button, prev, next = T[i], T[i-1], T[i+1]
local y_offset = prev and (-(db.spacing + E.Spacing*2) - (prev.isSeparator and prev.space or 0) - (button.isSeparator and button.space or 0)) or 0
button:SetPoint('TOP', (prev or header), (prev and 'BOTTOM' or 'TOP'), 0, y_offset)
count = button.isSeparator and count or count + 1
sepS = (button.isSeparator and sepS + ((prev and 2 or 1)*button.space + button.size)) or sepS
sepC = button.isSeparator and sepC + 1 or sepC
end
header:SetSize(header.width, (db.size * (count+1))+(db.spacing*(count))+sepS+(.5*sepC))
if menu.db.dropdownBackdrop then
header.backdrop:Show()
else
header.backdrop:Hide()
end
end
local function UpdateMouseOverSetting(menu)
if menu.db.mouse then
menu:SetAlpha(0)
else
menu:SetAlpha(1)
end
end
--Updating positions of the menu
local function Positioning(menu)
local db = menu.db
--position check
local header = menu
if db.orientation == 'vertical' then
for i = 1, #menu.ToggleTable do
local button, prev = menu.ToggleTable[i], menu.ToggleTable[i-1]
menu.ToggleTable[i]:ClearAllPoints()
menu.ToggleTable[i]:SetPoint('TOP', (prev or header), prev and 'BOTTOM' or 'TOP', 0, prev and -(db.spacing + E.Spacing*2) or -(1 + E.Spacing))
end
elseif db.orientation == 'horizontal' then
for i = 1, #menu.ToggleTable do
local button, prev = menu.ToggleTable[i], menu.ToggleTable[i-1]
menu.ToggleTable[i]:ClearAllPoints()
menu.ToggleTable[i]:SetPoint('LEFT', (prev or header), prev and 'RIGHT' or 'LEFT', prev and (db.spacing + E.Spacing*2) or (1 + E.Spacing), 0)
end
end
--Calling for dropdown updates
if menu.style == 'dropdown' then
for i = 1, #menu.GroupsTable do
menu:UpdateDropdownLayout(menu.GroupsTable[i])
end
end
end
--Resizing frames. Need to run after a new button was created to let the menu know it exist
local function FrameSize(menu)
local db = menu.db
if not db.size then return end
menu:MoverSize()
for i = 1, #menu.ToggleTable do
menu.ToggleTable[i]:SetSize(db.size, db.size)
end
if menu.style == 'dropdown' then
for i = 1, #menu.GroupsTable do
local group = menu.GroupsTable[i]
local mass = menu[group..'Table']
for w = 1, #mass do
if mass[w].text and mass[w].text:GetWidth() > menu.HoldersTable[i].width and not menu.fixedDropdownWidth then
menu.HoldersTable[i].width = mass[w].text:GetWidth() + 10
elseif menu.fixedDropdownWidth then
menu.HoldersTable[i].width = menu.fixedDropdownWidth
if mass[w].text and mass[w].text:GetWidth() > menu.fixedDropdownWidth then
mass[w].text:SetWidth(menu.fixedDropdownWidth - 10)
mass[w].text:SetWordWrap(false)
end
end
end
for n = 1, #mass do
if mass[n].isSeparator then
mass[n]:SetSize(menu.HoldersTable[i].width - 3, mass[n].size)
else
mass[n]:SetSize(menu.HoldersTable[i].width, db.size)
end
end
end
end
menu:Positioning()
end
local function UpdateBackdrop(menu)
if menu.db.menuBackdrop then
menu.backdrop:Show()
else
menu.backdrop:Hide()
end
end
--Enable/disable call
local function ToggleShow(menu)
if not menu.db.enable then
menu:Hide()
E:DisableMover(menu.mover:GetName())
UnregisterStateDriver(menu, 'visibility')
else
menu:Show()
menu:UpdateMouseOverSetting()
menu:UpdateBackdrop()
E:EnableMover(menu.mover:GetName())
if menu.db.visibility then RegisterStateDriver(menu, 'visibility', menu.db.visibility) end
end
end
--Creating of the menu
function lib:CreateFrame(name, db, default, style, styleDefault, strata, level, transparent)
--Checks to prevent a shitload of errors cause of wrong arguments passed
if _G[name] then return end
if not strata then strata = 'MEDIUM' end
local menu = CreateFrame('Frame', name, E.UIParent, 'BackdropTemplate')
menu.db = db --making menu db table so we can actually keep unified settings calls in other functions
menu.default = default --same for defaults
EqualizeDB(menu.db, menu.default)
if not style and styleDefault then style = styleDefault end
menu.style = style
menu.transparent = transparent
menu:SetFrameStrata(strata)
menu:SetFrameLevel(level or 5)
menu:SetClampedToScreen(true)
menu:SetPoint('LEFT', E.UIParent, 'LEFT', -2, 0)
menu:SetSize(17, 17) --Cause the damn thing doesn't want to show up without default size lol
menu.myname = UnitName('player') --used in checks for addon deps
menu:CreateBackdrop()
menu.NumBut = 0
menu.ToggleTable = {}
menu.HoldersTable = {}
menu.GroupsTable = {}
--Setting API
menu.CreateCoreButton = CreateCoreButton
menu.CreateDropdownButton = CreateDropdownButton
menu.CreateSeparator = CreateSeparator
menu.ToggleSetup = ToggleSetup
menu.ToggleCats = ToggleCats
menu.UpdateDropdownLayout = UpdateDropdownLayout
menu.Positioning = Positioning
menu.MoverSize = MoverSize
menu.UpdateMouseOverSetting = UpdateMouseOverSetting
menu.FrameSize = FrameSize
menu.SetupMover = SetupMover
menu.ToggleShow = ToggleShow
menu.UpdateBackdrop = UpdateBackdrop
menu.OnEnter = OnEnter
menu.OnLeave = OnLeave
menu:SetScript('OnEnter', function(self) menu:OnEnter() end)
menu:SetScript('OnLeave', function(self) menu:OnLeave() end)
return menu
end
--Default options table structure
local function GenerateTable(menu, coreGroup, groupName, groupTitle)
local positionValues = {
TOPLEFT = 'TOPLEFT',
LEFT = 'LEFT',
BOTTOMLEFT = 'BOTTOMLEFT',
RIGHT = 'RIGHT',
TOPRIGHT = 'TOPRIGHT',
BOTTOMRIGHT = 'BOTTOMRIGHT',
CENTER = 'CENTER',
TOP = 'TOP',
BOTTOM = 'BOTTOM',
}
local isDefault = coreGroup == true and true or false
if isDefault and not E.Options.args.uibuttons then
E.Options.args.uibuttons = {
type = 'group',
name = L["UI Buttons"],
order = 77,
childGroups = 'select',
args = {
},
}
coreGroup = E.Options.args.uibuttons
end
coreGroup.args[groupName] = {
type = 'group',
name = groupTitle,
order = 1,
args = {
header = {
order = 1,
type = 'header',
name = groupTitle,
},
enabled = {
order = 3,
type = 'toggle',
name = L["Enable"],
desc = L["Show/Hide UI buttons."],
get = function(info) return menu.db.enable end,
set = function(info, value) menu.db.enable = value; menu:ToggleShow() end
},
style = {
order = 4,
name = L["UI Buttons Style"],
type = 'select',
values = {
['classic'] = L["Classic"],
['dropdown'] = L["Dropdown"],
},
disabled = function() return not menu.db.enable end,
get = function(info) return E.private.sle.uiButtonStyle end,
set = function(info, value) E.private.sle.uiButtonStyle = value; E:StaticPopup_Show('PRIVATE_RL') end,
},
space = {
order = 5,
type = 'description',
name = '',
},
size = {
order = 6,
type = 'range',
name = L["Size"],
desc = L["Sets size of buttons"],
min = 12, max = 25, step = 1,
disabled = function() return not menu.db.enable end,
get = function(info) return menu.db.size end,
set = function(info, value) menu.db.size = value; menu:FrameSize() end,
},
spacing = {
order = 7,
type = 'range',
name = L["Button Spacing"],
desc = L["The spacing between buttons."],
min = 1, max = 10, step = 1,
disabled = function() return not menu.db.enable end,
get = function(info) return menu.db.spacing end,
set = function(info, value) menu.db.spacing = value; menu:FrameSize() end,
},
mouse = {
order = 8,
type = 'toggle',
name = L["Mouseover"],
desc = L["Show on mouse over."],
disabled = function() return not menu.db.enable end,
get = function(info) return menu.db.mouse end,
set = function(info, value) menu.db.mouse = value; menu:UpdateMouseOverSetting() end
},
menuBackdrop = {
order = 9,
type = 'toggle',
name = L["Backdrop"],
disabled = function() return not menu.db.enable end,
get = function(info) return menu.db.menuBackdrop end,
set = function(info, value) menu.db.menuBackdrop = value; menu:UpdateBackdrop() end
},
dropdownBackdrop = {
order = 10,
type = 'toggle',
name = L["Dropdown Backdrop"],
disabled = function() return not menu.db.enable or E.private.sle.uiButtonStyle == 'classic' end,
get = function(info) return menu.db.dropdownBackdrop end,
set = function(info, value) menu.db.dropdownBackdrop = value; menu:FrameSize() end
},
orientation = {
order = 11,
name = L["Buttons position"],
desc = L["Layout for UI buttons."],
type = 'select',
values = {
['horizontal'] = L["Horizontal"],
['vertical'] = L["Vertical"],
},
disabled = function() return not menu.db.enable end,
get = function(info) return menu.db.orientation end,
set = function(info, value) menu.db.orientation = value; menu:FrameSize() end,
},
point = {
type = 'select',
order = 13,
name = L["Anchor Point"],
desc = L["What point of dropdown will be attached to the toggle button."],
disabled = function() return not menu.db.enable or E.private.sle.uiButtonStyle == 'classic' end,
get = function(info) return menu.db.point end,
set = function(info, value) menu.db.point = value; menu:FrameSize() end,
values = positionValues,
},
anchor = {
type = 'select',
order = 14,
name = L["Attach To"],
desc = L["What point to anchor dropdown on the toggle button."],
disabled = function() return not menu.db.enable or E.private.sle.uiButtonStyle == 'classic' end,
get = function(info) return menu.db.anchor end,
set = function(info, value) menu.db.anchor = value; menu:FrameSize() end,
values = positionValues,
},
xoffset = {
order = 15,
type = 'range',
name = L["X-Offset"],
desc = L["Horizontal offset of dropdown from the toggle button."],
min = -10, max = 10, step = 1,
disabled = function() return not menu.db.enable or E.private.sle.uiButtonStyle == 'classic' end,
get = function(info) return menu.db.xoffset end,
set = function(info, value) menu.db.xoffset = value; menu:FrameSize() end,
},
yoffset = {
order = 16,
type = 'range',
name = L["Y-Offset"],
desc = L["Vertical offset of dropdown from the toggle button."],
min = -10, max = 10, step = 1,
disabled = function() return not menu.db.enable or E.private.sle.uiButtonStyle == 'classic' end,
get = function(info) return menu.db.yoffset end,
set = function(info, value) menu.db.yoffset = value; menu:FrameSize() end,
},
},
}
end
function lib:CreateOptions(menu, default, groupName, groupTitle)
menu:RegisterEvent('ADDON_LOADED')
menu:SetScript('OnEvent', function(self, event, addon)
if addon ~= 'ElvUI_OptionsUI' then return end
self:UnregisterEvent('ADDON_LOADED')
GenerateTable(self, default, groupName, groupTitle)
end)
end
--This function is for creating own menu style. Replacing is not encouraged, hooking recommended.
function lib:CustomStyleCoreButton(menu, name, text)
end