Init
In case that i stop maintaining this addon, feel free to contribute.
This commit is contained in:
parent
333dbc37ef
commit
603ee5f5f6
41
AchievementInfo.lua
Normal file
41
AchievementInfo.lua
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
--[[
|
||||||
|
AchievementInfo
|
||||||
|
@author Asto, @Astarax
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Init
|
||||||
|
AchievementInfo.hijackedFirstLoad = false
|
||||||
|
function AchievementInfo.initialize(eventCode, addOnName)
|
||||||
|
if (addOnName ~= AchievementInfo.name) then return end
|
||||||
|
|
||||||
|
--
|
||||||
|
if AchievementInfo.hijackedFirstLoad == false then
|
||||||
|
AchievementInfo.hijackedFirstLoad = true
|
||||||
|
|
||||||
|
-- Load Saved Variables
|
||||||
|
AchievementInfo.savedVars = AchievementInfo.loadSavedVars()
|
||||||
|
|
||||||
|
-- Load Language Data
|
||||||
|
LANG = AchievementInfo.loadLanguage()
|
||||||
|
|
||||||
|
-- Settings Panel
|
||||||
|
AchievementInfo.createSettingsPanel()
|
||||||
|
|
||||||
|
-- Register Events
|
||||||
|
AchievementInfo.registerEvent(EVENT_ACHIEVEMENT_UPDATED, AchievementInfo.onAchievementUpdated)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Status Output (debug mode only)
|
||||||
|
if AchievementInfo.settingGet("devDebug") then
|
||||||
|
zo_callLater(function()
|
||||||
|
AchievementInfo.echo(AchievementInfo.name .. " initialized in DEBUG MODE :)")
|
||||||
|
end, 500)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Register the Init Event
|
||||||
|
AchievementInfo.registerEvent(EVENT_ADD_ON_LOADED, AchievementInfo.initialize)
|
23
AchievementInfo.txt
Normal file
23
AchievementInfo.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
## Title: AchievementInfo
|
||||||
|
## Description: Displays progress updates for achievements in the chat. You can display update-details like 'Slay 25/100 Monsters' if interested. |cFF0000Important:|r The messages appear only when an achievement is updated. This is no permanent tracking tool.
|
||||||
|
## Version: 2.8
|
||||||
|
## Author: |c87B7CCAsto|r, @Astarax
|
||||||
|
## Contact: mail@coded-with-heart.com
|
||||||
|
|
||||||
|
## APIVersion: 100015
|
||||||
|
## SavedVariables: ACHIEVEMENT_INFO_DB
|
||||||
|
|
||||||
|
## OptionalDependsOn: LibAddonMenu-2.0, LibStub
|
||||||
|
|
||||||
|
## Libraries:
|
||||||
|
Libs/LibStub/LibStub.lua
|
||||||
|
Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
|
||||||
|
|
||||||
|
## Helper:
|
||||||
|
AchievementInfoCommon.lua
|
||||||
|
AchievementInfoLangStore.lua
|
||||||
|
|
||||||
|
## Core:
|
||||||
|
AchievementInfo.lua
|
||||||
|
AchievementInfoSettings.lua
|
||||||
|
AchievementInfoApplication.lua
|
193
AchievementInfoApplication.lua
Normal file
193
AchievementInfoApplication.lua
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
--[[
|
||||||
|
AchievementInfo
|
||||||
|
@author Asto, @Astarax
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Do the magic
|
||||||
|
function AchievementInfo.onAchievementUpdated(eventCode, achId)
|
||||||
|
local output = ""
|
||||||
|
|
||||||
|
-- addOn enabled?
|
||||||
|
if AchievementInfo.settingGet("genEnabled") == false then
|
||||||
|
if AchievementInfo.settingGet("devDebug") == false then
|
||||||
|
return
|
||||||
|
else
|
||||||
|
output = output .. "DEBUG (AddOn Disabled): "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--
|
||||||
|
|
||||||
|
local categoryId = AchievementInfo.getCorrectAchievementCategoryId(achId)
|
||||||
|
|
||||||
|
-- ignore unwanted achievements ...
|
||||||
|
if categoryId == false then
|
||||||
|
if AchievementInfo.settingGet("devDebug") == false then
|
||||||
|
return
|
||||||
|
else
|
||||||
|
output = output .. "DEBUG (Not Next): "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--
|
||||||
|
|
||||||
|
-- achievement category enabled?
|
||||||
|
if categoryId ~= false and AchievementInfo.settingGet("cat"..categoryId) == false then
|
||||||
|
if AchievementInfo.settingGet("devDebug") == false then
|
||||||
|
return
|
||||||
|
else
|
||||||
|
output = output .. "DEBUG (Category Off): "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--
|
||||||
|
|
||||||
|
-- okay continue with the message
|
||||||
|
local detailOutput = {}
|
||||||
|
local detailOutputCount = 1
|
||||||
|
local percentageCmpSum = 0
|
||||||
|
local percentageReqSum = 0
|
||||||
|
local percentageStep = false
|
||||||
|
local percentageStepSize = AchievementInfo.settingGet("genShowUpdateSteps")
|
||||||
|
|
||||||
|
local link = GetAchievementLink(achId, LINK_STYLE_BRACKET)
|
||||||
|
local name, description = GetAchievementInfo(achId)
|
||||||
|
local catName = "/"
|
||||||
|
|
||||||
|
if categoryId ~= false then
|
||||||
|
catName = GetAchievementCategoryInfo(categoryId)
|
||||||
|
end
|
||||||
|
|
||||||
|
output = output .. "" .. link .. " (" .. catName .. ")"
|
||||||
|
|
||||||
|
local numCriteria = GetAchievementNumCriteria(achId)
|
||||||
|
for i = 1, numCriteria, 1 do
|
||||||
|
local name, numCompleted, numRequired = GetAchievementCriterion(achId, i)
|
||||||
|
local tmpOutput = ""
|
||||||
|
|
||||||
|
if i > 1 and AchievementInfo.settingGet("genOnePerLine") == false then
|
||||||
|
tmpOutput = tmpOutput .. ", "
|
||||||
|
end
|
||||||
|
|
||||||
|
tmpOutput = tmpOutput .. name .. " "
|
||||||
|
tmpOutput = tmpOutput .. AchievementInfo.calcCriteriaColor(numCompleted, numRequired) .. numCompleted .. "|r"
|
||||||
|
tmpOutput = tmpOutput .. AchievementInfo.clrDefault .. "/" .. "|r"
|
||||||
|
tmpOutput = tmpOutput .. AchievementInfo.clrCriteriaComplete .. numRequired .. "|r"
|
||||||
|
tmpOutput = tmpOutput .. AchievementInfo.clrDefault
|
||||||
|
|
||||||
|
if AchievementInfo.settingGet("genShowOpenDetailsOnly") == true and numCompleted ~= numRequired then
|
||||||
|
detailOutput[detailOutputCount] = tmpOutput
|
||||||
|
detailOutputCount = detailOutputCount + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
-- show the achievement on every special achievement because it's a rare event
|
||||||
|
if numRequired == 1 and numCompleted == 1 then
|
||||||
|
percentageStep = true
|
||||||
|
-- collect the numbers to calculate the correct percentage
|
||||||
|
else
|
||||||
|
percentageReqSum = percentageReqSum + numRequired
|
||||||
|
percentageCmpSum = percentageCmpSum + numCompleted
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if percentageStep == false then
|
||||||
|
-- show at percent value
|
||||||
|
local percentage = 100 / percentageReqSum * percentageCmpSum
|
||||||
|
local percentageNext = 100 / percentageReqSum * (percentageCmpSum + 1)
|
||||||
|
|
||||||
|
-- if percentage of percentageStepSize is hit or the value is next to it and the next value will be higher
|
||||||
|
if --[[percentage > 0 and]] percentage % percentageStepSize == 0 or (percentage % percentageStepSize > percentageNext % percentageStepSize and percentageNext % percentageStepSize ~= 0) then
|
||||||
|
percentageStep = true
|
||||||
|
-- show if this is the first numCompleted value
|
||||||
|
elseif percentageCmpSum == 1 then
|
||||||
|
percentageStep = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- show details?
|
||||||
|
local detailsCount = AchievementInfo.tableLength(detailOutput)
|
||||||
|
if AchievementInfo.settingGet("genShowDetails") == true and detailsCount > 0 and AchievementInfo.settingGet("genOnePerLine") == false then
|
||||||
|
output = output .. " - "
|
||||||
|
|
||||||
|
for i = 1, detailsCount, 1 do
|
||||||
|
output = output .. detailOutput[i]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
output = output .. "."
|
||||||
|
end
|
||||||
|
--
|
||||||
|
|
||||||
|
-- output on every step OR when its a defined percentage step
|
||||||
|
if AchievementInfo.settingGet("genShowEveryUpdate") == false and percentageStep == false then
|
||||||
|
if AchievementInfo.settingGet("devDebug") == false then
|
||||||
|
return
|
||||||
|
else
|
||||||
|
output = "DEBUG (" .. AchievementInfo.settingGet("genShowUpdateSteps") .. "% Rule): " .. output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
if percentageReqSum == percentageCmpSum then
|
||||||
|
output = LANG.Completed .. ": " .. output
|
||||||
|
else
|
||||||
|
output = LANG.Updated .. ": " .. output
|
||||||
|
end
|
||||||
|
--
|
||||||
|
|
||||||
|
AchievementInfo.echo(output)
|
||||||
|
|
||||||
|
-- output the details line by line - start @2 because the normal output happend before (achievement name)
|
||||||
|
if AchievementInfo.settingGet("genShowDetails") == true and AchievementInfo.settingGet("genOnePerLine") == true then
|
||||||
|
for i = 1, AchievementInfo.tableLength(detailOutput), 1 do
|
||||||
|
AchievementInfo.echo(detailOutput[i])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Check if the category of an achievement is valid (reverse check)
|
||||||
|
function AchievementInfo.checkForValidCategory(achId)
|
||||||
|
local categoryTopLevelIndex, categoryIndex, achievementIndex = GetCategoryInfoFromAchievementId(achId)
|
||||||
|
local reverseAchievementId = GetAchievementId(categoryTopLevelIndex, categoryIndex, achievementIndex)
|
||||||
|
|
||||||
|
if achId == reverseAchievementId then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Get the correct achievement category
|
||||||
|
function AchievementInfo.getCorrectAchievementCategoryId(achId)
|
||||||
|
local previousAchievementId = GetPreviousAchievementInLine(achId)
|
||||||
|
local categoryId = 0
|
||||||
|
|
||||||
|
if AchievementInfo.checkForValidCategory(achId) == false and previousAchievementId ~= 0 then
|
||||||
|
return AchievementInfo.getCorrectAchievementCategoryId(previousAchievementId)
|
||||||
|
elseif AchievementInfo.checkForValidCategory(achId) then
|
||||||
|
categoryId = GetCategoryInfoFromAchievementId(achId)
|
||||||
|
return categoryId
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Calculates the percentage of the achievement completition to define the color
|
||||||
|
function AchievementInfo.calcCriteriaColor(completed, required)
|
||||||
|
local percentage = 100 / required * completed
|
||||||
|
|
||||||
|
if completed == required then
|
||||||
|
return AchievementInfo.clrCriteriaComplete
|
||||||
|
elseif percentage <= 33 then
|
||||||
|
return AchievementInfo.clrCriteriaFar
|
||||||
|
elseif percentage <= 66 then
|
||||||
|
return AchievementInfo.clrCriteriaMedi
|
||||||
|
else
|
||||||
|
return AchievementInfo.clrCriteriaClose
|
||||||
|
end
|
||||||
|
end
|
65
AchievementInfoCommon.lua
Normal file
65
AchievementInfoCommon.lua
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
--[[
|
||||||
|
AchievementInfo
|
||||||
|
@author Asto, @Astarax
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AchievementInfo = {}
|
||||||
|
AchievementInfo.name = "AchievementInfo"
|
||||||
|
AchievementInfo.author = "Asto, @Astarax"
|
||||||
|
AchievementInfo.version = 2.8
|
||||||
|
AchievementInfo.savedVars = nil
|
||||||
|
AchievementInfo.LangStore = {}
|
||||||
|
|
||||||
|
local clrPrefix = "|c"
|
||||||
|
AchievementInfo.clrDefault = clrPrefix .. "87B7CC"
|
||||||
|
AchievementInfo.clrCriteriaFar = clrPrefix .. "F27C7C"
|
||||||
|
AchievementInfo.clrCriteriaMedi = clrPrefix .. "EDE858"
|
||||||
|
AchievementInfo.clrCriteriaClose = clrPrefix .. "CCF048"
|
||||||
|
AchievementInfo.clrCriteriaComplete = clrPrefix .. "71DE73"
|
||||||
|
AchievementInfo.clrSettingsHeader = clrPrefix .. "F0C91A"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Load the correct language
|
||||||
|
function AchievementInfo.loadLanguage()
|
||||||
|
local lang = GetCVar("language.2")
|
||||||
|
|
||||||
|
if lang == "de" then
|
||||||
|
return LANG_STORE.DE
|
||||||
|
-- elseif lang == "fr" then
|
||||||
|
-- return LANG_STORE.EN
|
||||||
|
else
|
||||||
|
return LANG_STORE.EN
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Event Registration Shortcut
|
||||||
|
function AchievementInfo.registerEvent(event, handler)
|
||||||
|
EVENT_MANAGER:RegisterForEvent(AchievementInfo.name, event, handler)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Message Output Shortcut
|
||||||
|
function AchievementInfo.echo(message)
|
||||||
|
-- addOn enabled?
|
||||||
|
if AchievementInfo.settingGet("genEnabled") == false then return end
|
||||||
|
|
||||||
|
if message ~= nil then
|
||||||
|
CHAT_SYSTEM:AddMessage(AchievementInfo.clrDefault..message.."|r")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Helper method to count a lua table
|
||||||
|
function AchievementInfo.tableLength(T)
|
||||||
|
local count = 0
|
||||||
|
for _ in pairs(T) do count = count + 1 end
|
||||||
|
return count
|
||||||
|
end
|
122
AchievementInfoLangStore.lua
Normal file
122
AchievementInfoLangStore.lua
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
--[[
|
||||||
|
AchievementInfo
|
||||||
|
@author Asto, @Astarax
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LANG_STORE = {}
|
||||||
|
LANG_STORE.EN = {} -- English version by Asto
|
||||||
|
LANG_STORE.DE = {} -- German version by Asto (native)
|
||||||
|
LANG_STORE.FR = {} -- French version open
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--[[
|
||||||
|
English version
|
||||||
|
@author Asto
|
||||||
|
]]
|
||||||
|
-- AddOn Output
|
||||||
|
LANG_STORE.EN.Updated = "Updated"
|
||||||
|
LANG_STORE.EN.Completed = "Completed"
|
||||||
|
|
||||||
|
-- AddOn Settings Header
|
||||||
|
LANG_STORE.EN.SettingsHeader = {}
|
||||||
|
LANG_STORE.EN.SettingsHeader.General = "General"
|
||||||
|
|
||||||
|
LANG_STORE.EN.SettingsHeader.Categories = "Categories"
|
||||||
|
LANG_STORE.EN.SettingsHeader.CategoriesDescription = "Here you can setup the notifications per category"
|
||||||
|
|
||||||
|
LANG_STORE.EN.SettingsHeader.Development = "Development"
|
||||||
|
|
||||||
|
-- AddOn Settings General Options
|
||||||
|
LANG_STORE.EN.SettingsOption = {}
|
||||||
|
LANG_STORE.EN.SettingsOption.AddOnEnabled = "AddOn enabled"
|
||||||
|
LANG_STORE.EN.SettingsOption.AddOnEnabledTooltip = "Enable or disable this AddOn"
|
||||||
|
LANG_STORE.EN.SettingsOption.AddOnEnabledWarning = "Only the output messages can be disabled here"
|
||||||
|
|
||||||
|
LANG_STORE.EN.SettingsOption.ShowEveryUpdate = "Show every update"
|
||||||
|
LANG_STORE.EN.SettingsOption.ShowEveryUpdateTooltip = "Shows a message on every status update of an achievement. Otherwise the messages appear only in steps of x%"
|
||||||
|
|
||||||
|
LANG_STORE.EN.SettingsOption.ShowUpdateSteps = "Notification steps (%)"
|
||||||
|
LANG_STORE.EN.SettingsOption.ShowUpdateStepsTooltip = "Defines the step width of notifications, if '" .. LANG_STORE.EN.SettingsOption.ShowEveryUpdate .. "' is disabled"
|
||||||
|
|
||||||
|
LANG_STORE.EN.SettingsOption.ShowDetails = "Show details"
|
||||||
|
LANG_STORE.EN.SettingsOption.ShowDetailsTooltip = "Shows progress details in each update message"
|
||||||
|
|
||||||
|
LANG_STORE.EN.SettingsOption.ShowOpenDetailsOnly = "Show incomplete details only"
|
||||||
|
LANG_STORE.EN.SettingsOption.ShowOpenDetailsOnlyTooltip = "Shows only the incomplete tasks of an achiemevent in the details"
|
||||||
|
|
||||||
|
-- pCHat compatibility option
|
||||||
|
LANG_STORE.EN.SettingsOption.OneElementPerLine = "Output line by line"
|
||||||
|
LANG_STORE.EN.SettingsOption.OneElementPerLineTooltip = "Shows each part of an achievement in a single line"
|
||||||
|
LANG_STORE.EN.SettingsOption.OneElementPerLineWarning = "Necessary for pChat compatibility"
|
||||||
|
|
||||||
|
-- AddOn Settings Category Options
|
||||||
|
-- The categories are taken from the game language files
|
||||||
|
LANG_STORE.EN.SettingsOption.CategoryTooltip = "Show messages for the category"
|
||||||
|
|
||||||
|
-- AddOn Settings Development Options
|
||||||
|
LANG_STORE.EN.SettingsOption.DebugMode = "Debug Mode"
|
||||||
|
LANG_STORE.EN.SettingsOption.DebugModeTooltip = "Shows hidden messages to check if they are hidden by mistake"
|
||||||
|
LANG_STORE.EN.SettingsOption.DebugModeWarning = "In most cases you don't need to activate this option"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--[[
|
||||||
|
German version
|
||||||
|
@author Asto
|
||||||
|
]]
|
||||||
|
-- AddOn Output
|
||||||
|
LANG_STORE.DE.Updated = "Aktualisiert"
|
||||||
|
LANG_STORE.DE.Completed = "Abgeschlossen"
|
||||||
|
|
||||||
|
-- AddOn Settings Header
|
||||||
|
LANG_STORE.DE.SettingsHeader = {}
|
||||||
|
LANG_STORE.DE.SettingsHeader.General = "Allgemein"
|
||||||
|
|
||||||
|
LANG_STORE.DE.SettingsHeader.Categories = "Kategorien"
|
||||||
|
LANG_STORE.DE.SettingsHeader.CategoriesDescription = "Hier können die Benachrichtigungen je Kategorie eingestellt werden"
|
||||||
|
|
||||||
|
LANG_STORE.DE.SettingsHeader.Development = "Entwicklung"
|
||||||
|
|
||||||
|
-- AddOn Settings General Options
|
||||||
|
LANG_STORE.DE.SettingsOption = {}
|
||||||
|
LANG_STORE.DE.SettingsOption.AddOnEnabled = "AddOn aktiviert"
|
||||||
|
LANG_STORE.DE.SettingsOption.AddOnEnabledTooltip = "Aktiviere oder deaktiviere dieses AddOn"
|
||||||
|
LANG_STORE.DE.SettingsOption.AddOnEnabledWarning = "An dieser Stelle können nur die Ausgaben deaktiviert werden."
|
||||||
|
|
||||||
|
LANG_STORE.DE.SettingsOption.ShowEveryUpdate = "Zeige alle Fortschritte"
|
||||||
|
LANG_STORE.DE.SettingsOption.ShowEveryUpdateTooltip = "Zeigt bei jeder Aktualisierung eines Erfolgs einen Hinweis. Alternativ wird nur in x% Schritten ein Status ausgegeben"
|
||||||
|
|
||||||
|
LANG_STORE.DE.SettingsOption.ShowUpdateSteps = "Benachrichtigungsschritte (%)"
|
||||||
|
LANG_STORE.DE.SettingsOption.ShowUpdateStepsTooltip = "Definiert die Schrittweite (Häufigkeit) der Benachrichtigungen, wenn '" .. LANG_STORE.DE.SettingsOption.ShowEveryUpdate .. "' deaktiviert ist"
|
||||||
|
|
||||||
|
LANG_STORE.DE.SettingsOption.ShowDetails = "Zeige Details"
|
||||||
|
LANG_STORE.DE.SettingsOption.ShowDetailsTooltip = "Zeigt die Fortschritt-Details des Erfolgs im Hinweis an"
|
||||||
|
|
||||||
|
LANG_STORE.DE.SettingsOption.ShowOpenDetailsOnly = "Zeige nur unerledigte Details"
|
||||||
|
LANG_STORE.DE.SettingsOption.ShowOpenDetailsOnlyTooltip = "Zeigt nur offene Aufgaben in den Fortschritt-Details an"
|
||||||
|
|
||||||
|
-- pCHat compatibility option
|
||||||
|
LANG_STORE.DE.SettingsOption.OneElementPerLine = "Zeilenweise Ausgabe"
|
||||||
|
LANG_STORE.DE.SettingsOption.OneElementPerLineTooltip = "Zeigt jeden Unterpunkt eines Erfolgs als eigene Zeile im Chat"
|
||||||
|
LANG_STORE.DE.SettingsOption.OneElementPerLineWarning = "Voraussetzung für eine pChat Kompatibilität"
|
||||||
|
|
||||||
|
-- AddOn Settings Category Options
|
||||||
|
-- The categories are taken from the game language files
|
||||||
|
LANG_STORE.DE.SettingsOption.CategoryTooltip = "Zeige Nachrichten für die Kategorie"
|
||||||
|
|
||||||
|
-- AddOn Settings Development Options
|
||||||
|
LANG_STORE.DE.SettingsOption.DebugMode = "Debug Modus"
|
||||||
|
LANG_STORE.DE.SettingsOption.DebugModeTooltip = "Zeigt versteckte Nachrichten, um zu prüfen ob ggf. Nachrichten unrechtmäßig unterdrückt werden"
|
||||||
|
LANG_STORE.DE.SettingsOption.DebugModeWarning = "In den meißten Fällen muss diese Option nicht aktiviert werden"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--[[
|
||||||
|
French version
|
||||||
|
@author /
|
||||||
|
]]
|
||||||
|
-- missing
|
175
AchievementInfoSettings.lua
Normal file
175
AchievementInfoSettings.lua
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
--[[
|
||||||
|
AchievementInfo
|
||||||
|
@author Asto, @Astarax
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Function to set and load the Saved Variables
|
||||||
|
function AchievementInfo.loadSavedVars()
|
||||||
|
local defaults = {
|
||||||
|
genEnabled = true,
|
||||||
|
genShowEveryUpdate = true,
|
||||||
|
genShowUpdateSteps = 25,
|
||||||
|
genShowDetails = false,
|
||||||
|
genShowOpenDetailsOnly = true,
|
||||||
|
genOnePerLine = true,
|
||||||
|
cat1 = true,
|
||||||
|
cat2 = true,
|
||||||
|
cat3 = true,
|
||||||
|
cat4 = true,
|
||||||
|
cat5 = true,
|
||||||
|
cat6 = true,
|
||||||
|
cat7 = true,
|
||||||
|
cat8 = true,
|
||||||
|
cat9 = true,
|
||||||
|
cat10 = true,
|
||||||
|
devDebug = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return ZO_SavedVars:New("ACHIEVEMENT_INFO_DB", 1, nil, defaults)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Function to create the settings panel
|
||||||
|
function AchievementInfo.createSettingsPanel()
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
|
||||||
|
local panelData = {
|
||||||
|
type = "panel",
|
||||||
|
name = AchievementInfo.name,
|
||||||
|
displayName = AchievementInfo.clrDefault..AchievementInfo.name,
|
||||||
|
author = AchievementInfo.author,
|
||||||
|
version = string.format("%.1f", AchievementInfo.version),
|
||||||
|
slashCommand = "/achievementInfo"
|
||||||
|
}
|
||||||
|
|
||||||
|
local optionsTable = {
|
||||||
|
[1] = {
|
||||||
|
type = "header",
|
||||||
|
name = AchievementInfo.clrSettingsHeader..LANG.SettingsHeader.General
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
type = "checkbox",
|
||||||
|
name = LANG.SettingsOption.AddOnEnabled,
|
||||||
|
tooltip = LANG.SettingsOption.AddOnEnabledTooltip,
|
||||||
|
getFunc = function() return AchievementInfo.settingGet("genEnabled") end,
|
||||||
|
setFunc = function() AchievementInfo.settingToogle("genEnabled") end,
|
||||||
|
warning = LANG.SettingsOption.AddOnEnabledWarning
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
type = "checkbox",
|
||||||
|
name = LANG.SettingsOption.ShowEveryUpdate,
|
||||||
|
tooltip = LANG.SettingsOption.ShowEveryUpdateTooltip,
|
||||||
|
getFunc = function() return AchievementInfo.settingGet("genShowEveryUpdate") end,
|
||||||
|
setFunc = function() AchievementInfo.settingToogle("genShowEveryUpdate") end
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
type = "slider",
|
||||||
|
name = LANG.SettingsOption.ShowUpdateSteps,
|
||||||
|
tooltip = LANG.SettingsOption.ShowUpdateStepsTooltip,
|
||||||
|
min = 1,
|
||||||
|
max = 100,
|
||||||
|
step = 1,
|
||||||
|
getFunc = function() return AchievementInfo.settingGet("genShowUpdateSteps") end,
|
||||||
|
setFunc = function(value) AchievementInfo.settingSet("genShowUpdateSteps", value) end,
|
||||||
|
default = 25
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
type = "checkbox",
|
||||||
|
name = LANG.SettingsOption.ShowDetails,
|
||||||
|
tooltip = LANG.SettingsOption.ShowDetailsTooltip,
|
||||||
|
getFunc = function() return AchievementInfo.settingGet("genShowDetails") end,
|
||||||
|
setFunc = function() AchievementInfo.settingToogle("genShowDetails") end
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
type = "checkbox",
|
||||||
|
name = LANG.SettingsOption.ShowOpenDetailsOnly,
|
||||||
|
tooltip = LANG.SettingsOption.ShowOpenDetailsOnlyTooltip,
|
||||||
|
getFunc = function() return AchievementInfo.settingGet("genShowOpenDetailsOnly") end,
|
||||||
|
setFunc = function() AchievementInfo.settingToogle("genShowOpenDetailsOnly") end
|
||||||
|
},
|
||||||
|
[7] = {
|
||||||
|
type = "checkbox",
|
||||||
|
name = LANG.SettingsOption.OneElementPerLine,
|
||||||
|
tooltip = LANG.SettingsOption.OneElementPerLineTooltip,
|
||||||
|
getFunc = function() return AchievementInfo.settingGet("genOnePerLine") end,
|
||||||
|
setFunc = function() AchievementInfo.settingToogle("genOnePerLine") end,
|
||||||
|
warning = LANG.SettingsOption.OneElementPerLineWarning
|
||||||
|
},
|
||||||
|
[8] = {
|
||||||
|
type = "header",
|
||||||
|
name = AchievementInfo.clrSettingsHeader .. LANG.SettingsHeader.Categories
|
||||||
|
},
|
||||||
|
[9] = {
|
||||||
|
type = "description",
|
||||||
|
text = LANG.SettingsHeader.CategoriesDescription .. ":"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Add categories dynamically
|
||||||
|
local numCats = GetNumAchievementCategories()
|
||||||
|
local catCount = 1
|
||||||
|
|
||||||
|
for i = 1, numCats, 1 do
|
||||||
|
catName, numSubCats = GetAchievementCategoryInfo(i)
|
||||||
|
|
||||||
|
table.insert(optionsTable, {
|
||||||
|
type = "checkbox",
|
||||||
|
name = catName,
|
||||||
|
tooltip = LANG.SettingsOption.CategoryTooltip .. " '" .. catName .. "'",
|
||||||
|
getFunc = function() return AchievementInfo.settingGet("cat"..i) end,
|
||||||
|
setFunc = function() AchievementInfo.settingToogle("cat"..i) end
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug setting at the end
|
||||||
|
table.insert(optionsTable, {
|
||||||
|
type = "header",
|
||||||
|
name = AchievementInfo.clrSettingsHeader .. LANG.SettingsHeader.Development
|
||||||
|
})
|
||||||
|
|
||||||
|
table.insert(optionsTable, {
|
||||||
|
type = "checkbox",
|
||||||
|
name = LANG.SettingsOption.DebugMode,
|
||||||
|
tooltip = LANG.SettingsOption.DebugModeTooltip,
|
||||||
|
getFunc = function() return AchievementInfo.settingGet("devDebug") end,
|
||||||
|
setFunc = function() AchievementInfo.settingToogle("devDebug") end,
|
||||||
|
warning = LANG.SettingsOption.DebugModeWarning
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Register
|
||||||
|
LAM:RegisterAddonPanel(AchievementInfo.name.."SettingsPanel", panelData)
|
||||||
|
LAM:RegisterOptionControls(AchievementInfo.name.."SettingsPanel", optionsTable)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Function to retrieve settings
|
||||||
|
function AchievementInfo.settingGet(id)
|
||||||
|
if AchievementInfo.savedVars[id] == nil then
|
||||||
|
AchievementInfo.savedVars[id] = false
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
return AchievementInfo.savedVars[id]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Function to toggle Checkbox values
|
||||||
|
function AchievementInfo.settingToogle(id)
|
||||||
|
if AchievementInfo.savedVars[id] == false then
|
||||||
|
AchievementInfo.savedVars[id] = true
|
||||||
|
else
|
||||||
|
AchievementInfo.savedVars[id] = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Function to set settings
|
||||||
|
function AchievementInfo.settingSet(id, value)
|
||||||
|
AchievementInfo.savedVars[id] = value
|
||||||
|
end
|
25
Libs/LibAddonMenu-2.0.txt
Normal file
25
Libs/LibAddonMenu-2.0.txt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
## APIVersion: 100011
|
||||||
|
## Title: LibAddonMenu-2.0
|
||||||
|
## Version: 2.0 r18
|
||||||
|
## Author: Seerah, sirinsidiator, et al.
|
||||||
|
## Contributors: votan, merlight, Garkin
|
||||||
|
## Description: A library to aid in the creation of option panels.
|
||||||
|
|
||||||
|
|
||||||
|
LibStub\LibStub.lua
|
||||||
|
|
||||||
|
LibAddonMenu-2.0\LibAddonMenu-2.0.lua
|
||||||
|
|
||||||
|
LibAddonMenu-2.0\controls\panel.lua
|
||||||
|
LibAddonMenu-2.0\controls\submenu.lua
|
||||||
|
LibAddonMenu-2.0\controls\button.lua
|
||||||
|
LibAddonMenu-2.0\controls\checkbox.lua
|
||||||
|
LibAddonMenu-2.0\controls\colorpicker.lua
|
||||||
|
LibAddonMenu-2.0\controls\custom.lua
|
||||||
|
LibAddonMenu-2.0\controls\description.lua
|
||||||
|
LibAddonMenu-2.0\controls\dropdown.lua
|
||||||
|
LibAddonMenu-2.0\controls\editbox.lua
|
||||||
|
LibAddonMenu-2.0\controls\header.lua
|
||||||
|
LibAddonMenu-2.0\controls\slider.lua
|
||||||
|
LibAddonMenu-2.0\controls\texture.lua
|
||||||
|
LibAddonMenu-2.0\controls\iconpicker.lua
|
201
Libs/LibAddonMenu-2.0/LICENSE
Normal file
201
Libs/LibAddonMenu-2.0/LICENSE
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
The Artistic License 2.0
|
||||||
|
|
||||||
|
Copyright (c) 2015 Ryan Lakanen (Seerah)
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
This license establishes the terms under which a given free software
|
||||||
|
Package may be copied, modified, distributed, and/or redistributed.
|
||||||
|
The intent is that the Copyright Holder maintains some artistic
|
||||||
|
control over the development of that Package while still keeping the
|
||||||
|
Package available as open source and free software.
|
||||||
|
|
||||||
|
You are always permitted to make arrangements wholly outside of this
|
||||||
|
license directly with the Copyright Holder of a given Package. If the
|
||||||
|
terms of this license do not permit the full use that you propose to
|
||||||
|
make of the Package, you should contact the Copyright Holder and seek
|
||||||
|
a different licensing arrangement.
|
||||||
|
|
||||||
|
Definitions
|
||||||
|
|
||||||
|
"Copyright Holder" means the individual(s) or organization(s)
|
||||||
|
named in the copyright notice for the entire Package.
|
||||||
|
|
||||||
|
"Contributor" means any party that has contributed code or other
|
||||||
|
material to the Package, in accordance with the Copyright Holder's
|
||||||
|
procedures.
|
||||||
|
|
||||||
|
"You" and "your" means any person who would like to copy,
|
||||||
|
distribute, or modify the Package.
|
||||||
|
|
||||||
|
"Package" means the collection of files distributed by the
|
||||||
|
Copyright Holder, and derivatives of that collection and/or of
|
||||||
|
those files. A given Package may consist of either the Standard
|
||||||
|
Version, or a Modified Version.
|
||||||
|
|
||||||
|
"Distribute" means providing a copy of the Package or making it
|
||||||
|
accessible to anyone else, or in the case of a company or
|
||||||
|
organization, to others outside of your company or organization.
|
||||||
|
|
||||||
|
"Distributor Fee" means any fee that you charge for Distributing
|
||||||
|
this Package or providing support for this Package to another
|
||||||
|
party. It does not mean licensing fees.
|
||||||
|
|
||||||
|
"Standard Version" refers to the Package if it has not been
|
||||||
|
modified, or has been modified only in ways explicitly requested
|
||||||
|
by the Copyright Holder.
|
||||||
|
|
||||||
|
"Modified Version" means the Package, if it has been changed, and
|
||||||
|
such changes were not explicitly requested by the Copyright
|
||||||
|
Holder.
|
||||||
|
|
||||||
|
"Original License" means this Artistic License as Distributed with
|
||||||
|
the Standard Version of the Package, in its current version or as
|
||||||
|
it may be modified by The Perl Foundation in the future.
|
||||||
|
|
||||||
|
"Source" form means the source code, documentation source, and
|
||||||
|
configuration files for the Package.
|
||||||
|
|
||||||
|
"Compiled" form means the compiled bytecode, object code, binary,
|
||||||
|
or any other form resulting from mechanical transformation or
|
||||||
|
translation of the Source form.
|
||||||
|
|
||||||
|
|
||||||
|
Permission for Use and Modification Without Distribution
|
||||||
|
|
||||||
|
(1) You are permitted to use the Standard Version and create and use
|
||||||
|
Modified Versions for any purpose without restriction, provided that
|
||||||
|
you do not Distribute the Modified Version.
|
||||||
|
|
||||||
|
|
||||||
|
Permissions for Redistribution of the Standard Version
|
||||||
|
|
||||||
|
(2) You may Distribute verbatim copies of the Source form of the
|
||||||
|
Standard Version of this Package in any medium without restriction,
|
||||||
|
either gratis or for a Distributor Fee, provided that you duplicate
|
||||||
|
all of the original copyright notices and associated disclaimers. At
|
||||||
|
your discretion, such verbatim copies may or may not include a
|
||||||
|
Compiled form of the Package.
|
||||||
|
|
||||||
|
(3) You may apply any bug fixes, portability changes, and other
|
||||||
|
modifications made available from the Copyright Holder. The resulting
|
||||||
|
Package will still be considered the Standard Version, and as such
|
||||||
|
will be subject to the Original License.
|
||||||
|
|
||||||
|
|
||||||
|
Distribution of Modified Versions of the Package as Source
|
||||||
|
|
||||||
|
(4) You may Distribute your Modified Version as Source (either gratis
|
||||||
|
or for a Distributor Fee, and with or without a Compiled form of the
|
||||||
|
Modified Version) provided that you clearly document how it differs
|
||||||
|
from the Standard Version, including, but not limited to, documenting
|
||||||
|
any non-standard features, executables, or modules, and provided that
|
||||||
|
you do at least ONE of the following:
|
||||||
|
|
||||||
|
(a) make the Modified Version available to the Copyright Holder
|
||||||
|
of the Standard Version, under the Original License, so that the
|
||||||
|
Copyright Holder may include your modifications in the Standard
|
||||||
|
Version.
|
||||||
|
|
||||||
|
(b) ensure that installation of your Modified Version does not
|
||||||
|
prevent the user installing or running the Standard Version. In
|
||||||
|
addition, the Modified Version must bear a name that is different
|
||||||
|
from the name of the Standard Version.
|
||||||
|
|
||||||
|
(c) allow anyone who receives a copy of the Modified Version to
|
||||||
|
make the Source form of the Modified Version available to others
|
||||||
|
under
|
||||||
|
|
||||||
|
(i) the Original License or
|
||||||
|
|
||||||
|
(ii) a license that permits the licensee to freely copy,
|
||||||
|
modify and redistribute the Modified Version using the same
|
||||||
|
licensing terms that apply to the copy that the licensee
|
||||||
|
received, and requires that the Source form of the Modified
|
||||||
|
Version, and of any works derived from it, be made freely
|
||||||
|
available in that license fees are prohibited but Distributor
|
||||||
|
Fees are allowed.
|
||||||
|
|
||||||
|
|
||||||
|
Distribution of Compiled Forms of the Standard Version
|
||||||
|
or Modified Versions without the Source
|
||||||
|
|
||||||
|
(5) You may Distribute Compiled forms of the Standard Version without
|
||||||
|
the Source, provided that you include complete instructions on how to
|
||||||
|
get the Source of the Standard Version. Such instructions must be
|
||||||
|
valid at the time of your distribution. If these instructions, at any
|
||||||
|
time while you are carrying out such distribution, become invalid, you
|
||||||
|
must provide new instructions on demand or cease further distribution.
|
||||||
|
If you provide valid instructions or cease distribution within thirty
|
||||||
|
days after you become aware that the instructions are invalid, then
|
||||||
|
you do not forfeit any of your rights under this license.
|
||||||
|
|
||||||
|
(6) You may Distribute a Modified Version in Compiled form without
|
||||||
|
the Source, provided that you comply with Section 4 with respect to
|
||||||
|
the Source of the Modified Version.
|
||||||
|
|
||||||
|
|
||||||
|
Aggregating or Linking the Package
|
||||||
|
|
||||||
|
(7) You may aggregate the Package (either the Standard Version or
|
||||||
|
Modified Version) with other packages and Distribute the resulting
|
||||||
|
aggregation provided that you do not charge a licensing fee for the
|
||||||
|
Package. Distributor Fees are permitted, and licensing fees for other
|
||||||
|
components in the aggregation are permitted. The terms of this license
|
||||||
|
apply to the use and Distribution of the Standard or Modified Versions
|
||||||
|
as included in the aggregation.
|
||||||
|
|
||||||
|
(8) You are permitted to link Modified and Standard Versions with
|
||||||
|
other works, to embed the Package in a larger work of your own, or to
|
||||||
|
build stand-alone binary or bytecode versions of applications that
|
||||||
|
include the Package, and Distribute the result without restriction,
|
||||||
|
provided the result does not expose a direct interface to the Package.
|
||||||
|
|
||||||
|
|
||||||
|
Items That are Not Considered Part of a Modified Version
|
||||||
|
|
||||||
|
(9) Works (including, but not limited to, modules and scripts) that
|
||||||
|
merely extend or make use of the Package, do not, by themselves, cause
|
||||||
|
the Package to be a Modified Version. In addition, such works are not
|
||||||
|
considered parts of the Package itself, and are not subject to the
|
||||||
|
terms of this license.
|
||||||
|
|
||||||
|
|
||||||
|
General Provisions
|
||||||
|
|
||||||
|
(10) Any use, modification, and distribution of the Standard or
|
||||||
|
Modified Versions is governed by this Artistic License. By using,
|
||||||
|
modifying or distributing the Package, you accept this license. Do not
|
||||||
|
use, modify, or distribute the Package, if you do not accept this
|
||||||
|
license.
|
||||||
|
|
||||||
|
(11) If your Modified Version has been derived from a Modified
|
||||||
|
Version made by someone other than you, you are nevertheless required
|
||||||
|
to ensure that your Modified Version complies with the requirements of
|
||||||
|
this license.
|
||||||
|
|
||||||
|
(12) This license does not grant you the right to use any trademark,
|
||||||
|
service mark, tradename, or logo of the Copyright Holder.
|
||||||
|
|
||||||
|
(13) This license includes the non-exclusive, worldwide,
|
||||||
|
free-of-charge patent license to make, have made, use, offer to sell,
|
||||||
|
sell, import and otherwise transfer the Package with respect to any
|
||||||
|
patent claims licensable by the Copyright Holder that are necessarily
|
||||||
|
infringed by the Package. If you institute patent litigation
|
||||||
|
(including a cross-claim or counterclaim) against any party alleging
|
||||||
|
that the Package constitutes direct or contributory patent
|
||||||
|
infringement, then this Artistic License to you shall terminate on the
|
||||||
|
date that such litigation is filed.
|
||||||
|
|
||||||
|
(14) Disclaimer of Warranty:
|
||||||
|
THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
|
||||||
|
IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
||||||
|
NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL
|
||||||
|
LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL
|
||||||
|
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
809
Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
Normal file
809
Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua
Normal file
@ -0,0 +1,809 @@
|
|||||||
|
-- LibAddonMenu-2.0 & its files © Ryan Lakanen (Seerah) --
|
||||||
|
-- Distributed under The Artistic License 2.0 (see LICENSE) --
|
||||||
|
------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
--Register LAM with LibStub
|
||||||
|
local MAJOR, MINOR = "LibAddonMenu-2.0", 18
|
||||||
|
local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
|
||||||
|
if not lam then return end --the same or newer version of this lib is already loaded into memory
|
||||||
|
|
||||||
|
local messages = {}
|
||||||
|
local MESSAGE_PREFIX = "[LAM2] "
|
||||||
|
local function PrintLater(msg)
|
||||||
|
if CHAT_SYSTEM.primaryContainer then
|
||||||
|
d(MESSAGE_PREFIX .. msg)
|
||||||
|
else
|
||||||
|
messages[#messages + 1] = msg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function FlushMessages()
|
||||||
|
for i = 1, #messages do
|
||||||
|
d(MESSAGE_PREFIX .. messages[i])
|
||||||
|
end
|
||||||
|
messages = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
if LAMSettingsPanelCreated and not LAMCompatibilityWarning then
|
||||||
|
PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com")
|
||||||
|
LAMCompatibilityWarning = true
|
||||||
|
end
|
||||||
|
|
||||||
|
--UPVALUES--
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
local em = EVENT_MANAGER
|
||||||
|
local sm = SCENE_MANAGER
|
||||||
|
local cm = CALLBACK_MANAGER
|
||||||
|
local tconcat = table.concat
|
||||||
|
local tinsert = table.insert
|
||||||
|
|
||||||
|
local addonsForList = {}
|
||||||
|
local addonToOptionsMap = {}
|
||||||
|
local optionsCreated = {}
|
||||||
|
lam.widgets = lam.widgets or {}
|
||||||
|
local widgets = lam.widgets
|
||||||
|
lam.util = {}
|
||||||
|
local util = lam.util
|
||||||
|
|
||||||
|
local function GetTooltipText(tooltip)
|
||||||
|
if type(tooltip) == "string" then
|
||||||
|
return tooltip
|
||||||
|
elseif type(tooltip) == "function" then
|
||||||
|
return tostring(tooltip())
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function CreateBaseControl(parent, controlData, controlName)
|
||||||
|
local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL)
|
||||||
|
control.panel = parent.panel or parent -- if this is in a submenu, panel is the submenu's parent
|
||||||
|
control.data = controlData
|
||||||
|
|
||||||
|
control.isHalfWidth = controlData.width == "half"
|
||||||
|
control:SetWidth(control.panel:GetWidth() - 60)
|
||||||
|
return control
|
||||||
|
end
|
||||||
|
|
||||||
|
local MIN_HEIGHT = 26
|
||||||
|
local HALF_WIDTH_LINE_SPACING = 2
|
||||||
|
local function CreateLabelAndContainerControl(parent, controlData, controlName)
|
||||||
|
local control = CreateBaseControl(parent, controlData, controlName)
|
||||||
|
local width = control:GetWidth()
|
||||||
|
|
||||||
|
local container = wm:CreateControl(nil, control, CT_CONTROL)
|
||||||
|
container:SetDimensions(width / 3, MIN_HEIGHT)
|
||||||
|
control.container = container
|
||||||
|
|
||||||
|
local label = wm:CreateControl(nil, control, CT_LABEL)
|
||||||
|
label:SetFont("ZoFontWinH4")
|
||||||
|
label:SetHeight(MIN_HEIGHT)
|
||||||
|
label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
|
||||||
|
label:SetText(controlData.name)
|
||||||
|
control.label = label
|
||||||
|
|
||||||
|
if control.isHalfWidth then
|
||||||
|
control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING)
|
||||||
|
label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0)
|
||||||
|
label:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0)
|
||||||
|
container:SetAnchor(TOPRIGHT, control.label, BOTTOMRIGHT, 0, HALF_WIDTH_LINE_SPACING)
|
||||||
|
else
|
||||||
|
control:SetDimensions(width, MIN_HEIGHT)
|
||||||
|
container:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0)
|
||||||
|
label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0)
|
||||||
|
label:SetAnchor(TOPRIGHT, container, TOPLEFT, 5, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
control.data.tooltipText = GetTooltipText(control.data.tooltip)
|
||||||
|
control:SetMouseEnabled(true)
|
||||||
|
control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
|
||||||
|
control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
|
||||||
|
return control
|
||||||
|
end
|
||||||
|
|
||||||
|
util.GetTooltipText = GetTooltipText
|
||||||
|
util.CreateBaseControl = CreateBaseControl
|
||||||
|
util.CreateLabelAndContainerControl = CreateLabelAndContainerControl
|
||||||
|
|
||||||
|
local ADDON_DATA_TYPE = 1
|
||||||
|
local RESELECTING_DURING_REBUILD = true
|
||||||
|
local USER_REQUESTED_OPEN = true
|
||||||
|
|
||||||
|
|
||||||
|
--INTERNAL FUNCTION
|
||||||
|
--scrolls ZO_ScrollList `list` to move the row corresponding to `data`
|
||||||
|
-- into view (does nothing if there is no such row in the list)
|
||||||
|
--unlike ZO_ScrollList_ScrollDataIntoView, this function accounts for
|
||||||
|
-- fading near the list's edges - it avoids the fading area by scrolling
|
||||||
|
-- a little further than the ZO function
|
||||||
|
local function ScrollDataIntoView(list, data)
|
||||||
|
local targetIndex = data.sortIndex
|
||||||
|
if not targetIndex then return end
|
||||||
|
|
||||||
|
local scrollMin, scrollMax = list.scrollbar:GetMinMax()
|
||||||
|
local scrollTop = list.scrollbar:GetValue()
|
||||||
|
local controlHeight = list.controlHeight
|
||||||
|
local targetMin = controlHeight * (targetIndex - 1) - 64
|
||||||
|
-- subtracting 64 ain't arbitrary, it's the maximum fading height
|
||||||
|
-- (libraries/zo_templates/scrolltemplates.lua/UpdateScrollFade)
|
||||||
|
|
||||||
|
if targetMin < scrollTop then
|
||||||
|
ZO_ScrollList_ScrollAbsolute(list, zo_max(targetMin, scrollMin))
|
||||||
|
else
|
||||||
|
local listHeight = ZO_ScrollList_GetHeight(list)
|
||||||
|
local targetMax = controlHeight * targetIndex + 64 - listHeight
|
||||||
|
|
||||||
|
if targetMax > scrollTop then
|
||||||
|
ZO_ScrollList_ScrollAbsolute(list, zo_min(targetMax, scrollMax))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--INTERNAL FUNCTION
|
||||||
|
--constructs a string pattern from the text in `searchEdit` control
|
||||||
|
-- * metacharacters are escaped, losing their special meaning
|
||||||
|
-- * whitespace matches anything (including empty substring)
|
||||||
|
--if there is nothing but whitespace, returns nil
|
||||||
|
--otherwise returns a filter function, which takes a `data` table argument
|
||||||
|
-- and returns true iff `data.filterText` matches the pattern
|
||||||
|
local function GetSearchFilterFunc(searchEdit)
|
||||||
|
local text = searchEdit:GetText():lower()
|
||||||
|
local pattern = text:match("(%S+.-)%s*$")
|
||||||
|
|
||||||
|
if not pattern then -- nothing but whitespace
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de"
|
||||||
|
pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0")
|
||||||
|
|
||||||
|
-- replace whitespace with "match shortest anything"
|
||||||
|
pattern = pattern:gsub("%s+", ".-")
|
||||||
|
|
||||||
|
return function(data)
|
||||||
|
return data.filterText:lower():find(pattern) ~= nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--INTERNAL FUNCTION
|
||||||
|
--populates `addonList` with entries from `addonsForList`
|
||||||
|
-- addonList = ZO_ScrollList control
|
||||||
|
-- filter = [optional] function(data)
|
||||||
|
local function PopulateAddonList(addonList, filter)
|
||||||
|
local entryList = ZO_ScrollList_GetDataList(addonList)
|
||||||
|
local numEntries = 0
|
||||||
|
local selectedData = nil
|
||||||
|
|
||||||
|
ZO_ScrollList_Clear(addonList)
|
||||||
|
|
||||||
|
for i, data in ipairs(addonsForList) do
|
||||||
|
if not filter or filter(data) then
|
||||||
|
local dataEntry = ZO_ScrollList_CreateDataEntry(ADDON_DATA_TYPE, data)
|
||||||
|
numEntries = numEntries + 1
|
||||||
|
data.sortIndex = numEntries
|
||||||
|
entryList[numEntries] = dataEntry
|
||||||
|
-- select the first panel passing the filter, or the currently
|
||||||
|
-- shown panel, but only if it passes the filter as well
|
||||||
|
if selectedData == nil or data.panel == lam.currentAddonPanel then
|
||||||
|
selectedData = data
|
||||||
|
end
|
||||||
|
else
|
||||||
|
data.sortIndex = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ZO_ScrollList_Commit(addonList)
|
||||||
|
|
||||||
|
if selectedData then
|
||||||
|
if selectedData.panel == lam.currentAddonPanel then
|
||||||
|
ZO_ScrollList_SelectData(addonList, selectedData, nil, RESELECTING_DURING_REBUILD)
|
||||||
|
else
|
||||||
|
ZO_ScrollList_SelectData(addonList, selectedData, nil)
|
||||||
|
end
|
||||||
|
ScrollDataIntoView(addonList, selectedData)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--METHOD: REGISTER WIDGET--
|
||||||
|
--each widget has its version checked before loading,
|
||||||
|
--so we only have the most recent one in memory
|
||||||
|
--Usage:
|
||||||
|
-- widgetType = "string"; the type of widget being registered
|
||||||
|
-- widgetVersion = integer; the widget's version number
|
||||||
|
LAMCreateControl = LAMCreateControl or {}
|
||||||
|
local lamcc = LAMCreateControl
|
||||||
|
|
||||||
|
function lam:RegisterWidget(widgetType, widgetVersion)
|
||||||
|
if widgets[widgetType] and widgets[widgetType] >= widgetVersion then
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
widgets[widgetType] = widgetVersion
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--METHOD: OPEN TO ADDON PANEL--
|
||||||
|
--opens to a specific addon's option panel
|
||||||
|
--Usage:
|
||||||
|
-- panel = userdata; the panel returned by the :RegisterOptionsPanel method
|
||||||
|
local locSettings = GetString(SI_GAME_MENU_SETTINGS)
|
||||||
|
function lam:OpenToPanel(panel)
|
||||||
|
|
||||||
|
-- find and select the panel's row in addon list
|
||||||
|
|
||||||
|
local addonList = lam.addonList
|
||||||
|
local selectedData = nil
|
||||||
|
|
||||||
|
for _, addonData in ipairs(addonsForList) do
|
||||||
|
if addonData.panel == panel then
|
||||||
|
selectedData = addonData
|
||||||
|
ScrollDataIntoView(addonList, selectedData)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ZO_ScrollList_SelectData(addonList, selectedData)
|
||||||
|
ZO_ScrollList_RefreshVisible(addonList, selectedData)
|
||||||
|
|
||||||
|
local srchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit")
|
||||||
|
srchEdit:Clear()
|
||||||
|
|
||||||
|
-- note that ZO_ScrollList doesn't require `selectedData` to be actually
|
||||||
|
-- present in the list, and that the list will only be populated once LAM
|
||||||
|
-- "Addon Settings" menu entry is selected for the first time
|
||||||
|
|
||||||
|
local function openAddonSettingsMenu()
|
||||||
|
local gameMenu = ZO_GameMenu_InGame.gameMenu
|
||||||
|
local settingsMenu = gameMenu.headerControls[locSettings]
|
||||||
|
|
||||||
|
if settingsMenu then -- an instance of ZO_TreeNode
|
||||||
|
local children = settingsMenu:GetChildren()
|
||||||
|
for i = 1, (children and #children or 0) do
|
||||||
|
local childNode = children[i]
|
||||||
|
local data = childNode:GetData()
|
||||||
|
if data and data.id == lam.panelId then
|
||||||
|
-- found LAM "Addon Settings" node, yay!
|
||||||
|
childNode:GetTree():SelectNode(childNode)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if sm:GetScene("gameMenuInGame"):GetState() == SCENE_SHOWN then
|
||||||
|
openAddonSettingsMenu()
|
||||||
|
else
|
||||||
|
sm:CallWhen("gameMenuInGame", SCENE_SHOWN, openAddonSettingsMenu)
|
||||||
|
sm:Show("gameMenuInGame")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--INTERNAL FUNCTION
|
||||||
|
--creates controls when options panel is first shown
|
||||||
|
--controls anchoring of these controls in the panel
|
||||||
|
local function CreateOptionsControls(panel)
|
||||||
|
local addonID = panel:GetName()
|
||||||
|
local optionsTable = addonToOptionsMap[addonID]
|
||||||
|
|
||||||
|
if optionsTable then
|
||||||
|
local function CreateAndAnchorWidget(parent, widgetData, offsetX, offsetY, anchorTarget, wasHalf)
|
||||||
|
local widget
|
||||||
|
local status, err = pcall(function() widget = LAMCreateControl[widgetData.type](parent, widgetData) end)
|
||||||
|
if not status then
|
||||||
|
return err or true, offsetY, anchorTarget, wasHalf
|
||||||
|
else
|
||||||
|
local isHalf = (widgetData.width == "half")
|
||||||
|
if not anchorTarget then -- the first widget in a panel is just placed in the top left corner
|
||||||
|
widget:SetAnchor(TOPLEFT)
|
||||||
|
anchorTarget = widget
|
||||||
|
elseif wasHalf and isHalf then -- when the previous widget was only half width and this one is too, we place it on the right side
|
||||||
|
widget:SetAnchor(TOPLEFT, anchorTarget, TOPRIGHT, 5 + (offsetX or 0), 0)
|
||||||
|
widget.lineControl = anchorTarget
|
||||||
|
offsetY = zo_max(0, widget:GetHeight() - anchorTarget:GetHeight()) -- we need to get the common height of both widgets to know where the next row starts
|
||||||
|
isHalf = false
|
||||||
|
else -- otherwise we just put it below the previous one normally
|
||||||
|
widget:SetAnchor(TOPLEFT, anchorTarget, BOTTOMLEFT, 0, 15 + offsetY)
|
||||||
|
offsetY = 0
|
||||||
|
anchorTarget = widget
|
||||||
|
end
|
||||||
|
return false, offsetY, anchorTarget, isHalf
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local THROTTLE_TIMEOUT, THROTTLE_COUNT = 10, 20
|
||||||
|
local fifo = {}
|
||||||
|
local anchorOffset, lastAddedControl, wasHalf
|
||||||
|
local CreateWidgetsInPanel, err
|
||||||
|
|
||||||
|
local function PrepareForNextPanel()
|
||||||
|
anchorOffset, lastAddedControl, wasHalf = 0, nil, false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SetupCreationCalls(parent, widgetDataTable)
|
||||||
|
fifo[#fifo + 1] = PrepareForNextPanel
|
||||||
|
local count = #widgetDataTable
|
||||||
|
for i = 1, count, THROTTLE_COUNT do
|
||||||
|
fifo[#fifo + 1] = function()
|
||||||
|
CreateWidgetsInPanel(parent, widgetDataTable, i, zo_min(i + THROTTLE_COUNT - 1, count))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return count ~= NonContiguousCount(widgetDataTable)
|
||||||
|
end
|
||||||
|
|
||||||
|
CreateWidgetsInPanel = function(parent, widgetDataTable, startIndex, endIndex)
|
||||||
|
for i=startIndex,endIndex do
|
||||||
|
local widgetData = widgetDataTable[i]
|
||||||
|
if not widgetData then
|
||||||
|
PrintLater("Skipped creation of missing entry in the settings menu of " .. addonID .. ".")
|
||||||
|
else
|
||||||
|
local widgetType = widgetData.type
|
||||||
|
local offsetX = 0
|
||||||
|
local isSubmenu = (widgetType == "submenu")
|
||||||
|
if isSubmenu then
|
||||||
|
wasHalf = false
|
||||||
|
offsetX = 5
|
||||||
|
end
|
||||||
|
|
||||||
|
err, anchorOffset, lastAddedControl, wasHalf = CreateAndAnchorWidget(parent, widgetData, offsetX, anchorOffset, lastAddedControl, wasHalf)
|
||||||
|
if err then
|
||||||
|
PrintLater(("Could not create %s '%s' of %s."):format(widgetData.type, widgetData.name or "unnamed", addonID))
|
||||||
|
end
|
||||||
|
|
||||||
|
if isSubmenu then
|
||||||
|
if SetupCreationCalls(lastAddedControl, widgetData.controls) then
|
||||||
|
PrintLater(("The sub menu '%s' of %s is missing some entries."):format(widgetData.name or "unnamed", addonID))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function DoCreateSettings()
|
||||||
|
if #fifo > 0 then
|
||||||
|
local nextCall = table.remove(fifo, 1)
|
||||||
|
nextCall()
|
||||||
|
if(nextCall == PrepareForNextPanel) then
|
||||||
|
DoCreateSettings()
|
||||||
|
else
|
||||||
|
zo_callLater(DoCreateSettings, THROTTLE_TIMEOUT)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
optionsCreated[addonID] = true
|
||||||
|
cm:FireCallbacks("LAM-PanelControlsCreated", panel)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if SetupCreationCalls(panel, optionsTable) then
|
||||||
|
PrintLater(("The settings menu of %s is missing some entries."):format(addonID))
|
||||||
|
end
|
||||||
|
DoCreateSettings()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--INTERNAL FUNCTION
|
||||||
|
--handles switching between panels
|
||||||
|
local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel
|
||||||
|
local currentlySelected = lam.currentAddonPanel
|
||||||
|
if currentlySelected and currentlySelected ~= panel then
|
||||||
|
currentlySelected:SetHidden(true)
|
||||||
|
end
|
||||||
|
lam.currentAddonPanel = panel
|
||||||
|
|
||||||
|
-- refresh visible rows to reflect panel IsHidden status
|
||||||
|
ZO_ScrollList_RefreshVisible(lam.addonList)
|
||||||
|
|
||||||
|
if not optionsCreated[panel:GetName()] then --if this is the first time opening this panel, create these options
|
||||||
|
CreateOptionsControls(panel)
|
||||||
|
end
|
||||||
|
|
||||||
|
cm:FireCallbacks("LAM-RefreshPanel", panel)
|
||||||
|
end
|
||||||
|
|
||||||
|
local CheckSafetyAndInitialize
|
||||||
|
|
||||||
|
--METHOD: REGISTER ADDON PANEL
|
||||||
|
--registers your addon with LibAddonMenu and creates a panel
|
||||||
|
--Usage:
|
||||||
|
-- addonID = "string"; unique ID which will be the global name of your panel
|
||||||
|
-- panelData = table; data object for your panel - see controls\panel.lua
|
||||||
|
function lam:RegisterAddonPanel(addonID, panelData)
|
||||||
|
CheckSafetyAndInitialize(addonID)
|
||||||
|
local container = lam:GetAddonPanelContainer()
|
||||||
|
local panel = lamcc.panel(container, panelData, addonID) --addonID==global name of panel
|
||||||
|
panel:SetHidden(true)
|
||||||
|
panel:SetAnchorFill(container)
|
||||||
|
panel:SetHandler("OnShow", ToggleAddonPanels)
|
||||||
|
|
||||||
|
local function stripMarkup(str)
|
||||||
|
return str:gsub("|[Cc]%x%x%x%x%x%x", ""):gsub("|[Rr]", "")
|
||||||
|
end
|
||||||
|
|
||||||
|
local filterParts = {panelData.name, nil, nil}
|
||||||
|
-- append keywords and author separately, the may be nil
|
||||||
|
filterParts[#filterParts + 1] = panelData.keywords
|
||||||
|
filterParts[#filterParts + 1] = panelData.author
|
||||||
|
|
||||||
|
local addonData = {
|
||||||
|
panel = panel,
|
||||||
|
name = stripMarkup(panelData.name),
|
||||||
|
filterText = stripMarkup(tconcat(filterParts, "\t")):lower(),
|
||||||
|
}
|
||||||
|
|
||||||
|
tinsert(addonsForList, addonData)
|
||||||
|
|
||||||
|
if panelData.slashCommand then
|
||||||
|
SLASH_COMMANDS[panelData.slashCommand] = function()
|
||||||
|
lam:OpenToPanel(panel)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return panel --return for authors creating options manually
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--METHOD: REGISTER OPTION CONTROLS
|
||||||
|
--registers the options you want shown for your addon
|
||||||
|
--these are stored in a table where each key-value pair is the order
|
||||||
|
--of the options in the panel and the data for that control, respectively
|
||||||
|
--see exampleoptions.lua for an example
|
||||||
|
--see controls\<widget>.lua for each widget type
|
||||||
|
--Usage:
|
||||||
|
-- addonID = "string"; the same string passed to :RegisterAddonPanel
|
||||||
|
-- optionsTable = table; the table containing all of the options controls and their data
|
||||||
|
function lam:RegisterOptionControls(addonID, optionsTable) --optionsTable = {sliderData, buttonData, etc}
|
||||||
|
addonToOptionsMap[addonID] = optionsTable
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--INTERNAL FUNCTION
|
||||||
|
--creates LAM's Addon Settings entry in ZO_GameMenu
|
||||||
|
local function CreateAddonSettingsMenuEntry()
|
||||||
|
--Russian for TERAB1T's RuESO addon, which creates an "ru" locale
|
||||||
|
--game font does not support Cyrillic, so they are using custom fonts + extended latin charset
|
||||||
|
--Spanish provided by Luisen75 for their translation project
|
||||||
|
local controlPanelNames = {
|
||||||
|
en = "Addon Settings",
|
||||||
|
fr = "Extensions",
|
||||||
|
de = "Erweiterungen",
|
||||||
|
ru = "Îacòpoéêè äoïoìîeîèé",
|
||||||
|
es = "Configura Addons",
|
||||||
|
}
|
||||||
|
|
||||||
|
local panelData = {
|
||||||
|
id = KEYBOARD_OPTIONS.currentPanelId,
|
||||||
|
name = controlPanelNames[GetCVar("Language.2")] or controlPanelNames["en"],
|
||||||
|
}
|
||||||
|
|
||||||
|
KEYBOARD_OPTIONS.currentPanelId = panelData.id + 1
|
||||||
|
KEYBOARD_OPTIONS.panelNames[panelData.id] = panelData.name
|
||||||
|
|
||||||
|
lam.panelId = panelData.id
|
||||||
|
|
||||||
|
local addonListSorted = false
|
||||||
|
|
||||||
|
function panelData.callback()
|
||||||
|
sm:AddFragment(lam:GetAddonSettingsFragment())
|
||||||
|
KEYBOARD_OPTIONS:ChangePanels(lam.panelId)
|
||||||
|
|
||||||
|
local title = LAMAddonSettingsWindow:GetNamedChild("Title")
|
||||||
|
title:SetText(panelData.name)
|
||||||
|
|
||||||
|
if not addonListSorted and #addonsForList > 0 then
|
||||||
|
local searchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit")
|
||||||
|
--we're about to show our list for the first time - let's sort it
|
||||||
|
table.sort(addonsForList, function(a, b) return a.name < b.name end)
|
||||||
|
PopulateAddonList(lam.addonList, GetSearchFilterFunc(searchEdit))
|
||||||
|
addonListSorted = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function panelData.unselectedCallback()
|
||||||
|
sm:RemoveFragment(lam:GetAddonSettingsFragment())
|
||||||
|
if SetCameraOptionsPreviewModeEnabled then -- available since API version 100011
|
||||||
|
SetCameraOptionsPreviewModeEnabled(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ZO_GameMenu_AddSettingPanel(panelData)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--INTERNAL FUNCTION
|
||||||
|
--creates the left-hand menu in LAM's window
|
||||||
|
local function CreateAddonList(name, parent)
|
||||||
|
local addonList = wm:CreateControlFromVirtual(name, parent, "ZO_ScrollList")
|
||||||
|
|
||||||
|
local function addonListRow_OnMouseDown(control, button)
|
||||||
|
if button == 1 then
|
||||||
|
local data = ZO_ScrollList_GetData(control)
|
||||||
|
ZO_ScrollList_SelectData(addonList, data, control)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function addonListRow_OnMouseEnter(control)
|
||||||
|
ZO_ScrollList_MouseEnter(addonList, control)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function addonListRow_OnMouseExit(control)
|
||||||
|
ZO_ScrollList_MouseExit(addonList, control)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function addonListRow_Select(previouslySelectedData, selectedData, reselectingDuringRebuild)
|
||||||
|
if not reselectingDuringRebuild then
|
||||||
|
if previouslySelectedData then
|
||||||
|
previouslySelectedData.panel:SetHidden(true)
|
||||||
|
end
|
||||||
|
if selectedData then
|
||||||
|
selectedData.panel:SetHidden(false)
|
||||||
|
PlaySound(SOUNDS.MENU_SUBCATEGORY_SELECTION)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function addonListRow_Setup(control, data)
|
||||||
|
control:SetText(data.name)
|
||||||
|
control:SetSelected(not data.panel:IsHidden())
|
||||||
|
end
|
||||||
|
|
||||||
|
ZO_ScrollList_AddDataType(addonList, ADDON_DATA_TYPE, "ZO_SelectableLabel", 28, addonListRow_Setup)
|
||||||
|
-- I don't know how to make highlights clear properly; they often
|
||||||
|
-- get stuck and after a while the list is full of highlighted rows
|
||||||
|
--ZO_ScrollList_EnableHighlight(addonList, "ZO_ThinListHighlight")
|
||||||
|
ZO_ScrollList_EnableSelection(addonList, "ZO_ThinListHighlight", addonListRow_Select)
|
||||||
|
|
||||||
|
local addonDataType = ZO_ScrollList_GetDataTypeTable(addonList, ADDON_DATA_TYPE)
|
||||||
|
local addonListRow_CreateRaw = addonDataType.pool.m_Factory
|
||||||
|
|
||||||
|
local function addonListRow_Create(pool)
|
||||||
|
local control = addonListRow_CreateRaw(pool)
|
||||||
|
control:SetHandler("OnMouseDown", addonListRow_OnMouseDown)
|
||||||
|
--control:SetHandler("OnMouseEnter", addonListRow_OnMouseEnter)
|
||||||
|
--control:SetHandler("OnMouseExit", addonListRow_OnMouseExit)
|
||||||
|
control:SetHeight(28)
|
||||||
|
control:SetFont("ZoFontHeader")
|
||||||
|
control:SetHorizontalAlignment(TEXT_ALIGN_LEFT)
|
||||||
|
control:SetVerticalAlignment(TEXT_ALIGN_CENTER)
|
||||||
|
control:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
|
||||||
|
return control
|
||||||
|
end
|
||||||
|
|
||||||
|
addonDataType.pool.m_Factory = addonListRow_Create
|
||||||
|
|
||||||
|
return addonList
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--INTERNAL FUNCTION
|
||||||
|
local function CreateSearchFilterBox(name, parent)
|
||||||
|
local boxControl = wm:CreateControl(name, parent, CT_CONTROL)
|
||||||
|
|
||||||
|
local srchButton = wm:CreateControl("$(parent)Button", boxControl, CT_BUTTON)
|
||||||
|
srchButton:SetDimensions(32, 32)
|
||||||
|
srchButton:SetAnchor(LEFT, nil, LEFT, 2, 0)
|
||||||
|
srchButton:SetNormalTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_up.dds")
|
||||||
|
srchButton:SetPressedTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_down.dds")
|
||||||
|
srchButton:SetMouseOverTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_over.dds")
|
||||||
|
|
||||||
|
local srchEdit = wm:CreateControlFromVirtual("$(parent)Edit", boxControl, "ZO_DefaultEdit")
|
||||||
|
srchEdit:SetAnchor(LEFT, srchButton, RIGHT, 4, 1)
|
||||||
|
srchEdit:SetAnchor(RIGHT, nil, RIGHT, -4, 1)
|
||||||
|
srchEdit:SetColor(ZO_NORMAL_TEXT:UnpackRGBA())
|
||||||
|
|
||||||
|
local srchBg = wm:CreateControl("$(parent)Bg", boxControl, CT_BACKDROP)
|
||||||
|
srchBg:SetAnchorFill()
|
||||||
|
srchBg:SetAlpha(0)
|
||||||
|
srchBg:SetCenterColor(0, 0, 0, 0.5)
|
||||||
|
srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA())
|
||||||
|
srchBg:SetEdgeTexture("", 1, 1, 0, 0)
|
||||||
|
|
||||||
|
-- search backdrop should appear whenever you hover over either
|
||||||
|
-- the magnifying glass button or the edit field (which is only
|
||||||
|
-- visible when it contains some text), and also while the edit
|
||||||
|
-- field has keyboard focus
|
||||||
|
|
||||||
|
local srchActive = false
|
||||||
|
local srchHover = false
|
||||||
|
|
||||||
|
local function srchBgUpdateAlpha()
|
||||||
|
if srchActive or srchEdit:HasFocus() then
|
||||||
|
srchBg:SetAlpha(srchHover and 0.8 or 0.6)
|
||||||
|
else
|
||||||
|
srchBg:SetAlpha(srchHover and 0.6 or 0.0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function srchMouseEnter(control)
|
||||||
|
srchHover = true
|
||||||
|
srchBgUpdateAlpha()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function srchMouseExit(control)
|
||||||
|
srchHover = false
|
||||||
|
srchBgUpdateAlpha()
|
||||||
|
end
|
||||||
|
|
||||||
|
boxControl:SetMouseEnabled(true)
|
||||||
|
boxControl:SetHitInsets(1, 1, -1, -1)
|
||||||
|
boxControl:SetHandler("OnMouseEnter", srchMouseEnter)
|
||||||
|
boxControl:SetHandler("OnMouseExit", srchMouseExit)
|
||||||
|
|
||||||
|
srchButton:SetHandler("OnMouseEnter", srchMouseEnter)
|
||||||
|
srchButton:SetHandler("OnMouseExit", srchMouseExit)
|
||||||
|
|
||||||
|
local focusLostTime = 0
|
||||||
|
|
||||||
|
srchButton:SetHandler("OnClicked", function(self)
|
||||||
|
srchEdit:Clear()
|
||||||
|
if GetFrameTimeMilliseconds() - focusLostTime < 100 then
|
||||||
|
-- re-focus the edit box if it lost focus due to this
|
||||||
|
-- button click (note that this handler may run a few
|
||||||
|
-- frames later)
|
||||||
|
srchEdit:TakeFocus()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
srchEdit:SetHandler("OnMouseEnter", srchMouseEnter)
|
||||||
|
srchEdit:SetHandler("OnMouseExit", srchMouseExit)
|
||||||
|
srchEdit:SetHandler("OnFocusGained", srchBgUpdateAlpha)
|
||||||
|
|
||||||
|
srchEdit:SetHandler("OnFocusLost", function()
|
||||||
|
focusLostTime = GetFrameTimeMilliseconds()
|
||||||
|
srchBgUpdateAlpha()
|
||||||
|
end)
|
||||||
|
|
||||||
|
srchEdit:SetHandler("OnEscape", function(self)
|
||||||
|
self:Clear()
|
||||||
|
self:LoseFocus()
|
||||||
|
end)
|
||||||
|
|
||||||
|
srchEdit:SetHandler("OnTextChanged", function(self)
|
||||||
|
local filterFunc = GetSearchFilterFunc(self)
|
||||||
|
if filterFunc then
|
||||||
|
srchActive = true
|
||||||
|
srchBg:SetEdgeColor(ZO_SECOND_CONTRAST_TEXT:UnpackRGBA())
|
||||||
|
srchButton:SetState(BSTATE_PRESSED)
|
||||||
|
else
|
||||||
|
srchActive = false
|
||||||
|
srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA())
|
||||||
|
srchButton:SetState(BSTATE_NORMAL)
|
||||||
|
end
|
||||||
|
srchBgUpdateAlpha()
|
||||||
|
PopulateAddonList(lam.addonList, filterFunc)
|
||||||
|
PlaySound(SOUNDS.SPINNER_DOWN)
|
||||||
|
end)
|
||||||
|
|
||||||
|
return boxControl
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--INTERNAL FUNCTION
|
||||||
|
--creates LAM's Addon Settings top-level window
|
||||||
|
local function CreateAddonSettingsWindow()
|
||||||
|
local tlw = wm:CreateTopLevelWindow("LAMAddonSettingsWindow")
|
||||||
|
tlw:SetHidden(true)
|
||||||
|
tlw:SetDimensions(1010, 914) -- same height as ZO_OptionsWindow
|
||||||
|
|
||||||
|
ZO_ReanchorControlForLeftSidePanel(tlw)
|
||||||
|
|
||||||
|
-- create black background for the window (mimic ZO_RightFootPrintBackground)
|
||||||
|
|
||||||
|
local bgLeft = wm:CreateControl("$(parent)BackgroundLeft", tlw, CT_TEXTURE)
|
||||||
|
bgLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_left.dds")
|
||||||
|
bgLeft:SetDimensions(1024, 1024)
|
||||||
|
bgLeft:SetAnchor(TOPLEFT, nil, TOPLEFT)
|
||||||
|
bgLeft:SetDrawLayer(DL_BACKGROUND)
|
||||||
|
bgLeft:SetExcludeFromResizeToFitExtents(true)
|
||||||
|
|
||||||
|
local bgRight = wm:CreateControl("$(parent)BackgroundRight", tlw, CT_TEXTURE)
|
||||||
|
bgRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_right.dds")
|
||||||
|
bgRight:SetDimensions(64, 1024)
|
||||||
|
bgRight:SetAnchor(TOPLEFT, bgLeft, TOPRIGHT)
|
||||||
|
bgRight:SetDrawLayer(DL_BACKGROUND)
|
||||||
|
bgRight:SetExcludeFromResizeToFitExtents(true)
|
||||||
|
|
||||||
|
-- create gray background for addon list (mimic ZO_TreeUnderlay)
|
||||||
|
|
||||||
|
local underlayLeft = wm:CreateControl("$(parent)UnderlayLeft", tlw, CT_TEXTURE)
|
||||||
|
underlayLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_left.dds")
|
||||||
|
underlayLeft:SetDimensions(256, 1024)
|
||||||
|
underlayLeft:SetAnchor(TOPLEFT, bgLeft, TOPLEFT)
|
||||||
|
underlayLeft:SetDrawLayer(DL_BACKGROUND)
|
||||||
|
underlayLeft:SetExcludeFromResizeToFitExtents(true)
|
||||||
|
|
||||||
|
local underlayRight = wm:CreateControl("$(parent)UnderlayRight", tlw, CT_TEXTURE)
|
||||||
|
underlayRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_right.dds")
|
||||||
|
underlayRight:SetDimensions(128, 1024)
|
||||||
|
underlayRight:SetAnchor(TOPLEFT, underlayLeft, TOPRIGHT)
|
||||||
|
underlayRight:SetDrawLayer(DL_BACKGROUND)
|
||||||
|
underlayRight:SetExcludeFromResizeToFitExtents(true)
|
||||||
|
|
||||||
|
-- create title bar (mimic ZO_OptionsWindow)
|
||||||
|
|
||||||
|
local title = wm:CreateControl("$(parent)Title", tlw, CT_LABEL)
|
||||||
|
title:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 70)
|
||||||
|
title:SetFont("ZoFontWinH1")
|
||||||
|
title:SetModifyTextType(MODIFY_TEXT_TYPE_UPPERCASE)
|
||||||
|
|
||||||
|
local divider = wm:CreateControlFromVirtual("$(parent)Divider", tlw, "ZO_Options_Divider")
|
||||||
|
divider:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 108)
|
||||||
|
|
||||||
|
-- create search filter box
|
||||||
|
|
||||||
|
local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw)
|
||||||
|
srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120)
|
||||||
|
srchBox:SetDimensions(260, 30)
|
||||||
|
|
||||||
|
-- create scrollable addon list
|
||||||
|
|
||||||
|
local addonList = CreateAddonList("$(parent)AddonList", tlw)
|
||||||
|
addonList:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 160)
|
||||||
|
addonList:SetDimensions(285, 665)
|
||||||
|
|
||||||
|
lam.addonList = addonList -- for easy access from elsewhere
|
||||||
|
|
||||||
|
-- create container for option panels
|
||||||
|
|
||||||
|
local panelContainer = wm:CreateControl("$(parent)PanelContainer", tlw, CT_CONTROL)
|
||||||
|
panelContainer:SetAnchor(TOPLEFT, nil, TOPLEFT, 365, 120)
|
||||||
|
panelContainer:SetDimensions(645, 675)
|
||||||
|
|
||||||
|
return tlw
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--INITIALIZING
|
||||||
|
local safeToInitialize = false
|
||||||
|
local hasInitialized = false
|
||||||
|
|
||||||
|
local eventHandle = table.concat({MAJOR, MINOR}, "r")
|
||||||
|
local function OnLoad(_, addonName)
|
||||||
|
-- wait for the first loaded event
|
||||||
|
em:UnregisterForEvent(eventHandle, EVENT_ADD_ON_LOADED)
|
||||||
|
safeToInitialize = true
|
||||||
|
end
|
||||||
|
em:RegisterForEvent(eventHandle, EVENT_ADD_ON_LOADED, OnLoad)
|
||||||
|
|
||||||
|
local function OnActivated(_, addonName)
|
||||||
|
em:UnregisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED)
|
||||||
|
FlushMessages()
|
||||||
|
end
|
||||||
|
em:RegisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED, OnActivated)
|
||||||
|
|
||||||
|
function CheckSafetyAndInitialize(addonID)
|
||||||
|
if not safeToInitialize then
|
||||||
|
local msg = string.format("The panel with id '%s' was registered before addon loading has completed. This might break the AddOn Settings menu.", addonID)
|
||||||
|
PrintLater(msg)
|
||||||
|
end
|
||||||
|
if not hasInitialized then
|
||||||
|
hasInitialized = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--TODO documentation
|
||||||
|
function lam:GetAddonPanelContainer()
|
||||||
|
local fragment = lam:GetAddonSettingsFragment()
|
||||||
|
local window = fragment:GetControl()
|
||||||
|
return window:GetNamedChild("PanelContainer")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--TODO documentation
|
||||||
|
function lam:GetAddonSettingsFragment()
|
||||||
|
assert(hasInitialized or safeToInitialize)
|
||||||
|
if not LAMAddonSettingsFragment then
|
||||||
|
local window = CreateAddonSettingsWindow()
|
||||||
|
LAMAddonSettingsFragment = ZO_FadeSceneFragment:New(window, true, 100)
|
||||||
|
CreateAddonSettingsMenuEntry()
|
||||||
|
end
|
||||||
|
return LAMAddonSettingsFragment
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- vi: noexpandtab
|
89
Libs/LibAddonMenu-2.0/controls/button.lua
Normal file
89
Libs/LibAddonMenu-2.0/controls/button.lua
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
--[[buttonData = {
|
||||||
|
type = "button",
|
||||||
|
name = "My Button",
|
||||||
|
tooltip = "Button's tooltip text.",
|
||||||
|
func = function() end,
|
||||||
|
width = "full", --or "half" (optional)
|
||||||
|
disabled = function() return db.someBooleanSetting end, --or boolean (optional)
|
||||||
|
icon = "icon\\path.dds", --(optional)
|
||||||
|
warning = "Will need to reload the UI.", --(optional)
|
||||||
|
reference = "MyAddonButton" --(optional) unique global reference to control
|
||||||
|
} ]]
|
||||||
|
|
||||||
|
|
||||||
|
local widgetVersion = 7
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
if not LAM:RegisterWidget("button", widgetVersion) then return end
|
||||||
|
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
local cm = CALLBACK_MANAGER
|
||||||
|
local tinsert = table.insert
|
||||||
|
|
||||||
|
local function UpdateDisabled(control)
|
||||||
|
local disable
|
||||||
|
if type(control.data.disabled) == "function" then
|
||||||
|
disable = control.data.disabled()
|
||||||
|
else
|
||||||
|
disable = control.data.disabled
|
||||||
|
end
|
||||||
|
|
||||||
|
control.button:SetEnabled(not disable)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--controlName is optional
|
||||||
|
local MIN_HEIGHT = 28 -- default_button height
|
||||||
|
local HALF_WIDTH_LINE_SPACING = 2
|
||||||
|
function LAMCreateControl.button(parent, buttonData, controlName)
|
||||||
|
local control = LAM.util.CreateBaseControl(parent, buttonData, controlName)
|
||||||
|
control:SetMouseEnabled(true)
|
||||||
|
|
||||||
|
local width = control:GetWidth()
|
||||||
|
if control.isHalfWidth then
|
||||||
|
control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING)
|
||||||
|
else
|
||||||
|
control:SetDimensions(width, MIN_HEIGHT)
|
||||||
|
end
|
||||||
|
|
||||||
|
if buttonData.icon then
|
||||||
|
control.button = wm:CreateControl(nil, control, CT_BUTTON)
|
||||||
|
control.button:SetDimensions(26, 26)
|
||||||
|
control.button:SetNormalTexture(buttonData.icon)
|
||||||
|
control.button:SetPressedOffset(2, 2)
|
||||||
|
else
|
||||||
|
--control.button = wm:CreateControlFromVirtual(controlName.."Button", control, "ZO_DefaultButton")
|
||||||
|
control.button = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultButton")
|
||||||
|
control.button:SetWidth(width / 3)
|
||||||
|
control.button:SetText(buttonData.name)
|
||||||
|
end
|
||||||
|
local button = control.button
|
||||||
|
button:SetAnchor(control.isHalfWidth and CENTER or RIGHT)
|
||||||
|
button:SetClickSound("Click")
|
||||||
|
button.data = {tooltipText = LAM.util.GetTooltipText(buttonData.tooltip)}
|
||||||
|
button:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
|
||||||
|
button:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
|
||||||
|
button:SetHandler("OnClicked", function(self, ...)
|
||||||
|
buttonData.func(self, ...)
|
||||||
|
if control.panel.data.registerForRefresh then
|
||||||
|
cm:FireCallbacks("LAM-RefreshPanel", control)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if buttonData.warning then
|
||||||
|
control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
|
||||||
|
control.warning:SetAnchor(RIGHT, button, LEFT, -5, 0)
|
||||||
|
control.warning.data = {tooltipText = buttonData.warning}
|
||||||
|
end
|
||||||
|
|
||||||
|
if buttonData.disabled then
|
||||||
|
control.UpdateDisabled = UpdateDisabled
|
||||||
|
control:UpdateDisabled()
|
||||||
|
|
||||||
|
--this is here because buttons don't have an UpdateValue method
|
||||||
|
if control.panel.data.registerForRefresh then --if our parent window wants to refresh controls, then add this to the list
|
||||||
|
tinsert(control.panel.controlsToRefresh, control)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return control
|
||||||
|
end
|
144
Libs/LibAddonMenu-2.0/controls/checkbox.lua
Normal file
144
Libs/LibAddonMenu-2.0/controls/checkbox.lua
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
--[[checkboxData = {
|
||||||
|
type = "checkbox",
|
||||||
|
name = "My Checkbox",
|
||||||
|
tooltip = "Checkbox's tooltip text.",
|
||||||
|
getFunc = function() return db.var end,
|
||||||
|
setFunc = function(value) db.var = value doStuff() end,
|
||||||
|
width = "full", --or "half" (optional)
|
||||||
|
disabled = function() return db.someBooleanSetting end, --or boolean (optional)
|
||||||
|
warning = "Will need to reload the UI.", --(optional)
|
||||||
|
default = defaults.var, --(optional)
|
||||||
|
reference = "MyAddonCheckbox" --(optional) unique global reference to control
|
||||||
|
} ]]
|
||||||
|
|
||||||
|
|
||||||
|
local widgetVersion = 9
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
if not LAM:RegisterWidget("checkbox", widgetVersion) then return end
|
||||||
|
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
local cm = CALLBACK_MANAGER
|
||||||
|
local tinsert = table.insert
|
||||||
|
--label
|
||||||
|
local enabledColor = ZO_DEFAULT_ENABLED_COLOR
|
||||||
|
local enabledHLcolor = ZO_HIGHLIGHT_TEXT
|
||||||
|
local disabledColor = ZO_DEFAULT_DISABLED_COLOR
|
||||||
|
local disabledHLcolor = ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR
|
||||||
|
--checkbox
|
||||||
|
local checkboxColor = ZO_NORMAL_TEXT
|
||||||
|
local checkboxHLcolor = ZO_HIGHLIGHT_TEXT
|
||||||
|
|
||||||
|
|
||||||
|
local function UpdateDisabled(control)
|
||||||
|
local disable
|
||||||
|
if type(control.data.disabled) == "function" then
|
||||||
|
disable = control.data.disabled()
|
||||||
|
else
|
||||||
|
disable = control.data.disabled
|
||||||
|
end
|
||||||
|
|
||||||
|
control.label:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or control.value and ZO_DEFAULT_ENABLED_COLOR or ZO_DEFAULT_DISABLED_COLOR):UnpackRGBA())
|
||||||
|
control.checkbox:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or ZO_NORMAL_TEXT):UnpackRGBA())
|
||||||
|
--control:SetMouseEnabled(not disable)
|
||||||
|
--control:SetMouseEnabled(true)
|
||||||
|
|
||||||
|
control.isDisabled = disable
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ToggleCheckbox(control)
|
||||||
|
if control.value then
|
||||||
|
control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
|
||||||
|
control.checkbox:SetText(control.checkedText)
|
||||||
|
else
|
||||||
|
control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
|
||||||
|
control.checkbox:SetText(control.uncheckedText)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UpdateValue(control, forceDefault, value)
|
||||||
|
if forceDefault then --if we are forcing defaults
|
||||||
|
value = control.data.default
|
||||||
|
control.data.setFunc(value)
|
||||||
|
elseif value ~= nil then --our value could be false
|
||||||
|
control.data.setFunc(value)
|
||||||
|
--after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
|
||||||
|
if control.panel.data.registerForRefresh then
|
||||||
|
cm:FireCallbacks("LAM-RefreshPanel", control)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
value = control.data.getFunc()
|
||||||
|
end
|
||||||
|
control.value = value
|
||||||
|
|
||||||
|
ToggleCheckbox(control)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function OnMouseEnter(control)
|
||||||
|
ZO_Options_OnMouseEnter(control)
|
||||||
|
|
||||||
|
if control.isDisabled then return end
|
||||||
|
|
||||||
|
local label = control.label
|
||||||
|
if control.value then
|
||||||
|
label:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA())
|
||||||
|
else
|
||||||
|
label:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA())
|
||||||
|
end
|
||||||
|
control.checkbox:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA())
|
||||||
|
end
|
||||||
|
|
||||||
|
local function OnMouseExit(control)
|
||||||
|
ZO_Options_OnMouseExit(control)
|
||||||
|
|
||||||
|
if control.isDisabled then return end
|
||||||
|
|
||||||
|
local label = control.label
|
||||||
|
if control.value then
|
||||||
|
label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
|
||||||
|
else
|
||||||
|
label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
|
||||||
|
end
|
||||||
|
control.checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA())
|
||||||
|
end
|
||||||
|
|
||||||
|
--controlName is optional
|
||||||
|
function LAMCreateControl.checkbox(parent, checkboxData, controlName)
|
||||||
|
local control = LAM.util.CreateLabelAndContainerControl(parent, checkboxData, controlName)
|
||||||
|
control:SetHandler("OnMouseEnter", OnMouseEnter)
|
||||||
|
control:SetHandler("OnMouseExit", OnMouseExit)
|
||||||
|
control:SetHandler("OnMouseUp", function(control)
|
||||||
|
if control.isDisabled then return end
|
||||||
|
PlaySound(SOUNDS.DEFAULT_CLICK)
|
||||||
|
control.value = not control.value
|
||||||
|
control:UpdateValue(false, control.value)
|
||||||
|
end)
|
||||||
|
|
||||||
|
control.checkbox = wm:CreateControl(nil, control.container, CT_LABEL)
|
||||||
|
local checkbox = control.checkbox
|
||||||
|
checkbox:SetAnchor(LEFT, control.container, LEFT, 0, 0)
|
||||||
|
checkbox:SetFont("ZoFontGameBold")
|
||||||
|
checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA())
|
||||||
|
control.checkedText = GetString(SI_CHECK_BUTTON_ON):upper()
|
||||||
|
control.uncheckedText = GetString(SI_CHECK_BUTTON_OFF):upper()
|
||||||
|
|
||||||
|
if checkboxData.warning then
|
||||||
|
control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
|
||||||
|
control.warning:SetAnchor(RIGHT, checkbox, LEFT, -5, 0)
|
||||||
|
control.warning.data = {tooltipText = checkboxData.warning}
|
||||||
|
end
|
||||||
|
|
||||||
|
control.data.tooltipText = LAM.util.GetTooltipText(checkboxData.tooltip)
|
||||||
|
|
||||||
|
if checkboxData.disabled then
|
||||||
|
control.UpdateDisabled = UpdateDisabled
|
||||||
|
control:UpdateDisabled()
|
||||||
|
end
|
||||||
|
control.UpdateValue = UpdateValue
|
||||||
|
control:UpdateValue()
|
||||||
|
|
||||||
|
if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then --if our parent window wants to refresh controls, then add this to the list
|
||||||
|
tinsert(control.panel.controlsToRefresh, control)
|
||||||
|
end
|
||||||
|
|
||||||
|
return control
|
||||||
|
end
|
110
Libs/LibAddonMenu-2.0/controls/colorpicker.lua
Normal file
110
Libs/LibAddonMenu-2.0/controls/colorpicker.lua
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
--[[colorpickerData = {
|
||||||
|
type = "colorpicker",
|
||||||
|
name = "My Color Picker",
|
||||||
|
tooltip = "Color Picker's tooltip text.",
|
||||||
|
getFunc = function() return db.r, db.g, db.b, db.a end, --(alpha is optional)
|
||||||
|
setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, --(alpha is optional)
|
||||||
|
width = "full", --or "half" (optional)
|
||||||
|
disabled = function() return db.someBooleanSetting end, --or boolean (optional)
|
||||||
|
warning = "Will need to reload the UI.", --(optional)
|
||||||
|
default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, --(optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a])
|
||||||
|
reference = "MyAddonColorpicker" --(optional) unique global reference to control
|
||||||
|
} ]]
|
||||||
|
|
||||||
|
|
||||||
|
local widgetVersion = 7
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end
|
||||||
|
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
local cm = CALLBACK_MANAGER
|
||||||
|
local tinsert = table.insert
|
||||||
|
|
||||||
|
|
||||||
|
local function UpdateDisabled(control)
|
||||||
|
local disable
|
||||||
|
if type(control.data.disabled) == "function" then
|
||||||
|
disable = control.data.disabled()
|
||||||
|
else
|
||||||
|
disable = control.data.disabled
|
||||||
|
end
|
||||||
|
|
||||||
|
if disable then
|
||||||
|
control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
|
||||||
|
else
|
||||||
|
control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
|
||||||
|
end
|
||||||
|
|
||||||
|
control.isDisabled = disable
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA)
|
||||||
|
if forceDefault then --if we are forcing defaults
|
||||||
|
local color = control.data.default
|
||||||
|
valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a
|
||||||
|
control.data.setFunc(valueR, valueG, valueB, valueA)
|
||||||
|
elseif valueR and valueG and valueB then
|
||||||
|
control.data.setFunc(valueR, valueG, valueB, valueA or 1)
|
||||||
|
--after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
|
||||||
|
if control.panel.data.registerForRefresh then
|
||||||
|
cm:FireCallbacks("LAM-RefreshPanel", control)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
valueR, valueG, valueB, valueA = control.data.getFunc()
|
||||||
|
end
|
||||||
|
|
||||||
|
control.thumb:SetColor(valueR, valueG, valueB, valueA or 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function LAMCreateControl.colorpicker(parent, colorpickerData, controlName)
|
||||||
|
local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName)
|
||||||
|
|
||||||
|
control.color = control.container
|
||||||
|
local color = control.color
|
||||||
|
|
||||||
|
control.thumb = wm:CreateControl(nil, color, CT_TEXTURE)
|
||||||
|
local thumb = control.thumb
|
||||||
|
thumb:SetDimensions(36, 18)
|
||||||
|
thumb:SetAnchor(LEFT, color, LEFT, 4, 0)
|
||||||
|
|
||||||
|
color.border = wm:CreateControl(nil, color, CT_TEXTURE)
|
||||||
|
local border = color.border
|
||||||
|
border:SetTexture("EsoUI\\Art\\ChatWindow\\chatOptions_bgColSwatch_frame.dds")
|
||||||
|
border:SetTextureCoords(0, .625, 0, .8125)
|
||||||
|
border:SetDimensions(40, 22)
|
||||||
|
border:SetAnchor(CENTER, thumb, CENTER, 0, 0)
|
||||||
|
|
||||||
|
local function ColorPickerCallback(r, g, b, a)
|
||||||
|
control:UpdateValue(false, r, g, b, a)
|
||||||
|
end
|
||||||
|
|
||||||
|
control:SetHandler("OnMouseUp", function(self, btn, upInside)
|
||||||
|
if self.isDisabled then return end
|
||||||
|
|
||||||
|
if upInside then
|
||||||
|
local r, g, b, a = colorpickerData.getFunc()
|
||||||
|
COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, colorpickerData.name)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if colorpickerData.warning then
|
||||||
|
control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
|
||||||
|
control.warning:SetAnchor(RIGHT, control.color, LEFT, -5, 0)
|
||||||
|
control.warning.data = {tooltipText = colorpickerData.warning}
|
||||||
|
end
|
||||||
|
|
||||||
|
control.data.tooltipText = LAM.util.GetTooltipText(colorpickerData.tooltip)
|
||||||
|
|
||||||
|
if colorpickerData.disabled then
|
||||||
|
control.UpdateDisabled = UpdateDisabled
|
||||||
|
control:UpdateDisabled()
|
||||||
|
end
|
||||||
|
control.UpdateValue = UpdateValue
|
||||||
|
control:UpdateValue()
|
||||||
|
|
||||||
|
if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then --if our parent window wants to refresh controls, then add this to the list
|
||||||
|
tinsert(control.panel.controlsToRefresh, control)
|
||||||
|
end
|
||||||
|
|
||||||
|
return control
|
||||||
|
end
|
40
Libs/LibAddonMenu-2.0/controls/custom.lua
Normal file
40
Libs/LibAddonMenu-2.0/controls/custom.lua
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
--[[customData = {
|
||||||
|
type = "custom",
|
||||||
|
reference = "MyAddonCustomControl", --(optional) unique name for your control to use as reference
|
||||||
|
refreshFunc = function(customControl) end, --(optional) function to call when panel/controls refresh
|
||||||
|
width = "full", --or "half" (optional)
|
||||||
|
} ]]
|
||||||
|
|
||||||
|
local widgetVersion = 6
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
if not LAM:RegisterWidget("custom", widgetVersion) then return end
|
||||||
|
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
local tinsert = table.insert
|
||||||
|
|
||||||
|
local function UpdateValue(control)
|
||||||
|
if control.data.refreshFunc then
|
||||||
|
control.data.refreshFunc(control)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local MIN_HEIGHT = 26
|
||||||
|
function LAMCreateControl.custom(parent, customData, controlName)
|
||||||
|
local control = LAM.util.CreateBaseControl(parent, customData, controlName)
|
||||||
|
local width = control:GetWidth()
|
||||||
|
control:SetResizeToFitDescendents(true)
|
||||||
|
|
||||||
|
if control.isHalfWidth then --note these restrictions
|
||||||
|
control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4)
|
||||||
|
else
|
||||||
|
control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
control.UpdateValue = UpdateValue
|
||||||
|
|
||||||
|
if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then --if our parent window wants to refresh controls, then add this to the list
|
||||||
|
tinsert(control.panel.controlsToRefresh, control)
|
||||||
|
end
|
||||||
|
|
||||||
|
return control
|
||||||
|
end
|
64
Libs/LibAddonMenu-2.0/controls/description.lua
Normal file
64
Libs/LibAddonMenu-2.0/controls/description.lua
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
--[[descriptionData = {
|
||||||
|
type = "description",
|
||||||
|
title = "My Title", --(optional)
|
||||||
|
text = "My description text to display.",
|
||||||
|
width = "full", --or "half" (optional)
|
||||||
|
reference = "MyAddonDescription" --(optional) unique global reference to control
|
||||||
|
} ]]
|
||||||
|
|
||||||
|
|
||||||
|
local widgetVersion = 6
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
if not LAM:RegisterWidget("description", widgetVersion) then return end
|
||||||
|
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
local tinsert = table.insert
|
||||||
|
|
||||||
|
local function UpdateValue(control)
|
||||||
|
if control.title then
|
||||||
|
control.title:SetText(control.data.title)
|
||||||
|
end
|
||||||
|
control.desc:SetText(control.data.text)
|
||||||
|
end
|
||||||
|
|
||||||
|
local MIN_HEIGHT = 26
|
||||||
|
function LAMCreateControl.description(parent, descriptionData, controlName)
|
||||||
|
local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName)
|
||||||
|
local isHalfWidth = control.isHalfWidth
|
||||||
|
local width = control:GetWidth()
|
||||||
|
control:SetResizeToFitDescendents(true)
|
||||||
|
|
||||||
|
if isHalfWidth then
|
||||||
|
control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4)
|
||||||
|
else
|
||||||
|
control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
control.desc = wm:CreateControl(nil, control, CT_LABEL)
|
||||||
|
local desc = control.desc
|
||||||
|
desc:SetVerticalAlignment(TEXT_ALIGN_TOP)
|
||||||
|
desc:SetFont("ZoFontGame")
|
||||||
|
desc:SetText(descriptionData.text)
|
||||||
|
desc:SetWidth(isHalfWidth and width / 2 or width)
|
||||||
|
|
||||||
|
if descriptionData.title then
|
||||||
|
control.title = wm:CreateControl(nil, control, CT_LABEL)
|
||||||
|
local title = control.title
|
||||||
|
title:SetWidth(isHalfWidth and width / 2 or width)
|
||||||
|
title:SetAnchor(TOPLEFT, control, TOPLEFT)
|
||||||
|
title:SetFont("ZoFontWinH4")
|
||||||
|
title:SetText(descriptionData.title)
|
||||||
|
desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT)
|
||||||
|
else
|
||||||
|
desc:SetAnchor(TOPLEFT)
|
||||||
|
end
|
||||||
|
|
||||||
|
control.UpdateValue = UpdateValue
|
||||||
|
|
||||||
|
if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then --if our parent window wants to refresh controls, then add this to the list
|
||||||
|
tinsert(control.panel.controlsToRefresh, control)
|
||||||
|
end
|
||||||
|
|
||||||
|
return control
|
||||||
|
|
||||||
|
end
|
131
Libs/LibAddonMenu-2.0/controls/dropdown.lua
Normal file
131
Libs/LibAddonMenu-2.0/controls/dropdown.lua
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
--[[dropdownData = {
|
||||||
|
type = "dropdown",
|
||||||
|
name = "My Dropdown",
|
||||||
|
tooltip = "Dropdown's tooltip text.",
|
||||||
|
choices = {"table", "of", "choices"},
|
||||||
|
sort = "name-up", --or "name-down", "numeric-up", "numeric-down" (optional) - if not provided, list will not be sorted
|
||||||
|
getFunc = function() return db.var end,
|
||||||
|
setFunc = function(var) db.var = var doStuff() end,
|
||||||
|
width = "full", --or "half" (optional)
|
||||||
|
disabled = function() return db.someBooleanSetting end, --or boolean (optional)
|
||||||
|
warning = "Will need to reload the UI.", --(optional)
|
||||||
|
default = defaults.var, --(optional)
|
||||||
|
reference = "MyAddonDropdown" --(optional) unique global reference to control
|
||||||
|
} ]]
|
||||||
|
|
||||||
|
|
||||||
|
local widgetVersion = 9
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
if not LAM:RegisterWidget("dropdown", widgetVersion) then return end
|
||||||
|
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
local cm = CALLBACK_MANAGER
|
||||||
|
local tinsert = table.insert
|
||||||
|
|
||||||
|
|
||||||
|
local function UpdateDisabled(control)
|
||||||
|
local disable
|
||||||
|
if type(control.data.disabled) == "function" then
|
||||||
|
disable = control.data.disabled()
|
||||||
|
else
|
||||||
|
disable = control.data.disabled
|
||||||
|
end
|
||||||
|
|
||||||
|
control.dropdown:SetEnabled(not disable)
|
||||||
|
if disable then
|
||||||
|
control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
|
||||||
|
else
|
||||||
|
control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UpdateValue(control, forceDefault, value)
|
||||||
|
if forceDefault then --if we are forcing defaults
|
||||||
|
value = control.data.default
|
||||||
|
control.data.setFunc(value)
|
||||||
|
control.dropdown:SetSelectedItem(value)
|
||||||
|
elseif value then
|
||||||
|
control.data.setFunc(value)
|
||||||
|
--after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
|
||||||
|
if control.panel.data.registerForRefresh then
|
||||||
|
cm:FireCallbacks("LAM-RefreshPanel", control)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
value = control.data.getFunc()
|
||||||
|
control.dropdown:SetSelectedItem(value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function DropdownCallback(control, choiceText, choice)
|
||||||
|
choice.control:UpdateValue(false, choiceText)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UpdateChoices(control, choices)
|
||||||
|
control.dropdown:ClearItems() --remove previous choices --(need to call :SetSelectedItem()?)
|
||||||
|
|
||||||
|
--build new list of choices
|
||||||
|
local choices = choices or control.data.choices
|
||||||
|
for i = 1, #choices do
|
||||||
|
local entry = control.dropdown:CreateItemEntry(choices[i], DropdownCallback)
|
||||||
|
entry.control = control
|
||||||
|
control.dropdown:AddItem(entry, not control.data.sort and ZO_COMBOBOX_SUPRESS_UPDATE) --if sort type/order isn't specified, then don't sort
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function GrabSortingInfo(sortInfo)
|
||||||
|
local t, i = {}, 1
|
||||||
|
for info in string.gmatch(sortInfo, "([^%-]+)") do
|
||||||
|
t[i] = info
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
function LAMCreateControl.dropdown(parent, dropdownData, controlName)
|
||||||
|
local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName)
|
||||||
|
|
||||||
|
local countControl = parent
|
||||||
|
local name = parent:GetName()
|
||||||
|
if not name or #name == 0 then
|
||||||
|
countControl = LAMCreateControl
|
||||||
|
name = "LAM"
|
||||||
|
end
|
||||||
|
local comboboxCount = (countControl.comboboxCount or 0) + 1
|
||||||
|
countControl.comboboxCount = comboboxCount
|
||||||
|
control.combobox = wm:CreateControlFromVirtual(zo_strjoin(nil, name, "Combobox", comboboxCount), control.container, "ZO_ComboBox")
|
||||||
|
|
||||||
|
local combobox = control.combobox
|
||||||
|
combobox:SetAnchor(TOPLEFT)
|
||||||
|
combobox:SetDimensions(control.container:GetDimensions())
|
||||||
|
combobox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
|
||||||
|
combobox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end)
|
||||||
|
control.dropdown = ZO_ComboBox_ObjectFromContainer(combobox)
|
||||||
|
local dropdown = control.dropdown
|
||||||
|
if dropdownData.sort then
|
||||||
|
local sortInfo = GrabSortingInfo(dropdownData.sort)
|
||||||
|
local sortType, sortOrder = sortInfo[1], sortInfo[2]
|
||||||
|
dropdown:SetSortOrder(sortOrder == "up" and ZO_SORT_ORDER_UP or ZO_SORT_ORDER_DOWN, sortType == "name" and ZO_SORT_BY_NAME or ZO_SORT_BY_NAME_NUMERIC)
|
||||||
|
end
|
||||||
|
|
||||||
|
if dropdownData.warning then
|
||||||
|
control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
|
||||||
|
control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0)
|
||||||
|
control.warning.data = {tooltipText = dropdownData.warning}
|
||||||
|
end
|
||||||
|
|
||||||
|
if dropdownData.disabled then
|
||||||
|
control.UpdateDisabled = UpdateDisabled
|
||||||
|
control:UpdateDisabled()
|
||||||
|
end
|
||||||
|
control.UpdateChoices = UpdateChoices
|
||||||
|
control:UpdateChoices(dropdownData.choices)
|
||||||
|
control.UpdateValue = UpdateValue
|
||||||
|
control:UpdateValue()
|
||||||
|
|
||||||
|
if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then --if our parent window wants to refresh controls, then add this to the list
|
||||||
|
tinsert(control.panel.controlsToRefresh, control)
|
||||||
|
end
|
||||||
|
|
||||||
|
return control
|
||||||
|
end
|
136
Libs/LibAddonMenu-2.0/controls/editbox.lua
Normal file
136
Libs/LibAddonMenu-2.0/controls/editbox.lua
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
--[[editboxData = {
|
||||||
|
type = "editbox",
|
||||||
|
name = "My Editbox",
|
||||||
|
tooltip = "Editbox's tooltip text.",
|
||||||
|
getFunc = function() return db.text end,
|
||||||
|
setFunc = function(text) db.text = text doStuff() end,
|
||||||
|
isMultiline = true, --boolean
|
||||||
|
width = "full", --or "half" (optional)
|
||||||
|
disabled = function() return db.someBooleanSetting end, --or boolean (optional)
|
||||||
|
warning = "Will need to reload the UI.", --(optional)
|
||||||
|
default = defaults.text, --(optional)
|
||||||
|
reference = "MyAddonEditbox" --(optional) unique global reference to control
|
||||||
|
} ]]
|
||||||
|
|
||||||
|
|
||||||
|
local widgetVersion = 8
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
if not LAM:RegisterWidget("editbox", widgetVersion) then return end
|
||||||
|
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
local cm = CALLBACK_MANAGER
|
||||||
|
local tinsert = table.insert
|
||||||
|
|
||||||
|
|
||||||
|
local function UpdateDisabled(control)
|
||||||
|
local disable
|
||||||
|
if type(control.data.disabled) == "function" then
|
||||||
|
disable = control.data.disabled()
|
||||||
|
else
|
||||||
|
disable = control.data.disabled
|
||||||
|
end
|
||||||
|
|
||||||
|
if disable then
|
||||||
|
control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
|
||||||
|
control.editbox:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA())
|
||||||
|
else
|
||||||
|
control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
|
||||||
|
control.editbox:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
|
||||||
|
end
|
||||||
|
--control.editbox:SetEditEnabled(not disable)
|
||||||
|
control.editbox:SetMouseEnabled(not disable)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UpdateValue(control, forceDefault, value)
|
||||||
|
if forceDefault then --if we are forcing defaults
|
||||||
|
value = control.data.default
|
||||||
|
control.data.setFunc(value)
|
||||||
|
control.editbox:SetText(value)
|
||||||
|
elseif value then
|
||||||
|
control.data.setFunc(value)
|
||||||
|
--after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
|
||||||
|
if control.panel.data.registerForRefresh then
|
||||||
|
cm:FireCallbacks("LAM-RefreshPanel", control)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
value = control.data.getFunc()
|
||||||
|
control.editbox:SetText(value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local MIN_HEIGHT = 26
|
||||||
|
local HALF_WIDTH_LINE_SPACING = 2
|
||||||
|
function LAMCreateControl.editbox(parent, editboxData, controlName)
|
||||||
|
local control = LAM.util.CreateLabelAndContainerControl(parent, editboxData, controlName)
|
||||||
|
|
||||||
|
local container = control.container
|
||||||
|
control.bg = wm:CreateControlFromVirtual(nil, container, "ZO_EditBackdrop")
|
||||||
|
local bg = control.bg
|
||||||
|
bg:SetAnchorFill()
|
||||||
|
|
||||||
|
if editboxData.isMultiline then
|
||||||
|
control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditMultiLineForBackdrop")
|
||||||
|
control.editbox:SetHandler("OnMouseWheel", function(self, delta)
|
||||||
|
if self:HasFocus() then --only set focus to new spots if the editbox is currently in use
|
||||||
|
local cursorPos = self:GetCursorPosition()
|
||||||
|
local text = self:GetText()
|
||||||
|
local textLen = text:len()
|
||||||
|
local newPos
|
||||||
|
if delta > 0 then --scrolling up
|
||||||
|
local reverseText = text:reverse()
|
||||||
|
local revCursorPos = textLen - cursorPos
|
||||||
|
local revPos = reverseText:find("\n", revCursorPos+1)
|
||||||
|
newPos = revPos and textLen - revPos
|
||||||
|
else --scrolling down
|
||||||
|
newPos = text:find("\n", cursorPos+1)
|
||||||
|
end
|
||||||
|
if newPos then --if we found a new line, then scroll, otherwise don't
|
||||||
|
self:SetCursorPosition(newPos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditForBackdrop")
|
||||||
|
end
|
||||||
|
local editbox = control.editbox
|
||||||
|
editbox:SetText(editboxData.getFunc())
|
||||||
|
editbox:SetMaxInputChars(3000)
|
||||||
|
editbox:SetHandler("OnFocusLost", function(self) control:UpdateValue(false, self:GetText()) end)
|
||||||
|
editbox:SetHandler("OnEscape", function(self) self:LoseFocus() control:UpdateValue(false, self:GetText()) end)
|
||||||
|
editbox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
|
||||||
|
editbox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end)
|
||||||
|
|
||||||
|
if not editboxData.isMultiline then
|
||||||
|
container:SetHeight(24)
|
||||||
|
else
|
||||||
|
local width = container:GetWidth()
|
||||||
|
local height = control.isHalfWidth and 74 or 100
|
||||||
|
container:SetHeight(height)
|
||||||
|
editbox:SetDimensionConstraints(width, height, width, 500)
|
||||||
|
|
||||||
|
if control.lineControl then
|
||||||
|
control.lineControl:SetHeight(MIN_HEIGHT + height + HALF_WIDTH_LINE_SPACING)
|
||||||
|
else
|
||||||
|
control:SetHeight(height)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if editboxData.warning then
|
||||||
|
control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
|
||||||
|
control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0)
|
||||||
|
control.warning.data = {tooltipText = editboxData.warning}
|
||||||
|
end
|
||||||
|
|
||||||
|
if editboxData.disabled then
|
||||||
|
control.UpdateDisabled = UpdateDisabled
|
||||||
|
control:UpdateDisabled()
|
||||||
|
end
|
||||||
|
control.UpdateValue = UpdateValue
|
||||||
|
control:UpdateValue()
|
||||||
|
|
||||||
|
if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then --if our parent window wants to refresh controls, then add this to the list
|
||||||
|
tinsert(control.panel.controlsToRefresh, control)
|
||||||
|
end
|
||||||
|
|
||||||
|
return control
|
||||||
|
end
|
45
Libs/LibAddonMenu-2.0/controls/header.lua
Normal file
45
Libs/LibAddonMenu-2.0/controls/header.lua
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
--[[headerData = {
|
||||||
|
type = "header",
|
||||||
|
name = "My Header",
|
||||||
|
width = "full", --or "half" (optional)
|
||||||
|
reference = "MyAddonHeader" --(optional) unique global reference to control
|
||||||
|
} ]]
|
||||||
|
|
||||||
|
|
||||||
|
local widgetVersion = 6
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
if not LAM:RegisterWidget("header", widgetVersion) then return end
|
||||||
|
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
local tinsert = table.insert
|
||||||
|
|
||||||
|
local function UpdateValue(control)
|
||||||
|
control.header:SetText(control.data.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
local MIN_HEIGHT = 30
|
||||||
|
function LAMCreateControl.header(parent, headerData, controlName)
|
||||||
|
local control = LAM.util.CreateBaseControl(parent, headerData, controlName)
|
||||||
|
local isHalfWidth = control.isHalfWidth
|
||||||
|
local width = control:GetWidth()
|
||||||
|
control:SetDimensions(isHalfWidth and width / 2 or width, MIN_HEIGHT)
|
||||||
|
|
||||||
|
control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider")
|
||||||
|
local divider = control.divider
|
||||||
|
divider:SetWidth(isHalfWidth and width / 2 or width)
|
||||||
|
divider:SetAnchor(TOPLEFT)
|
||||||
|
|
||||||
|
control.header = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
|
||||||
|
local header = control.header
|
||||||
|
header:SetAnchor(TOPLEFT, divider, BOTTOMLEFT)
|
||||||
|
header:SetAnchor(BOTTOMRIGHT)
|
||||||
|
header:SetText(headerData.name)
|
||||||
|
|
||||||
|
control.UpdateValue = UpdateValue
|
||||||
|
|
||||||
|
if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then --if our parent window wants to refresh controls, then add this to the list
|
||||||
|
tinsert(control.panel.controlsToRefresh, control)
|
||||||
|
end
|
||||||
|
|
||||||
|
return control
|
||||||
|
end
|
441
Libs/LibAddonMenu-2.0/controls/iconpicker.lua
Normal file
441
Libs/LibAddonMenu-2.0/controls/iconpicker.lua
Normal file
@ -0,0 +1,441 @@
|
|||||||
|
--[[iconpickerData = {
|
||||||
|
type = "iconpicker",
|
||||||
|
name = "My Icon Picker",
|
||||||
|
tooltip = "Color Picker's tooltip text.",
|
||||||
|
choices = {"texture path 1", "texture path 2", "texture path 3"},
|
||||||
|
choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, --(optional)
|
||||||
|
getFunc = function() return db.var end,
|
||||||
|
setFunc = function(var) db.var = var doStuff() end,
|
||||||
|
maxColumns = 5, --(optional) number of icons in one row
|
||||||
|
visibleRows = 4.5, --(optional) number of visible rows
|
||||||
|
iconSize = 28, --(optional) size of the icons
|
||||||
|
defaultColor = ZO_ColorDef:New("FFFFFF"), --(optional) default color of the icons
|
||||||
|
width = "full", --or "half" (optional)
|
||||||
|
beforeShow = function(control, iconPicker) return preventShow end, --(optional)
|
||||||
|
disabled = function() return db.someBooleanSetting end, --or boolean (optional)
|
||||||
|
warning = "Will need to reload the UI.", --(optional)
|
||||||
|
default = defaults.var, --(optional)
|
||||||
|
reference = "MyAddonIconPicker" --(optional) unique global reference to control
|
||||||
|
} ]]
|
||||||
|
|
||||||
|
local widgetVersion = 2
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
if not LAM:RegisterWidget("iconpicker", widgetVersion) then return end
|
||||||
|
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
local cm = CALLBACK_MANAGER
|
||||||
|
local tinsert = table.insert
|
||||||
|
|
||||||
|
local IconPickerMenu = ZO_Object:Subclass()
|
||||||
|
local iconPicker
|
||||||
|
LAM.util.GetIconPickerMenu = function()
|
||||||
|
if not iconPicker then
|
||||||
|
iconPicker = IconPickerMenu:New("LAMIconPicker")
|
||||||
|
local sceneFragment = LAM:GetAddonSettingsFragment()
|
||||||
|
ZO_PreHook(sceneFragment, "OnHidden", function()
|
||||||
|
if not iconPicker.control:IsHidden() then
|
||||||
|
iconPicker:Clear()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
return iconPicker
|
||||||
|
end
|
||||||
|
|
||||||
|
function IconPickerMenu:New(...)
|
||||||
|
local object = ZO_Object.New(self)
|
||||||
|
object:Initialize(...)
|
||||||
|
return object
|
||||||
|
end
|
||||||
|
|
||||||
|
function IconPickerMenu:Initialize(name)
|
||||||
|
local control = wm:CreateTopLevelWindow(name)
|
||||||
|
control:SetDrawTier(DT_HIGH)
|
||||||
|
control:SetHidden(true)
|
||||||
|
self.control = control
|
||||||
|
|
||||||
|
local scrollContainer = wm:CreateControlFromVirtual(name .. "ScrollContainer", control, "ZO_ScrollContainer")
|
||||||
|
-- control:SetDimensions(control.container:GetWidth(), height) -- adjust to icon size / col count
|
||||||
|
scrollContainer:SetAnchorFill()
|
||||||
|
ZO_Scroll_SetUseFadeGradient(scrollContainer, false)
|
||||||
|
ZO_Scroll_SetHideScrollbarOnDisable(scrollContainer, false)
|
||||||
|
ZO_VerticalScrollbarBase_OnMouseExit(scrollContainer:GetNamedChild("ScrollBar")) -- scrollbar initialization seems to be broken so we force it to update the correct alpha value
|
||||||
|
local scroll = GetControl(scrollContainer, "ScrollChild")
|
||||||
|
self.scroll = scroll
|
||||||
|
self.scrollContainer = scrollContainer
|
||||||
|
|
||||||
|
local bg = wm:CreateControl(nil, scrollContainer, CT_BACKDROP)
|
||||||
|
bg:SetAnchor(TOPLEFT, scrollContainer, TOPLEFT, 0, -3)
|
||||||
|
bg:SetAnchor(BOTTOMRIGHT, scrollContainer, BOTTOMRIGHT, 2, 5)
|
||||||
|
bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16)
|
||||||
|
bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds")
|
||||||
|
bg:SetInsets(16, 16, -16, -16)
|
||||||
|
|
||||||
|
local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE)
|
||||||
|
mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds")
|
||||||
|
mungeOverlay:SetDrawLevel(1)
|
||||||
|
mungeOverlay:SetAddressMode(TEX_MODE_WRAP)
|
||||||
|
mungeOverlay:SetAnchorFill()
|
||||||
|
|
||||||
|
local mouseOver = wm:CreateControl(nil, scrollContainer, CT_TEXTURE)
|
||||||
|
mouseOver:SetDrawLevel(2)
|
||||||
|
mouseOver:SetTexture("EsoUI/Art/Buttons/minmax_mouseover.dds")
|
||||||
|
mouseOver:SetHidden(true)
|
||||||
|
|
||||||
|
local function IconFactory(pool)
|
||||||
|
local icon = wm:CreateControl(name .. "Entry" .. pool:GetNextControlId(), scroll, CT_TEXTURE)
|
||||||
|
icon:SetMouseEnabled(true)
|
||||||
|
icon:SetDrawLevel(3)
|
||||||
|
icon:SetHandler("OnMouseEnter", function()
|
||||||
|
mouseOver:SetAnchor(TOPLEFT, icon, TOPLEFT, 0, 0)
|
||||||
|
mouseOver:SetAnchor(BOTTOMRIGHT, icon, BOTTOMRIGHT, 0, 0)
|
||||||
|
mouseOver:SetHidden(false)
|
||||||
|
if self.customOnMouseEnter then
|
||||||
|
self.customOnMouseEnter(icon)
|
||||||
|
else
|
||||||
|
self:OnMouseEnter(icon)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
icon:SetHandler("OnMouseExit", function()
|
||||||
|
mouseOver:ClearAnchors()
|
||||||
|
mouseOver:SetHidden(true)
|
||||||
|
if self.customOnMouseExit then
|
||||||
|
self.customOnMouseExit(icon)
|
||||||
|
else
|
||||||
|
self:OnMouseExit(icon)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
icon:SetHandler("OnMouseUp", function(control, ...)
|
||||||
|
PlaySound("Click")
|
||||||
|
icon.OnSelect(icon, icon.texture)
|
||||||
|
self:Clear()
|
||||||
|
end)
|
||||||
|
return icon
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ResetFunction(icon)
|
||||||
|
icon:ClearAnchors()
|
||||||
|
end
|
||||||
|
|
||||||
|
self.iconPool = ZO_ObjectPool:New(IconFactory, ResetFunction)
|
||||||
|
self:SetMaxColumns(1)
|
||||||
|
self.icons = {}
|
||||||
|
self.color = ZO_DEFAULT_ENABLED_COLOR
|
||||||
|
|
||||||
|
EVENT_MANAGER:RegisterForEvent(name .. "_OnGlobalMouseUp", EVENT_GLOBAL_MOUSE_UP, function()
|
||||||
|
if self.refCount ~= nil then
|
||||||
|
local moc = wm:GetMouseOverControl()
|
||||||
|
if(moc:GetOwningWindow() ~= control) then
|
||||||
|
self.refCount = self.refCount - 1
|
||||||
|
if self.refCount <= 0 then
|
||||||
|
self:Clear()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function IconPickerMenu:OnMouseEnter(icon)
|
||||||
|
InitializeTooltip(InformationTooltip, icon, TOPLEFT, 0, 0, BOTTOMRIGHT)
|
||||||
|
SetTooltipText(InformationTooltip, LAM.util.GetTooltipText(icon.tooltip))
|
||||||
|
InformationTooltipTopLevel:BringWindowToTop()
|
||||||
|
end
|
||||||
|
|
||||||
|
function IconPickerMenu:OnMouseExit(icon)
|
||||||
|
ClearTooltip(InformationTooltip)
|
||||||
|
end
|
||||||
|
|
||||||
|
function IconPickerMenu:SetMaxColumns(value)
|
||||||
|
self.maxCols = value ~= nil and value or 5
|
||||||
|
end
|
||||||
|
|
||||||
|
local DEFAULT_SIZE = 28
|
||||||
|
function IconPickerMenu:SetIconSize(value)
|
||||||
|
local iconSize = DEFAULT_SIZE
|
||||||
|
if value ~= nil then iconSize = math.max(iconSize, value) end
|
||||||
|
self.iconSize = iconSize
|
||||||
|
end
|
||||||
|
|
||||||
|
function IconPickerMenu:SetVisibleRows(value)
|
||||||
|
self.visibleRows = value ~= nil and value or 4.5
|
||||||
|
end
|
||||||
|
|
||||||
|
function IconPickerMenu:SetMouseHandlers(onEnter, onExit)
|
||||||
|
self.customOnMouseEnter = onEnter
|
||||||
|
self.customOnMouseExit = onExit
|
||||||
|
end
|
||||||
|
|
||||||
|
function IconPickerMenu:UpdateDimensions()
|
||||||
|
local iconSize = self.iconSize
|
||||||
|
local width = iconSize * self.maxCols + 20
|
||||||
|
local height = iconSize * self.visibleRows
|
||||||
|
self.control:SetDimensions(width, height)
|
||||||
|
|
||||||
|
local icons = self.icons
|
||||||
|
for i = 1, #icons do
|
||||||
|
local icon = icons[i]
|
||||||
|
icon:SetDimensions(iconSize, iconSize)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function IconPickerMenu:UpdateAnchors()
|
||||||
|
local iconSize = self.iconSize
|
||||||
|
local col, maxCols = 1, self.maxCols
|
||||||
|
local previousCol, previousRow
|
||||||
|
local scroll = self.scroll
|
||||||
|
local icons = self.icons
|
||||||
|
|
||||||
|
for i = 1, #icons do
|
||||||
|
local icon = icons[i]
|
||||||
|
icon:ClearAnchors()
|
||||||
|
if i == 1 then
|
||||||
|
icon:SetAnchor(TOPLEFT, scroll, TOPLEFT, 0, 0)
|
||||||
|
previousRow = icon
|
||||||
|
elseif col == 1 then
|
||||||
|
icon:SetAnchor(TOPLEFT, previousRow, BOTTOMLEFT, 0, 0)
|
||||||
|
previousRow = icon
|
||||||
|
else
|
||||||
|
icon:SetAnchor(TOPLEFT, previousCol, TOPRIGHT, 0, 0)
|
||||||
|
end
|
||||||
|
previousCol = icon
|
||||||
|
col = col >= maxCols and 1 or col + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function IconPickerMenu:Clear()
|
||||||
|
self.icons = {}
|
||||||
|
self.iconPool:ReleaseAllObjects()
|
||||||
|
self.control:SetHidden(true)
|
||||||
|
self.color = ZO_DEFAULT_ENABLED_COLOR
|
||||||
|
self.refCount = nil
|
||||||
|
self.parent = nil
|
||||||
|
self.customOnMouseEnter = nil
|
||||||
|
self.customOnMouseExit = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function IconPickerMenu:AddIcon(texturePath, callback, tooltip)
|
||||||
|
local icon, key = self.iconPool:AcquireObject()
|
||||||
|
icon:SetTexture(texturePath)
|
||||||
|
icon:SetColor(self.color:UnpackRGBA())
|
||||||
|
icon.texture = texturePath
|
||||||
|
icon.tooltip = tooltip
|
||||||
|
icon.OnSelect = callback
|
||||||
|
self.icons[#self.icons + 1] = icon
|
||||||
|
end
|
||||||
|
|
||||||
|
function IconPickerMenu:Show(parent)
|
||||||
|
if #self.icons == 0 then return false end
|
||||||
|
if not self.control:IsHidden() then self:Clear() return false end
|
||||||
|
self:UpdateDimensions()
|
||||||
|
self:UpdateAnchors()
|
||||||
|
|
||||||
|
local control = self.control
|
||||||
|
control:ClearAnchors()
|
||||||
|
control:SetAnchor(TOPLEFT, parent, BOTTOMLEFT, 0, 8)
|
||||||
|
control:SetHidden(false)
|
||||||
|
control:BringWindowToTop()
|
||||||
|
self.parent = parent
|
||||||
|
self.refCount = 2
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function IconPickerMenu:SetColor(color)
|
||||||
|
local icons = self.icons
|
||||||
|
self.color = color
|
||||||
|
for i = 1, #icons do
|
||||||
|
local icon = icons[i]
|
||||||
|
icon:SetColor(color:UnpackRGBA())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------
|
||||||
|
|
||||||
|
local function UpdateChoices(control, choices, choicesTooltips)
|
||||||
|
local data = control.data
|
||||||
|
if not choices then
|
||||||
|
choices, choicesTooltips = data.choices, data.choicesTooltips
|
||||||
|
end
|
||||||
|
local addedChoices = {}
|
||||||
|
|
||||||
|
local iconPicker = LAM.util.GetIconPickerMenu()
|
||||||
|
iconPicker:Clear()
|
||||||
|
for i = 1, #choices do
|
||||||
|
local texture = choices[i]
|
||||||
|
if not addedChoices[texture] then -- remove duplicates
|
||||||
|
iconPicker:AddIcon(choices[i], function(self, texture)
|
||||||
|
control.icon:SetTexture(texture)
|
||||||
|
data.setFunc(texture)
|
||||||
|
if control.panel.data.registerForRefresh then
|
||||||
|
cm:FireCallbacks("LAM-RefreshPanel", control)
|
||||||
|
end
|
||||||
|
end, choicesTooltips[i])
|
||||||
|
addedChoices[texture] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function IsDisabled(control)
|
||||||
|
if type(control.data.disabled) == "function" then
|
||||||
|
return control.data.disabled()
|
||||||
|
else
|
||||||
|
return control.data.disabled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SetColor(control, color)
|
||||||
|
local icon = control.icon
|
||||||
|
if IsDisabled(control) then
|
||||||
|
icon:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
|
||||||
|
else
|
||||||
|
icon.color = color or control.data.defaultColor or ZO_DEFAULT_ENABLED_COLOR
|
||||||
|
icon:SetColor(icon.color:UnpackRGBA())
|
||||||
|
end
|
||||||
|
|
||||||
|
local iconPicker = LAM.util.GetIconPickerMenu()
|
||||||
|
if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then
|
||||||
|
iconPicker:SetColor(icon.color)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UpdateDisabled(control)
|
||||||
|
local disable = IsDisabled(control)
|
||||||
|
|
||||||
|
control.dropdown:SetMouseEnabled(not disable)
|
||||||
|
control.dropdownButton:SetEnabled(not disable)
|
||||||
|
|
||||||
|
local iconPicker = LAM.util.GetIconPickerMenu()
|
||||||
|
if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then
|
||||||
|
iconPicker:Clear()
|
||||||
|
end
|
||||||
|
|
||||||
|
SetColor(control)
|
||||||
|
if disable then
|
||||||
|
control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
|
||||||
|
else
|
||||||
|
control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UpdateValue(control, forceDefault, value)
|
||||||
|
if forceDefault then --if we are forcing defaults
|
||||||
|
value = control.data.default
|
||||||
|
control.data.setFunc(value)
|
||||||
|
control.icon:SetTexture(value)
|
||||||
|
elseif value then
|
||||||
|
control.data.setFunc(value)
|
||||||
|
--after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
|
||||||
|
if control.panel.data.registerForRefresh then
|
||||||
|
cm:FireCallbacks("LAM-RefreshPanel", control)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
value = control.data.getFunc()
|
||||||
|
control.icon:SetTexture(value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local MIN_HEIGHT = 26
|
||||||
|
local HALF_WIDTH_LINE_SPACING = 2
|
||||||
|
local function SetIconSize(control, size)
|
||||||
|
local icon = control.icon
|
||||||
|
icon.size = size
|
||||||
|
icon:SetDimensions(size, size)
|
||||||
|
|
||||||
|
local height = size + 4
|
||||||
|
control.dropdown:SetDimensions(size + 20, height)
|
||||||
|
height = math.max(height, MIN_HEIGHT)
|
||||||
|
control.container:SetHeight(height)
|
||||||
|
if control.lineControl then
|
||||||
|
control.lineControl:SetHeight(MIN_HEIGHT + size + HALF_WIDTH_LINE_SPACING)
|
||||||
|
else
|
||||||
|
control:SetHeight(height)
|
||||||
|
end
|
||||||
|
|
||||||
|
local iconPicker = LAM.util.GetIconPickerMenu()
|
||||||
|
if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then
|
||||||
|
iconPicker:SetIconSize(size)
|
||||||
|
iconPicker:UpdateDimensions()
|
||||||
|
iconPicker:UpdateAnchors()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function LAMCreateControl.iconpicker(parent, iconpickerData, controlName)
|
||||||
|
local control = LAM.util.CreateLabelAndContainerControl(parent, iconpickerData, controlName)
|
||||||
|
|
||||||
|
local function ShowIconPicker()
|
||||||
|
local iconPicker = LAM.util.GetIconPickerMenu()
|
||||||
|
if iconPicker.parent == control.container then
|
||||||
|
iconPicker:Clear()
|
||||||
|
else
|
||||||
|
iconPicker:SetMaxColumns(iconpickerData.maxColumns)
|
||||||
|
iconPicker:SetVisibleRows(iconpickerData.visibleRows)
|
||||||
|
iconPicker:SetIconSize(control.icon.size)
|
||||||
|
UpdateChoices(control)
|
||||||
|
iconPicker:SetColor(control.icon.color)
|
||||||
|
if iconpickerData.beforeShow then
|
||||||
|
if iconpickerData.beforeShow(control, iconPicker) then
|
||||||
|
iconPicker:Clear()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
iconPicker:Show(control.container)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local iconSize = iconpickerData.iconSize ~= nil and iconpickerData.iconSize or DEFAULT_SIZE
|
||||||
|
control.dropdown = wm:CreateControl(nil, control.container, CT_CONTROL)
|
||||||
|
local dropdown = control.dropdown
|
||||||
|
dropdown:SetAnchor(LEFT, control.container, LEFT, 0, 0)
|
||||||
|
dropdown:SetMouseEnabled(true)
|
||||||
|
dropdown:SetHandler("OnMouseUp", ShowIconPicker)
|
||||||
|
dropdown:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
|
||||||
|
dropdown:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end)
|
||||||
|
|
||||||
|
control.icon = wm:CreateControl(nil, dropdown, CT_TEXTURE)
|
||||||
|
local icon = control.icon
|
||||||
|
icon:SetAnchor(LEFT, dropdown, LEFT, 3, 0)
|
||||||
|
icon:SetDrawLevel(2)
|
||||||
|
|
||||||
|
local dropdownButton = wm:CreateControlFromVirtual(nil, dropdown, "ZO_DropdownButton")
|
||||||
|
dropdownButton:SetDimensions(16, 16)
|
||||||
|
dropdownButton:SetHandler("OnClicked", ShowIconPicker)
|
||||||
|
dropdownButton:SetAnchor(RIGHT, dropdown, RIGHT, -3, 0)
|
||||||
|
control.dropdownButton = dropdownButton
|
||||||
|
|
||||||
|
control.bg = wm:CreateControl(nil, dropdown, CT_BACKDROP)
|
||||||
|
local bg = control.bg
|
||||||
|
bg:SetAnchor(TOPLEFT, dropdown, TOPLEFT, 0, -3)
|
||||||
|
bg:SetAnchor(BOTTOMRIGHT, dropdown, BOTTOMRIGHT, 2, 5)
|
||||||
|
bg:SetEdgeTexture("EsoUI/Art/Tooltips/UI-Border.dds", 128, 16)
|
||||||
|
bg:SetCenterTexture("EsoUI/Art/Tooltips/UI-TooltipCenter.dds")
|
||||||
|
bg:SetInsets(16, 16, -16, -16)
|
||||||
|
local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE)
|
||||||
|
mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds")
|
||||||
|
mungeOverlay:SetDrawLevel(1)
|
||||||
|
mungeOverlay:SetAddressMode(TEX_MODE_WRAP)
|
||||||
|
mungeOverlay:SetAnchorFill()
|
||||||
|
|
||||||
|
if iconpickerData.warning then
|
||||||
|
control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
|
||||||
|
control.warning:SetAnchor(RIGHT, control.container, LEFT, -5, 0)
|
||||||
|
control.warning.data = {tooltipText = iconpickerData.warning}
|
||||||
|
end
|
||||||
|
|
||||||
|
if iconpickerData.disabled then
|
||||||
|
control.UpdateDisabled = UpdateDisabled
|
||||||
|
control:UpdateDisabled()
|
||||||
|
end
|
||||||
|
|
||||||
|
control.UpdateChoices = UpdateChoices
|
||||||
|
control.UpdateValue = UpdateValue
|
||||||
|
control:UpdateValue()
|
||||||
|
control.SetColor = SetColor
|
||||||
|
control:SetColor()
|
||||||
|
control.SetIconSize = SetIconSize
|
||||||
|
control:SetIconSize(iconSize)
|
||||||
|
|
||||||
|
if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then --if our parent window wants to refresh controls, then add this to the list
|
||||||
|
tinsert(control.panel.controlsToRefresh, control)
|
||||||
|
end
|
||||||
|
|
||||||
|
return control
|
||||||
|
end
|
132
Libs/LibAddonMenu-2.0/controls/panel.lua
Normal file
132
Libs/LibAddonMenu-2.0/controls/panel.lua
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
--[[panelData = {
|
||||||
|
type = "panel",
|
||||||
|
name = "Window Title",
|
||||||
|
displayName = "My Longer Window Title", --(optional) (can be useful for long addon names or if you want to colorize it)
|
||||||
|
author = "Seerah", --(optional)
|
||||||
|
version = "2.0", --(optional)
|
||||||
|
keywords = "settings", --(optional) additional keywords for search filter (it looks for matches in name..keywords..author)
|
||||||
|
slashCommand = "/myaddon", --(optional) will register a keybind to open to this panel (don't forget to include the slash!)
|
||||||
|
registerForRefresh = true, --boolean (optional) (will refresh all options controls when a setting is changed and when the panel is shown)
|
||||||
|
registerForDefaults = true, --boolean (optional) (will set all options controls back to default values)
|
||||||
|
resetFunc = function() print("defaults reset") end, --(optional) custom function to run after settings are reset to defaults
|
||||||
|
} ]]
|
||||||
|
|
||||||
|
|
||||||
|
local widgetVersion = 9
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
if not LAM:RegisterWidget("panel", widgetVersion) then return end
|
||||||
|
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
local cm = CALLBACK_MANAGER
|
||||||
|
|
||||||
|
local function RefreshPanel(control)
|
||||||
|
local panel = control.panel or control --callback can be fired by a single control or by the panel showing
|
||||||
|
local panelControls = panel.controlsToRefresh
|
||||||
|
|
||||||
|
for i = 1, #panelControls do
|
||||||
|
local updateControl = panelControls[i]
|
||||||
|
if updateControl ~= control then
|
||||||
|
if updateControl.UpdateValue then
|
||||||
|
updateControl:UpdateValue()
|
||||||
|
end
|
||||||
|
if updateControl.UpdateDisabled then
|
||||||
|
updateControl:UpdateDisabled()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ForceDefaults(panel)
|
||||||
|
local panelControls = panel.controlsToRefresh
|
||||||
|
|
||||||
|
for i = 1, #panelControls do
|
||||||
|
local updateControl = panelControls[i]
|
||||||
|
if updateControl.UpdateValue and updateControl.data.default ~= nil then
|
||||||
|
updateControl:UpdateValue(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if panel.data.resetFunc then
|
||||||
|
panel.data.resetFunc()
|
||||||
|
end
|
||||||
|
|
||||||
|
cm:FireCallbacks("LAM-RefreshPanel", panel)
|
||||||
|
end
|
||||||
|
ESO_Dialogs["LAM_DEFAULTS"] = {
|
||||||
|
title = {
|
||||||
|
text = SI_INTERFACE_OPTIONS_RESET_TO_DEFAULT_TOOLTIP,
|
||||||
|
},
|
||||||
|
mainText = {
|
||||||
|
text = SI_OPTIONS_RESET_PROMPT,
|
||||||
|
align = TEXT_ALIGN_CENTER,
|
||||||
|
},
|
||||||
|
buttons = {
|
||||||
|
[1] = {
|
||||||
|
text = SI_OPTIONS_RESET,
|
||||||
|
callback = function(dialog) ForceDefaults(dialog.data[1]) end,
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
text = SI_DIALOG_CANCEL,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local callbackRegistered = false
|
||||||
|
LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1
|
||||||
|
function LAMCreateControl.panel(parent, panelData, controlName)
|
||||||
|
local control = wm:CreateControl(controlName, parent, CT_CONTROL)
|
||||||
|
|
||||||
|
control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
|
||||||
|
local label = control.label
|
||||||
|
label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4)
|
||||||
|
label:SetText(panelData.displayName or panelData.name)
|
||||||
|
|
||||||
|
if panelData.author or panelData.version then
|
||||||
|
control.info = wm:CreateControl(nil, control, CT_LABEL)
|
||||||
|
local info = control.info
|
||||||
|
info:SetFont("$(CHAT_FONT)|14|soft-shadow-thin")
|
||||||
|
info:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2)
|
||||||
|
if panelData.author and panelData.version then
|
||||||
|
info:SetText(string.format("Version: %s - %s: %s", panelData.version, GetString(SI_ADDON_MANAGER_AUTHOR), panelData.author))
|
||||||
|
elseif panelData.author then
|
||||||
|
info:SetText(string.format("%s: %s", GetString(SI_ADDON_MANAGER_AUTHOR), panelData.author))
|
||||||
|
else
|
||||||
|
info:SetText("Version: "..panelData.version)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer")
|
||||||
|
LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1
|
||||||
|
local container = control.container
|
||||||
|
container:SetAnchor(TOPLEFT, control.info or label, BOTTOMLEFT, 0, 20)
|
||||||
|
container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, -3, -3)
|
||||||
|
control.scroll = GetControl(control.container, "ScrollChild")
|
||||||
|
control.scroll:SetResizeToFitPadding(0, 20)
|
||||||
|
|
||||||
|
if panelData.registerForDefaults then
|
||||||
|
control.defaultButton = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultTextButton")
|
||||||
|
local defaultButton = control.defaultButton
|
||||||
|
defaultButton:SetFont("ZoFontDialogKeybindDescription")
|
||||||
|
defaultButton:SetHorizontalAlignment(TEXT_ALIGN_LEFT)
|
||||||
|
--defaultButton:SetText("Reset To Defaults")
|
||||||
|
defaultButton:SetText(GetString(SI_OPTIONS_DEFAULTS))
|
||||||
|
defaultButton:SetDimensions(200, 30)
|
||||||
|
defaultButton:SetAnchor(TOPLEFT, control, BOTTOMLEFT, 0, 2)
|
||||||
|
defaultButton:SetHandler("OnClicked", function()
|
||||||
|
ZO_Dialogs_ShowDialog("LAM_DEFAULTS", {control})
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
if panelData.registerForRefresh and not callbackRegistered then --don't want to register our callback more than once
|
||||||
|
cm:RegisterCallback("LAM-RefreshPanel", RefreshPanel)
|
||||||
|
callbackRegistered = true
|
||||||
|
end
|
||||||
|
|
||||||
|
control.data = panelData
|
||||||
|
control.controlsToRefresh = {}
|
||||||
|
|
||||||
|
return control
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- vi: noexpandtab
|
157
Libs/LibAddonMenu-2.0/controls/slider.lua
Normal file
157
Libs/LibAddonMenu-2.0/controls/slider.lua
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
--[[sliderData = {
|
||||||
|
type = "slider",
|
||||||
|
name = "My Slider",
|
||||||
|
tooltip = "Slider's tooltip text.",
|
||||||
|
min = 0,
|
||||||
|
max = 20,
|
||||||
|
step = 1, --(optional)
|
||||||
|
getFunc = function() return db.var end,
|
||||||
|
setFunc = function(value) db.var = value doStuff() end,
|
||||||
|
width = "full", --or "half" (optional)
|
||||||
|
disabled = function() return db.someBooleanSetting end, --or boolean (optional)
|
||||||
|
warning = "Will need to reload the UI.", --(optional)
|
||||||
|
default = defaults.var, --(optional)
|
||||||
|
reference = "MyAddonSlider" --(optional) unique global reference to control
|
||||||
|
} ]]
|
||||||
|
|
||||||
|
|
||||||
|
local widgetVersion = 7
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
if not LAM:RegisterWidget("slider", widgetVersion) then return end
|
||||||
|
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
local cm = CALLBACK_MANAGER
|
||||||
|
local round = zo_round
|
||||||
|
local strformat = string.format
|
||||||
|
local tinsert = table.insert
|
||||||
|
|
||||||
|
local function UpdateDisabled(control)
|
||||||
|
local disable
|
||||||
|
if type(control.data.disabled) == "function" then
|
||||||
|
disable = control.data.disabled()
|
||||||
|
else
|
||||||
|
disable = control.data.disabled
|
||||||
|
end
|
||||||
|
|
||||||
|
control.slider:SetEnabled(not disable)
|
||||||
|
control.slidervalue:SetEditEnabled(not disable)
|
||||||
|
if disable then
|
||||||
|
control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
|
||||||
|
control.minText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
|
||||||
|
control.maxText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA())
|
||||||
|
control.slidervalue:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA())
|
||||||
|
else
|
||||||
|
control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
|
||||||
|
control.minText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
|
||||||
|
control.maxText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
|
||||||
|
control.slidervalue:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function UpdateValue(control, forceDefault, value)
|
||||||
|
if forceDefault then --if we are forcing defaults
|
||||||
|
value = control.data.default
|
||||||
|
control.data.setFunc(value)
|
||||||
|
elseif value and value >= control.data.min and value <= control.data.max then
|
||||||
|
control.data.setFunc(value)
|
||||||
|
--after setting this value, let's refresh the others to see if any should be disabled or have their settings changed
|
||||||
|
if control.panel.data.registerForRefresh then
|
||||||
|
cm:FireCallbacks("LAM-RefreshPanel", control)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
value = control.data.getFunc()
|
||||||
|
end
|
||||||
|
|
||||||
|
control.slider:SetValue(value)
|
||||||
|
control.slidervalue:SetText(value)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function LAMCreateControl.slider(parent, sliderData, controlName)
|
||||||
|
local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName)
|
||||||
|
|
||||||
|
--skipping creating the backdrop... Is this the actual slider texture?
|
||||||
|
control.slider = wm:CreateControl(nil, control.container, CT_SLIDER)
|
||||||
|
local slider = control.slider
|
||||||
|
slider:SetAnchor(TOPLEFT)
|
||||||
|
slider:SetAnchor(TOPRIGHT)
|
||||||
|
slider:SetHeight(14)
|
||||||
|
slider:SetMouseEnabled(true)
|
||||||
|
slider:SetOrientation(ORIENTATION_HORIZONTAL)
|
||||||
|
--put nil for highlighted texture file path, and what look to be texture coords
|
||||||
|
slider:SetThumbTexture("EsoUI\\Art\\Miscellaneous\\scrollbox_elevator.dds", "EsoUI\\Art\\Miscellaneous\\scrollbox_elevator_disabled.dds", nil, 8, 16)
|
||||||
|
local minValue = sliderData.min
|
||||||
|
local maxValue = sliderData.max
|
||||||
|
slider:SetMinMax(minValue, maxValue)
|
||||||
|
slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end)
|
||||||
|
slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseExit(control) end)
|
||||||
|
|
||||||
|
slider.bg = wm:CreateControl(nil, slider, CT_BACKDROP)
|
||||||
|
local bg = slider.bg
|
||||||
|
bg:SetCenterColor(0, 0, 0)
|
||||||
|
bg:SetAnchor(TOPLEFT, slider, TOPLEFT, 0, 4)
|
||||||
|
bg:SetAnchor(BOTTOMRIGHT, slider, BOTTOMRIGHT, 0, -4)
|
||||||
|
bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-SliderBackdrop.dds", 32, 4)
|
||||||
|
|
||||||
|
control.minText = wm:CreateControl(nil, slider, CT_LABEL)
|
||||||
|
local minText = control.minText
|
||||||
|
minText:SetFont("ZoFontGameSmall")
|
||||||
|
minText:SetAnchor(TOPLEFT, slider, BOTTOMLEFT)
|
||||||
|
minText:SetText(sliderData.min)
|
||||||
|
|
||||||
|
control.maxText = wm:CreateControl(nil, slider, CT_LABEL)
|
||||||
|
local maxText = control.maxText
|
||||||
|
maxText:SetFont("ZoFontGameSmall")
|
||||||
|
maxText:SetAnchor(TOPRIGHT, slider, BOTTOMRIGHT)
|
||||||
|
maxText:SetText(sliderData.max)
|
||||||
|
|
||||||
|
control.slidervalueBG = wm:CreateControlFromVirtual(nil, slider, "ZO_EditBackdrop")
|
||||||
|
control.slidervalueBG:SetDimensions(50, 16)
|
||||||
|
control.slidervalueBG:SetAnchor(TOP, slider, BOTTOM, 0, 0)
|
||||||
|
control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop")
|
||||||
|
local slidervalue = control.slidervalue
|
||||||
|
slidervalue:ClearAnchors()
|
||||||
|
slidervalue:SetAnchor(TOPLEFT, control.slidervalueBG, TOPLEFT, 3, 1)
|
||||||
|
slidervalue:SetAnchor(BOTTOMRIGHT, control.slidervalueBG, BOTTOMRIGHT, -3, -1)
|
||||||
|
slidervalue:SetTextType(TEXT_TYPE_NUMERIC)
|
||||||
|
slidervalue:SetFont("ZoFontGameSmall")
|
||||||
|
slidervalue:SetHandler("OnEscape", function(self)
|
||||||
|
self:LoseFocus()
|
||||||
|
control:UpdateValue()
|
||||||
|
end)
|
||||||
|
slidervalue:SetHandler("OnEnter", function(self)
|
||||||
|
self:LoseFocus()
|
||||||
|
control:UpdateValue(false, tonumber(self:GetText()))
|
||||||
|
end)
|
||||||
|
|
||||||
|
local range = maxValue - minValue
|
||||||
|
slider:SetValueStep(sliderData.step or 1)
|
||||||
|
slider:SetHandler("OnValueChanged", function(self, value, eventReason)
|
||||||
|
if eventReason == EVENT_REASON_SOFTWARE then return end
|
||||||
|
self:SetValue(value) --do we actually need this line?
|
||||||
|
slidervalue:SetText(value)
|
||||||
|
end)
|
||||||
|
slider:SetHandler("OnSliderReleased", function(self, value)
|
||||||
|
--sliderData.setFunc(value)
|
||||||
|
control:UpdateValue(false, value) --does this work here instead?
|
||||||
|
end)
|
||||||
|
|
||||||
|
if sliderData.warning then
|
||||||
|
control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon")
|
||||||
|
control.warning:SetAnchor(RIGHT, slider, LEFT, -5, 0)
|
||||||
|
control.warning.data = {tooltipText = sliderData.warning}
|
||||||
|
end
|
||||||
|
|
||||||
|
if sliderData.disabled then
|
||||||
|
control.UpdateDisabled = UpdateDisabled
|
||||||
|
control:UpdateDisabled()
|
||||||
|
end
|
||||||
|
control.UpdateValue = UpdateValue
|
||||||
|
control:UpdateValue()
|
||||||
|
|
||||||
|
if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then --if our parent window wants to refresh controls, then add this to the list
|
||||||
|
tinsert(control.panel.controlsToRefresh, control)
|
||||||
|
end
|
||||||
|
|
||||||
|
return control
|
||||||
|
end
|
112
Libs/LibAddonMenu-2.0/controls/submenu.lua
Normal file
112
Libs/LibAddonMenu-2.0/controls/submenu.lua
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
--[[submenuData = {
|
||||||
|
type = "submenu",
|
||||||
|
name = "Submenu Title",
|
||||||
|
tooltip = "My submenu tooltip", --(optional)
|
||||||
|
controls = {sliderData, buttonData} --(optional) used by LAM
|
||||||
|
reference = "MyAddonSubmenu" --(optional) unique global reference to control
|
||||||
|
} ]]
|
||||||
|
|
||||||
|
local widgetVersion = 9
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
if not LAM:RegisterWidget("submenu", widgetVersion) then return end
|
||||||
|
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
local am = ANIMATION_MANAGER
|
||||||
|
local tinsert = table.insert
|
||||||
|
|
||||||
|
|
||||||
|
local function UpdateValue(control)
|
||||||
|
control.label:SetText(control.data.name)
|
||||||
|
if control.data.tooltip then
|
||||||
|
control.label.data.tooltipText = LAM.util.GetTooltipText(control.data.tooltip)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function AnimateSubmenu(clicked)
|
||||||
|
local control = clicked:GetParent()
|
||||||
|
control.open = not control.open
|
||||||
|
|
||||||
|
if control.open then
|
||||||
|
control.animation:PlayFromStart()
|
||||||
|
else
|
||||||
|
control.animation:PlayFromEnd()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function LAMCreateControl.submenu(parent, submenuData, controlName)
|
||||||
|
local width = parent:GetWidth() - 45
|
||||||
|
local control = wm:CreateControl(controlName or submenuData.reference, parent.scroll or parent, CT_CONTROL)
|
||||||
|
control.panel = parent
|
||||||
|
control.data = submenuData
|
||||||
|
|
||||||
|
control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel")
|
||||||
|
local label = control.label
|
||||||
|
label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5)
|
||||||
|
label:SetDimensions(width, 30)
|
||||||
|
label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS)
|
||||||
|
label:SetText(submenuData.name)
|
||||||
|
label:SetMouseEnabled(true)
|
||||||
|
if submenuData.tooltip then
|
||||||
|
label.data = {tooltipText = LAM.util.GetTooltipText(submenuData.tooltip)}
|
||||||
|
label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
|
||||||
|
label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
|
||||||
|
end
|
||||||
|
|
||||||
|
control.scroll = wm:CreateControl(nil, control, CT_SCROLL)
|
||||||
|
local scroll = control.scroll
|
||||||
|
scroll:SetParent(control)
|
||||||
|
scroll:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 10)
|
||||||
|
scroll:SetDimensionConstraints(width + 5, 0, width + 5, 2500)
|
||||||
|
|
||||||
|
control.bg = wm:CreateControl(nil, label, CT_BACKDROP)
|
||||||
|
local bg = control.bg
|
||||||
|
bg:SetAnchor(TOPLEFT, label, TOPLEFT, -5, -5)
|
||||||
|
bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0)
|
||||||
|
bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16)
|
||||||
|
bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds")
|
||||||
|
bg:SetInsets(16, 16, -16, -16)
|
||||||
|
|
||||||
|
control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE)
|
||||||
|
local arrow = control.arrow
|
||||||
|
arrow:SetDimensions(28, 28)
|
||||||
|
arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") --list_sortup for the other way
|
||||||
|
arrow:SetAnchor(TOPRIGHT, bg, TOPRIGHT, -5, 5)
|
||||||
|
|
||||||
|
--figure out the cool animation later...
|
||||||
|
control.animation = am:CreateTimeline()
|
||||||
|
local animation = control.animation
|
||||||
|
animation:SetPlaybackType(ANIMATION_SIZE, 0) --2nd arg = loop count
|
||||||
|
|
||||||
|
control:SetResizeToFitDescendents(true)
|
||||||
|
control.open = false
|
||||||
|
label:SetHandler("OnMouseUp", AnimateSubmenu)
|
||||||
|
animation:SetHandler("OnStop", function(self, completedPlaying)
|
||||||
|
scroll:SetResizeToFitDescendents(control.open)
|
||||||
|
if control.open then
|
||||||
|
control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortup.dds")
|
||||||
|
scroll:SetResizeToFitPadding(5, 20)
|
||||||
|
else
|
||||||
|
control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds")
|
||||||
|
scroll:SetResizeToFitPadding(5, 0)
|
||||||
|
scroll:SetHeight(0)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--small strip at the bottom of the submenu that you can click to close it
|
||||||
|
control.btmToggle = wm:CreateControl(nil, control, CT_TEXTURE)
|
||||||
|
local btmToggle = control.btmToggle
|
||||||
|
btmToggle:SetMouseEnabled(true)
|
||||||
|
btmToggle:SetAnchor(BOTTOMLEFT, control.scroll, BOTTOMLEFT)
|
||||||
|
btmToggle:SetAnchor(BOTTOMRIGHT, control.scroll, BOTTOMRIGHT)
|
||||||
|
btmToggle:SetHeight(15)
|
||||||
|
btmToggle:SetAlpha(0)
|
||||||
|
btmToggle:SetHandler("OnMouseUp", AnimateSubmenu)
|
||||||
|
|
||||||
|
control.UpdateValue = UpdateValue
|
||||||
|
|
||||||
|
if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then --if our parent window wants to refresh controls, then add this to the list
|
||||||
|
tinsert(control.panel.controlsToRefresh, control)
|
||||||
|
end
|
||||||
|
|
||||||
|
return control
|
||||||
|
end
|
45
Libs/LibAddonMenu-2.0/controls/texture.lua
Normal file
45
Libs/LibAddonMenu-2.0/controls/texture.lua
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
--[[textureData = {
|
||||||
|
type = "texture",
|
||||||
|
image = "file/path.dds",
|
||||||
|
imageWidth = 64, --max of 250 for half width, 510 for full
|
||||||
|
imageHeight = 32, --max of 100
|
||||||
|
tooltip = "Image's tooltip text.", --(optional)
|
||||||
|
width = "full", --or "half" (optional)
|
||||||
|
reference = "MyAddonTexture" --(optional) unique global reference to control
|
||||||
|
} ]]
|
||||||
|
|
||||||
|
--add texture coords support?
|
||||||
|
|
||||||
|
local widgetVersion = 7
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
if not LAM:RegisterWidget("texture", widgetVersion) then return end
|
||||||
|
|
||||||
|
local wm = WINDOW_MANAGER
|
||||||
|
|
||||||
|
local MIN_HEIGHT = 26
|
||||||
|
function LAMCreateControl.texture(parent, textureData, controlName)
|
||||||
|
local control = LAM.util.CreateBaseControl(parent, textureData, controlName)
|
||||||
|
local width = control:GetWidth()
|
||||||
|
control:SetResizeToFitDescendents(true)
|
||||||
|
|
||||||
|
if control.isHalfWidth then --note these restrictions
|
||||||
|
control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4)
|
||||||
|
else
|
||||||
|
control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
control.texture = wm:CreateControl(nil, control, CT_TEXTURE)
|
||||||
|
local texture = control.texture
|
||||||
|
texture:SetAnchor(CENTER)
|
||||||
|
texture:SetDimensions(textureData.imageWidth, textureData.imageHeight)
|
||||||
|
texture:SetTexture(textureData.image)
|
||||||
|
|
||||||
|
if textureData.tooltip then
|
||||||
|
texture:SetMouseEnabled(true)
|
||||||
|
texture.data = {tooltipText = LAM.util.GetTooltipText(textureData.tooltip)}
|
||||||
|
texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
|
||||||
|
texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseExit)
|
||||||
|
end
|
||||||
|
|
||||||
|
return control
|
||||||
|
end
|
36
Libs/LibStub/LibStub.lua
Normal file
36
Libs/LibStub/LibStub.lua
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
|
||||||
|
-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
|
||||||
|
-- LibStub developed for World of Warcraft by above members of the WowAce community.
|
||||||
|
-- Ported to Elder Scrolls Online by Seerah
|
||||||
|
|
||||||
|
local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 3
|
||||||
|
local LibStub = _G[LIBSTUB_MAJOR]
|
||||||
|
|
||||||
|
local strformat = string.format
|
||||||
|
if not LibStub or LibStub.minor < LIBSTUB_MINOR then
|
||||||
|
LibStub = LibStub or {libs = {}, minors = {} }
|
||||||
|
_G[LIBSTUB_MAJOR] = LibStub
|
||||||
|
LibStub.minor = LIBSTUB_MINOR
|
||||||
|
|
||||||
|
function LibStub:NewLibrary(major, minor)
|
||||||
|
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
|
||||||
|
if type(minor) ~= "number" then
|
||||||
|
minor = assert(tonumber(zo_strmatch(minor, "%d+%.?%d*")), "Minor version must either be a number or contain a number.")
|
||||||
|
end
|
||||||
|
|
||||||
|
local oldminor = self.minors[major]
|
||||||
|
if oldminor and oldminor >= minor then return nil end
|
||||||
|
self.minors[major], self.libs[major] = minor, self.libs[major] or {}
|
||||||
|
return self.libs[major], oldminor
|
||||||
|
end
|
||||||
|
|
||||||
|
function LibStub:GetLibrary(major, silent)
|
||||||
|
if not self.libs[major] and not silent then
|
||||||
|
error(strformat("Cannot find a library instance of %q.", tostring(major)), 2)
|
||||||
|
end
|
||||||
|
return self.libs[major], self.minors[major]
|
||||||
|
end
|
||||||
|
|
||||||
|
function LibStub:IterateLibraries() return pairs(self.libs) end
|
||||||
|
setmetatable(LibStub, { __call = LibStub.GetLibrary })
|
||||||
|
end
|
119
Libs/exampleoptions.lua
Normal file
119
Libs/exampleoptions.lua
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
local panelData = {
|
||||||
|
type = "panel",
|
||||||
|
name = "Window Title",
|
||||||
|
displayName = "Longer Window Title",
|
||||||
|
author = "Seerah",
|
||||||
|
version = "1.3",
|
||||||
|
slashCommand = "/myaddon", --(optional) will register a keybind to open to this panel
|
||||||
|
registerForRefresh = true, --boolean (optional) (will refresh all options controls when a setting is changed and when the panel is shown)
|
||||||
|
registerForDefaults = true, --boolean (optional) (will set all options controls back to default values)
|
||||||
|
}
|
||||||
|
|
||||||
|
local optionsTable = {
|
||||||
|
[1] = {
|
||||||
|
type = "header",
|
||||||
|
name = "My Header",
|
||||||
|
width = "full", --or "half" (optional)
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
type = "description",
|
||||||
|
--title = "My Title", --(optional)
|
||||||
|
title = nil, --(optional)
|
||||||
|
text = "My description text to display. blah blah blah blah blah blah blah - even more sample text!!",
|
||||||
|
width = "full", --or "half" (optional)
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
type = "dropdown",
|
||||||
|
name = "My Dropdown",
|
||||||
|
tooltip = "Dropdown's tooltip text.",
|
||||||
|
choices = {"table", "of", "choices"},
|
||||||
|
getFunc = function() return "of" end,
|
||||||
|
setFunc = function(var) print(var) end,
|
||||||
|
width = "half", --or "half" (optional)
|
||||||
|
warning = "Will need to reload the UI.", --(optional)
|
||||||
|
},
|
||||||
|
[4] = {
|
||||||
|
type = "dropdown",
|
||||||
|
name = "My Dropdown",
|
||||||
|
tooltip = "Dropdown's tooltip text.",
|
||||||
|
choices = {"table", "of", "choices"},
|
||||||
|
getFunc = function() return "of" end,
|
||||||
|
setFunc = function(var) print(var) end,
|
||||||
|
width = "half", --or "half" (optional)
|
||||||
|
warning = "Will need to reload the UI.", --(optional)
|
||||||
|
},
|
||||||
|
[5] = {
|
||||||
|
type = "slider",
|
||||||
|
name = "My Slider",
|
||||||
|
tooltip = "Slider's tooltip text.",
|
||||||
|
min = 0,
|
||||||
|
max = 20,
|
||||||
|
step = 1, --(optional)
|
||||||
|
getFunc = function() return 3 end,
|
||||||
|
setFunc = function(value) d(value) end,
|
||||||
|
width = "half", --or "half" (optional)
|
||||||
|
default = 5, --(optional)
|
||||||
|
},
|
||||||
|
[6] = {
|
||||||
|
type = "button",
|
||||||
|
name = "My Button",
|
||||||
|
tooltip = "Button's tooltip text.",
|
||||||
|
func = function() d("button pressed!") end,
|
||||||
|
width = "half", --or "half" (optional)
|
||||||
|
warning = "Will need to reload the UI.", --(optional)
|
||||||
|
},
|
||||||
|
[7] = {
|
||||||
|
type = "submenu",
|
||||||
|
name = "Submenu Title",
|
||||||
|
tooltip = "My submenu tooltip", --(optional)
|
||||||
|
controls = {
|
||||||
|
[1] = {
|
||||||
|
type = "checkbox",
|
||||||
|
name = "My Checkbox",
|
||||||
|
tooltip = "Checkbox's tooltip text.",
|
||||||
|
getFunc = function() return true end,
|
||||||
|
setFunc = function(value) d(value) end,
|
||||||
|
width = "half", --or "half" (optional)
|
||||||
|
warning = "Will need to reload the UI.", --(optional)
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
type = "colorpicker",
|
||||||
|
name = "My Color Picker",
|
||||||
|
tooltip = "Color Picker's tooltip text.",
|
||||||
|
getFunc = function() return 1, 0, 0, 1 end, --(alpha is optional)
|
||||||
|
setFunc = function(r,g,b,a) print(r, g, b, a) end, --(alpha is optional)
|
||||||
|
width = "half", --or "half" (optional)
|
||||||
|
warning = "warning text",
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
type = "editbox",
|
||||||
|
name = "My Editbox",
|
||||||
|
tooltip = "Editbox's tooltip text.",
|
||||||
|
getFunc = function() return "this is some text" end,
|
||||||
|
setFunc = function(text) print(text) end,
|
||||||
|
isMultiline = false, --boolean
|
||||||
|
width = "half", --or "half" (optional)
|
||||||
|
warning = "Will need to reload the UI.", --(optional)
|
||||||
|
default = "", --(optional)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[8] = {
|
||||||
|
type = "custom",
|
||||||
|
reference = "MyAddonCustomControl", --unique name for your control to use as reference
|
||||||
|
refreshFunc = function(customControl) end, --(optional) function to call when panel/controls refresh
|
||||||
|
width = "half", --or "half" (optional)
|
||||||
|
},
|
||||||
|
[9] = {
|
||||||
|
type = "texture",
|
||||||
|
image = "EsoUI\\Art\\ActionBar\\abilityframe64_up.dds",
|
||||||
|
imageWidth = 64, --max of 250 for half width, 510 for full
|
||||||
|
imageHeight = 64, --max of 100
|
||||||
|
tooltip = "Image's tooltip text.", --(optional)
|
||||||
|
width = "half", --or "half" (optional)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local LAM = LibStub("LibAddonMenu-2.0")
|
||||||
|
LAM:RegisterAddonPanel("MyAddon", panelData)
|
||||||
|
LAM:RegisterOptionControls("MyAddon", optionsTable)
|
Loading…
Reference in New Issue
Block a user