diff --git a/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua index b104979..2cdb271 100644 --- a/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua +++ b/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua @@ -1,33 +1,33 @@ --- LibAddonMenu-2.0 & its files © Ryan Lakanen (Seerah) -- --- Distributed under The Artistic License 2.0 (see LICENSE) -- +-- 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", 20 +local MAJOR, MINOR = "LibAddonMenu-2.0", 21 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 +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 + 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 = {} + 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 + 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-- @@ -38,76 +38,126 @@ local cm = CALLBACK_MANAGER local tconcat = table.concat local tinsert = table.insert +local MIN_HEIGHT = 26 +local HALF_WIDTH_LINE_SPACING = 2 +local OPTIONS_CREATION_RUNNING = 1 +local OPTIONS_CREATED = 2 +local LAM_CONFIRM_DIALOG = "LAM_CONFIRM_DIALOG" + local addonsForList = {} local addonToOptionsMap = {} -local optionsCreated = {} +local optionsState = {} lam.widgets = lam.widgets or {} local widgets = lam.widgets -lam.util = {} +lam.util = lam.util or {} local util = lam.util local function GetDefaultValue(default) - if type(default) == "function" then - return default() - end - return default + if type(default) == "function" then + return default() + end + return default end local function GetStringFromValue(value) - if type(value) == "function" then - return value() - elseif type(value) == "number" then - return GetString(value) - end - return value + if type(value) == "function" then + return value() + elseif type(value) == "number" then + return GetString(value) + end + return value 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" - local width = 510 -- set default width in case a custom parent object is passed - if control.panel.GetWidth ~= nil then width = control.panel:GetWidth() - 60 end - control:SetWidth(width) - return control + 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" + local width = 510 -- set default width in case a custom parent object is passed + if control.panel.GetWidth ~= nil then width = control.panel:GetWidth() - 60 end + control:SetWidth(width) + 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(GetStringFromValue(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 = GetStringFromValue(control.data.tooltip) - control:SetMouseEnabled(true) - control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - return control + 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(GetStringFromValue(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 = GetStringFromValue(control.data.tooltip) + control:SetMouseEnabled(true) + control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + return control +end + +local function RequestRefreshIfNeeded(control) + if control.panel.data.registerForRefresh then + cm:FireCallbacks("LAM-RefreshPanel", control) + end +end + +local function RegisterForRefreshIfNeeded(control) + -- if our parent window wants to refresh controls, then add this to the list + local panelData = control.panel.data + if panelData.registerForRefresh or panelData.registerForDefaults then + tinsert(control.panel.controlsToRefresh, control) + end +end + +local function GetConfirmDialog() + if(not ESO_Dialogs[LAM_CONFIRM_DIALOG]) then + ESO_Dialogs[LAM_CONFIRM_DIALOG] = { + canQueue = true, + title = { + text = "", + }, + mainText = { + text = "", + }, + buttons = { + [1] = { + text = SI_DIALOG_CONFIRM, + callback = function(dialog) end, + }, + [2] = { + text = SI_DIALOG_CANCEL, + } + } + } + end + return ESO_Dialogs[LAM_CONFIRM_DIALOG] +end + +local function ShowConfirmationDialog(title, body, callback) + local dialog = GetConfirmDialog() + dialog.title.text = title + dialog.mainText.text = body + dialog.buttons[1].callback = callback + ZO_Dialogs_ShowDialog(LAM_CONFIRM_DIALOG) end util.GetTooltipText = GetStringFromValue -- deprecated, use util.GetStringFromValue instead @@ -115,6 +165,9 @@ util.GetStringFromValue = GetStringFromValue util.GetDefaultValue = GetDefaultValue util.CreateBaseControl = CreateBaseControl util.CreateLabelAndContainerControl = CreateLabelAndContainerControl +util.RequestRefreshIfNeeded = RequestRefreshIfNeeded +util.RegisterForRefreshIfNeeded = RegisterForRefreshIfNeeded +util.ShowConfirmationDialog = ShowConfirmationDialog local ADDON_DATA_TYPE = 1 local RESELECTING_DURING_REBUILD = true @@ -123,98 +176,98 @@ 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) +-- 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 +-- 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 + 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) +-- * 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 +-- and returns true iff `data.filterText` matches the pattern local function GetSearchFilterFunc(searchEdit) - local text = searchEdit:GetText():lower() - local pattern = text:match("(%S+.-)%s*$") + local text = searchEdit:GetText():lower() + local pattern = text:match("(%S+.-)%s*$") - if not pattern then -- nothing but whitespace - return nil - end + if not pattern then -- nothing but whitespace + return nil + end - -- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de" - pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0") + -- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de" + pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0") - -- replace whitespace with "match shortest anything" - pattern = pattern:gsub("%s+", ".-") + -- replace whitespace with "match shortest anything" + pattern = pattern:gsub("%s+", ".-") - return function(data) - return data.filterText:lower():find(pattern) ~= nil - end + 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) +-- 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 + 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 @@ -222,245 +275,252 @@ end --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 +-- 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 + if widgets[widgetType] and widgets[widgetType] >= widgetVersion then + return false + else + widgets[widgetType] = widgetVersion + return true + end end -- INTERNAL METHOD: fires the LAM-PanelOpened callback if not already done local function OpenCurrentPanel() - if(lam.currentAddonPanel and not lam.currentPanelOpened) then - lam.currentPanelOpened = true - cm:FireCallbacks("LAM-PanelOpened", lam.currentAddonPanel) - end + if(lam.currentAddonPanel and not lam.currentPanelOpened) then + lam.currentPanelOpened = true + cm:FireCallbacks("LAM-PanelOpened", lam.currentAddonPanel) + end end -- INTERNAL METHOD: fires the LAM-PanelClosed callback if not already done local function CloseCurrentPanel() - if(lam.currentAddonPanel and lam.currentPanelOpened) then - lam.currentPanelOpened = false - cm:FireCallbacks("LAM-PanelClosed", lam.currentAddonPanel) - end + if(lam.currentAddonPanel and lam.currentPanelOpened) then + lam.currentPanelOpened = false + cm:FireCallbacks("LAM-PanelClosed", lam.currentAddonPanel) + 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 +-- 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 + -- 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 local TwinOptionsContainer_Index = 0 local function TwinOptionsContainer(parent, leftWidget, rightWidget) - TwinOptionsContainer_Index = TwinOptionsContainer_Index + 1 - local cParent = parent.scroll or parent - local panel = parent.panel or cParent - local container = wm:CreateControl("$(parent)TwinContainer" .. tostring(TwinOptionsContainer_Index), - cParent, CT_CONTROL) - container:SetResizeToFitDescendents(true) - container:SetAnchor(select(2, leftWidget:GetAnchor(0) )) - - leftWidget:ClearAnchors() - leftWidget:SetAnchor(TOPLEFT, container, TOPLEFT) - rightWidget:SetAnchor(TOPLEFT, leftWidget, TOPRIGHT, 5, 0) - - leftWidget:SetWidth( leftWidget:GetWidth() - 2.5 ) -- fixes bad alignment with 'full' controls - rightWidget:SetWidth( rightWidget:GetWidth() - 2.5 ) - - leftWidget:SetParent(container) - rightWidget:SetParent(container) - - container.data = {type = "container"} - container.panel = panel - return container + TwinOptionsContainer_Index = TwinOptionsContainer_Index + 1 + local cParent = parent.scroll or parent + local panel = parent.panel or cParent + local container = wm:CreateControl("$(parent)TwinContainer" .. tostring(TwinOptionsContainer_Index), + cParent, CT_CONTROL) + container:SetResizeToFitDescendents(true) + container:SetAnchor(select(2, leftWidget:GetAnchor(0) )) + + leftWidget:ClearAnchors() + leftWidget:SetAnchor(TOPLEFT, container, TOPLEFT) + rightWidget:SetAnchor(TOPLEFT, leftWidget, TOPRIGHT, 5, 0) + + leftWidget:SetWidth( leftWidget:GetWidth() - 2.5 ) -- fixes bad alignment with 'full' controls + rightWidget:SetWidth( rightWidget:GetWidth() - 2.5 ) + + leftWidget:SetParent(container) + rightWidget:SetParent(container) + + container.data = {type = "container"} + container.panel = panel + return container 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.lineControl = anchorTarget - isHalf = false - offsetY = 0 - anchorTarget = TwinOptionsContainer(parent, anchorTarget, widget) - else -- otherwise we just put it below the previous one normally - widget:SetAnchor(TOPLEFT, anchorTarget, BOTTOMLEFT, 0, 15) - 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) - OpenCurrentPanel() - end - end - - if SetupCreationCalls(panel, optionsTable) then - PrintLater(("The settings menu of %s is missing some entries."):format(addonID)) - end - DoCreateSettings() - else - optionsCreated[addonID] = true - cm:FireCallbacks("LAM-PanelControlsCreated", panel) - OpenCurrentPanel() - end + local addonID = panel:GetName() + if(optionsState[addonID] == OPTIONS_CREATED) then + return false + elseif(optionsState[addonID] == OPTIONS_CREATION_RUNNING) then + return true + end + optionsState[addonID] = OPTIONS_CREATION_RUNNING + + local function CreationFinished() + optionsState[addonID] = OPTIONS_CREATED + cm:FireCallbacks("LAM-PanelControlsCreated", panel) + OpenCurrentPanel() + end + + 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.lineControl = anchorTarget + isHalf = false + offsetY = 0 + anchorTarget = TwinOptionsContainer(parent, anchorTarget, widget) + else -- otherwise we just put it below the previous one normally + widget:SetAnchor(TOPLEFT, anchorTarget, BOTTOMLEFT, 0, 15) + 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 + CreationFinished() + end + end + + if SetupCreationCalls(panel, optionsTable) then + PrintLater(("The settings menu of %s is missing some entries."):format(addonID)) + end + DoCreateSettings() + else + CreationFinished() + end + + return true 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) - CloseCurrentPanel() - 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) - else - OpenCurrentPanel() - end - - cm:FireCallbacks("LAM-RefreshPanel", panel) +local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel + local currentlySelected = lam.currentAddonPanel + if currentlySelected and currentlySelected ~= panel then + currentlySelected:SetHidden(true) + CloseCurrentPanel() + end + lam.currentAddonPanel = panel + + -- refresh visible rows to reflect panel IsHidden status + ZO_ScrollList_RefreshVisible(lam.addonList) + + if not CreateOptionsControls(panel) then + OpenCurrentPanel() + end + + cm:FireCallbacks("LAM-RefreshPanel", panel) end local CheckSafetyAndInitialize @@ -468,40 +528,40 @@ 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 +-- 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 + 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 @@ -512,306 +572,308 @@ end --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 +-- 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) + --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 + --Japanese provided by k0ta0uchi + local controlPanelNames = { + en = "Addon Settings", + fr = "Extensions", + de = "Erweiterungen", + ru = "Îacòpoéêè äoïoìîeîèé", + es = "Configura Addons", + jp = "アドオンè¨å®š", + } + + 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 + 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 + 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 + local tlw = wm:CreateTopLevelWindow("LAMAddonSettingsWindow") + tlw:SetHidden(true) + tlw:SetDimensions(1010, 914) -- same height as ZO_OptionsWindow - ZO_ReanchorControlForLeftSidePanel(tlw) + ZO_ReanchorControlForLeftSidePanel(tlw) - -- create black background for the window (mimic ZO_RightFootPrintBackground) + -- 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 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) + 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) + -- 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 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) + 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) + -- 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 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) + local divider = wm:CreateControlFromVirtual("$(parent)Divider", tlw, "ZO_Options_Divider") + divider:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 108) - -- create search filter box + -- create search filter box - local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw) - srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120) - srchBox:SetDimensions(260, 30) + local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw) + srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120) + srchBox:SetDimensions(260, 30) - -- create scrollable addon list + -- create scrollable addon list - local addonList = CreateAddonList("$(parent)AddonList", tlw) - addonList:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 160) - addonList:SetDimensions(285, 665) + 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 + lam.addonList = addonList -- for easy access from elsewhere - -- create container for option panels + -- 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) + local panelContainer = wm:CreateControl("$(parent)PanelContainer", tlw, CT_CONTROL) + panelContainer:SetAnchor(TOPLEFT, nil, TOPLEFT, 365, 120) + panelContainer:SetDimensions(645, 675) - return tlw + return tlw end @@ -821,57 +883,51 @@ 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 + -- 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() - - -- a little something for 4/1. Please keep it a secret ;-) The code was minified with https://mothereff.in/lua-minifier and the original code can be found at https://gist.github.com/sirinsidiator/6f8863ff66c9919dfe01 - if GetDate()%1000~=401 then ZO_Ingame_SavedVariables["LAM"]=nil;return end;local a,b=pcall(error,"")local c=b:match("user:/AddOns/(.*)LibAddonMenu.-.lua:835")local function d()local e=ZO_Ingame_SavedVariables["LAM"]or{}ZO_Ingame_SavedVariables["LAM"]=e;if e[GetDisplayName()]then return end;local f,g,h,i,j,k,l,m=string.rep,string.format,math.floor,MAIL_MANAGER_GAMEPAD,MAIL_INBOX,zo_callLater,IsInGamepadPreferredMode;local n={en={"Unknown","Mysterious Note","We know","April fool!\nThe addon community wishes you a happy April Fools' Day!",0},de={"Unbekannt","Geheimnisvolle Notiz","Wir wissen Bescheid","April, April!\nEinen guten 1. April wünscht euch eure Addon Gemeinschaft!",7},fr={"Inconnu","Note mystérieuse","Nous savons tout","Poisson d'avril!\nLes développeurs d'addons vous souhaitent un joyeux premier avril!",6}}local o=n[GetCVar("language.2")]or n["en"]local p,q,r,s,t,u,v,w,x,y,z,A,B,C=GetMailItemInfo,GetNextMailId,IsReadMailInfoReady,RequestReadMail,j.GetMailData,ReadMail,DeleteMail,GetNumUnreadMail,i.inbox,GetMailAttachmentInfo,GetAttachedItemLink,ItemTooltip.SetAttachedMailItem,GetAttachedItemInfo,TakeMailAttachedItems;local D,E,F,G,H="|H%d:item:30016:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0|h|h",c.."controls/separator.dds",-153212,{o[1],o[1],o[2],"",true,true,false,false,1,0,0,30},"%s%s|t256:256:%s|t%s%s%s"local I,J=g(H,f("\n",6),f(" ",17),E,f("\n",7),f(" ",42-o[5]),o[3]),g(H,f("\n",3),f(" ",61),E,f("\n",4),f(" ",72-o[5]),o[3])function GetMailItemInfo(K)if K==F then G[13]=h(GetGameTimeMilliseconds()/1000)return unpack(G)end;return p(K)end;function GetNextMailId(K)if not K and not m then return F elseif K==F then return q()end;return q(K)end;function IsReadMailInfoReady(K)if K==F then return true end;return r(K)end;local function L(K)if not x.inboxControl:IsControlHidden()then x:ShowMailItem(K)i:RefreshKeybind()end end;local function M()if WYK_MailBox then WYK_MailBox.ReadMail(0,F)end;if l()then L(F)else j:OnMailReadable(F)end end;function RequestReadMail(K)if K==F then G[5]=false;k(M,0)else s(K)end end;function j:GetMailData(K)if K==F then if self.masterList then for N=1,#self.masterList do local O=self.masterList[N]if O.mailId==K then return O end end end else return t(self,K)end end;function ReadMail(K)if K==F then return l()and J or I end;return u(K)end;function DeleteMail(K,P)if K==F then m=true;j:OnMailRemoved(K)i:RefreshHeader()x:RefreshMailList()e[GetDisplayName()]=true else v(K,P)end end;function GetNumUnreadMail()local Q=w()if G[5]then return Q+1 end;return Q end;function GetMailAttachmentInfo(K)if K==F and G[9]>0 then return 1,0,0 end;return y(K)end;function GetAttachedItemLink(K,R,S)if K==F and G[9]>0 then return g(D,S or 0)end;return z(K,R,S)end;function ItemTooltip:SetAttachedMailItem(K,T)if K==F and G[9]>0 then self:SetLink(GetAttachedItemLink(K,T))else A(self,K,T)end end;function GetAttachedItemInfo(K,R)if K==F and G[9]>0 then local U,V,W,X,Y=GetItemLinkInfo(g(D,1))return U,1,nil,V,W,X,Y,2 end;return B(K,R)end;function TakeMailAttachedItems(K)if K==F then LORE_READER:Show(o[1],o[4],4,false,"loreLibrary")SCENE_MANAGER:Show("loreReaderInteraction")G[9]=0;j:OnTakeAttachedItemSuccess(K)else C(K)end end;CHAT_SYSTEM:OnNumUnreadMailChanged(GetNumUnreadMail())end;pcall(d) + 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 + 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") + 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) - LAMAddonSettingsFragment:RegisterCallback("StateChange", function(oldState, newState) - if(newState == SCENE_FRAGMENT_SHOWN) then - OpenCurrentPanel() - elseif(newState == SCENE_FRAGMENT_HIDDEN) then - CloseCurrentPanel() - end - end) - CreateAddonSettingsMenuEntry() - end - return LAMAddonSettingsFragment -end - - --- vi: noexpandtab + assert(hasInitialized or safeToInitialize) + if not LAMAddonSettingsFragment then + local window = CreateAddonSettingsWindow() + LAMAddonSettingsFragment = ZO_FadeSceneFragment:New(window, true, 100) + LAMAddonSettingsFragment:RegisterCallback("StateChange", function(oldState, newState) + if(newState == SCENE_FRAGMENT_SHOWN) then + OpenCurrentPanel() + elseif(newState == SCENE_FRAGMENT_HIDDEN) then + CloseCurrentPanel() + end + end) + CreateAddonSettingsMenuEntry() + end + return LAMAddonSettingsFragment +end diff --git a/lib/LibAddonMenu-2.0/controls/button.lua b/lib/LibAddonMenu-2.0/controls/button.lua index 340ff35..9bf5c01 100644 --- a/lib/LibAddonMenu-2.0/controls/button.lua +++ b/lib/LibAddonMenu-2.0/controls/button.lua @@ -1,89 +1,90 @@ --[[buttonData = { - type = "button", - name = "My Button", -- string id or function returning a string - func = function() end, - tooltip = "Button's tooltip text.", -- string id or function returning a string (optional) - 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", -- unique global reference to control (optional) -} ]] + type = "button", + name = "My Button", -- string id or function returning a string + func = function() end, + tooltip = "Button's tooltip text.", -- string id or function returning a string (optional) + width = "full", --or "half" (optional) + disabled = function() return db.someBooleanSetting end, --or boolean (optional) + icon = "icon\\path.dds", --(optional) + isDangerous = false, -- boolean, if set to true, the button text will be red and a confirmation dialog with the button label and warning text will show on click before the callback is executed (optional) + warning = "Will need to reload the UI.", --(optional) + reference = "MyAddonButton", -- unique global reference to control (optional) +} ]] - -local widgetVersion = 9 +local widgetVersion = 10 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) + local disable = control.data.disabled + if type(disable) == "function" then + disable = disable() + 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 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 - 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(LAM.util.GetStringFromValue(buttonData.name)) + if buttonData.isDangerous then control.button:SetNormalFontColor(ZO_ERROR_COLOR:UnpackRGBA()) end + end + local button = control.button + button:SetAnchor(control.isHalfWidth and CENTER or RIGHT) + button:SetClickSound("Click") + button.data = {tooltipText = LAM.util.GetStringFromValue(buttonData.tooltip)} + button:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + button:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + button:SetHandler("OnClicked", function(...) + local args = {...} + local function callback() + buttonData.func(unpack(args)) + LAM.util.RequestRefreshIfNeeded(control) + 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(LAM.util.GetStringFromValue(buttonData.name)) - end - local button = control.button - button:SetAnchor(control.isHalfWidth and CENTER or RIGHT) - button:SetClickSound("Click") - button.data = {tooltipText = LAM.util.GetStringFromValue(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.isDangerous) then + local title = LAM.util.GetStringFromValue(buttonData.name) + local body = LAM.util.GetStringFromValue(buttonData.warning) + LAM.util.ShowConfirmationDialog(title, body, callback) + else + callback() + 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 = LAM.util.GetStringFromValue(buttonData.warning)} - 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 = LAM.util.GetStringFromValue(buttonData.warning)} + end - if buttonData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() + if buttonData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end - --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 + LAM.util.RegisterForRefreshIfNeeded(control) - return control + return control end diff --git a/lib/LibAddonMenu-2.0/controls/checkbox.lua b/lib/LibAddonMenu-2.0/controls/checkbox.lua index 0b9ea48..6e34fec 100644 --- a/lib/LibAddonMenu-2.0/controls/checkbox.lua +++ b/lib/LibAddonMenu-2.0/controls/checkbox.lua @@ -1,24 +1,23 @@ --[[checkboxData = { - type = "checkbox", - name = "My Checkbox", -- or string id or function returning a string - getFunc = function() return db.var end, - setFunc = function(value) db.var = value doStuff() end, - tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional) - width = "full", -- or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "Will need to reload the UI.", -- or string id or function returning a string (optional) - default = defaults.var, -- a boolean or function that returns a boolean (optional) - reference = "MyAddonCheckbox", -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 11 + type = "checkbox", + name = "My Checkbox", -- or string id or function returning a string + getFunc = function() return db.var end, + setFunc = function(value) db.var = value doStuff() end, + tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, --or boolean (optional) + warning = "Will need to reload the UI.", -- or string id or function returning a string (optional) + default = defaults.var, -- a boolean or function that returns a boolean (optional) + reference = "MyAddonCheckbox", -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 12 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 @@ -30,115 +29,111 @@ 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 + 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 + 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 = LAM.util.GetDefaultValue(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) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(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 + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + end + control.value = value + + ToggleCheckbox(control) end local function OnMouseEnter(control) - ZO_Options_OnMouseEnter(control) + ZO_Options_OnMouseEnter(control) - if control.isDisabled then return end + 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()) + 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) + ZO_Options_OnMouseExit(control) - if control.isDisabled then return end + 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()) + 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 = LAM.util.GetStringFromValue(checkboxData.warning)} - end - - control.data.tooltipText = LAM.util.GetStringFromValue(checkboxData.tooltip) - - if checkboxData.disabled ~= nil 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 + 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 = LAM.util.GetStringFromValue(checkboxData.warning)} + end + + control.data.tooltipText = LAM.util.GetStringFromValue(checkboxData.tooltip) + + control.UpdateValue = UpdateValue + control:UpdateValue() + if checkboxData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control end diff --git a/lib/LibAddonMenu-2.0/controls/colorpicker.lua b/lib/LibAddonMenu-2.0/controls/colorpicker.lua index afb6063..eb5855a 100644 --- a/lib/LibAddonMenu-2.0/controls/colorpicker.lua +++ b/lib/LibAddonMenu-2.0/controls/colorpicker.lua @@ -1,110 +1,103 @@ --[[colorpickerData = { - type = "colorpicker", - name = "My Color Picker", -- or string id or function returning a string - 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) - tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "Will need to reload the UI.", -- or string id or function returning a string (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]) or a function that returns the color - reference = "MyAddonColorpicker" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 10 + type = "colorpicker", + name = "My Color Picker", -- or string id or function returning a string + 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) + tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) + width = "full", --or "half" (optional) + disabled = function() return db.someBooleanSetting end, --or boolean (optional) + warning = "Will need to reload the UI.", -- or string id or function returning a string (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]) or a function that returns the color + reference = "MyAddonColorpicker" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 11 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 + 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 = LAM.util.GetDefaultValue(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) + if forceDefault then --if we are forcing defaults + local color = LAM.util.GetDefaultValue(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 + LAM.util.RequestRefreshIfNeeded(control) + 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, LAM.util.GetStringFromValue(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 = LAM.util.GetStringFromValue(colorpickerData.warning)} - end - - control.data.tooltipText = LAM.util.GetStringFromValue(colorpickerData.tooltip) - - if colorpickerData.disabled ~= nil 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 + 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, LAM.util.GetStringFromValue(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 = LAM.util.GetStringFromValue(colorpickerData.warning)} + end + + control.data.tooltipText = LAM.util.GetStringFromValue(colorpickerData.tooltip) + + control.UpdateValue = UpdateValue + control:UpdateValue() + if colorpickerData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control end diff --git a/lib/LibAddonMenu-2.0/controls/custom.lua b/lib/LibAddonMenu-2.0/controls/custom.lua index 921402a..40a7c42 100644 --- a/lib/LibAddonMenu-2.0/controls/custom.lua +++ b/lib/LibAddonMenu-2.0/controls/custom.lua @@ -1,40 +1,35 @@ --[[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) -} ]] + 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 widgetVersion = 7 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 + 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) + 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 + 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 + 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 + LAM.util.RegisterForRefreshIfNeeded(control) - return control -end \ No newline at end of file + return control +end diff --git a/lib/LibAddonMenu-2.0/controls/description.lua b/lib/LibAddonMenu-2.0/controls/description.lua index c9211ee..da207a0 100644 --- a/lib/LibAddonMenu-2.0/controls/description.lua +++ b/lib/LibAddonMenu-2.0/controls/description.lua @@ -1,10 +1,10 @@ --[[descriptionData = { - type = "description", - text = "My description text to display.", -- or string id or function returning a string - title = "My Title", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - reference = "MyAddonDescription" -- unique global reference to control (optional) -} ]] + type = "description", + text = "My description text to display.", -- or string id or function returning a string + title = "My Title", -- or string id or function returning a string (optional) + width = "full", --or "half" (optional) + reference = "MyAddonDescription" -- unique global reference to control (optional) +} ]] local widgetVersion = 8 @@ -12,52 +12,49 @@ 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(LAM.util.GetStringFromValue(control.data.title)) - end - control.desc:SetText(LAM.util.GetStringFromValue(control.data.text)) + if control.title then + control.title:SetText(LAM.util.GetStringFromValue(control.data.title)) + end + control.desc:SetText(LAM.util.GetStringFromValue(control.data.text)) end 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, 0, width / 2, 0) - else - control:SetDimensionConstraints(width, 0, width, 0) - end - - control.desc = wm:CreateControl(nil, control, CT_LABEL) - local desc = control.desc - desc:SetVerticalAlignment(TEXT_ALIGN_TOP) - desc:SetFont("ZoFontGame") - desc:SetText(LAM.util.GetStringFromValue(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(LAM.util.GetStringFromValue(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 \ No newline at end of file + 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, 0, width / 2, 0) + else + control:SetDimensionConstraints(width, 0, width, 0) + end + + control.desc = wm:CreateControl(nil, control, CT_LABEL) + local desc = control.desc + desc:SetVerticalAlignment(TEXT_ALIGN_TOP) + desc:SetFont("ZoFontGame") + desc:SetText(LAM.util.GetStringFromValue(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(LAM.util.GetStringFromValue(descriptionData.title)) + desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT) + else + desc:SetAnchor(TOPLEFT) + end + + control.UpdateValue = UpdateValue + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control + +end diff --git a/lib/LibAddonMenu-2.0/controls/dropdown.lua b/lib/LibAddonMenu-2.0/controls/dropdown.lua index 6ed4370..0e5d3e2 100644 --- a/lib/LibAddonMenu-2.0/controls/dropdown.lua +++ b/lib/LibAddonMenu-2.0/controls/dropdown.lua @@ -1,131 +1,124 @@ --[[dropdownData = { - type = "dropdown", - name = "My Dropdown", -- or string id or function returning a string - choices = {"table", "of", "choices"}, - getFunc = function() return db.var end, - setFunc = function(var) db.var = var doStuff() end, - tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional) - sort = "name-up", --or "name-down", "numeric-up", "numeric-down" (optional) - if not provided, list will not be sorted - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "Will need to reload the UI.", -- or string id or function returning a string (optional) - default = defaults.var, -- default value or function that returns the default value (optional) - reference = "MyAddonDropdown" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 12 + type = "dropdown", + name = "My Dropdown", -- or string id or function returning a string + choices = {"table", "of", "choices"}, + getFunc = function() return db.var end, + setFunc = function(var) db.var = var doStuff() end, + tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional) + sort = "name-up", --or "name-down", "numeric-up", "numeric-down" (optional) - if not provided, list will not be sorted + width = "full", --or "half" (optional) + disabled = function() return db.someBooleanSetting end, --or boolean (optional) + warning = "Will need to reload the UI.", -- or string id or function returning a string (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonDropdown" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 13 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 + 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 = LAM.util.GetDefaultValue(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 + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(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 + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.dropdown:SetSelectedItem(value) + end end local function DropdownCallback(control, choiceText, choice) - choice.control:UpdateValue(false, choiceText) + 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 + 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 + local t, i = {}, 1 + for info in string.gmatch(sortInfo, "([^%-]+)") do + t[i] = info + i = i + 1 + end - return t + 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 = LAM.util.GetStringFromValue(dropdownData.warning)} - end - - if dropdownData.disabled ~= nil 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 + 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 = LAM.util.GetStringFromValue(dropdownData.warning)} + end + + control.UpdateChoices = UpdateChoices + control:UpdateChoices(dropdownData.choices) + control.UpdateValue = UpdateValue + control:UpdateValue() + if dropdownData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control end diff --git a/lib/LibAddonMenu-2.0/controls/editbox.lua b/lib/LibAddonMenu-2.0/controls/editbox.lua index fdcadfb..d7e2054 100644 --- a/lib/LibAddonMenu-2.0/controls/editbox.lua +++ b/lib/LibAddonMenu-2.0/controls/editbox.lua @@ -1,160 +1,153 @@ --[[editboxData = { - type = "editbox", - name = "My Editbox", -- or string id or function returning a string - getFunc = function() return db.text end, - setFunc = function(text) db.text = text doStuff() end, - tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional) - isMultiline = true, --boolean (optional) - isExtraWide = true, --boolean (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "Will need to reload the UI.", -- or string id or function returning a string (optional) - default = defaults.text, -- default value or function that returns the default value (optional) - reference = "MyAddonEditbox" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 11 + type = "editbox", + name = "My Editbox", -- or string id or function returning a string + getFunc = function() return db.text end, + setFunc = function(text) db.text = text doStuff() end, + tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional) + isMultiline = true, --boolean (optional) + isExtraWide = true, --boolean (optional) + width = "full", --or "half" (optional) + disabled = function() return db.someBooleanSetting end, --or boolean (optional) + warning = "Will need to reload the UI.", -- or string id or function returning a string (optional) + default = defaults.text, -- default value or function that returns the default value (optional) + reference = "MyAddonEditbox" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 12 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) + 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 = LAM.util.GetDefaultValue(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 + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(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 + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.editbox:SetText(value) + end end local MIN_HEIGHT = 24 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) - - local MIN_WIDTH = (parent.GetWidth and (parent:GetWidth() / 10)) or (parent.panel.GetWidth and (parent.panel:GetWidth() / 10)) or 0 - - control.label:ClearAnchors() - container:ClearAnchors() - - control.label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) - container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) - - if control.isHalfWidth then - container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) - end - - if editboxData.isExtraWide then - container:SetAnchor(BOTTOMLEFT, control, BOTTOMLEFT, 0, 0) - else - container:SetWidth(MIN_WIDTH * 3.2) - end - - if editboxData.isMultiline then - container:SetHeight(MIN_HEIGHT * 3) - else - container:SetHeight(MIN_HEIGHT) - end - - if control.isHalfWidth ~= true and editboxData.isExtraWide ~= true then - control:SetHeight(container:GetHeight()) - else - control:SetHeight(container:GetHeight() + control.label:GetHeight()) - end - - editbox:ClearAnchors() - editbox:SetAnchor(TOPLEFT, container, TOPLEFT, 2, 2) - editbox:SetAnchor(BOTTOMRIGHT, container, BOTTOMRIGHT, -2, -2) - - if editboxData.warning then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - if editboxData.isExtraWide then - control.warning:SetAnchor(BOTTOMRIGHT, control.bg, TOPRIGHT, 2, 0) - else - control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0) - end - control.warning.data = {tooltipText = LAM.util.GetStringFromValue(editboxData.warning)} - end - - if editboxData.disabled ~= nil 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 + 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) + + local MIN_WIDTH = (parent.GetWidth and (parent:GetWidth() / 10)) or (parent.panel.GetWidth and (parent.panel:GetWidth() / 10)) or 0 + + control.label:ClearAnchors() + container:ClearAnchors() + + control.label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) + + if control.isHalfWidth then + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) + end + + if editboxData.isExtraWide then + container:SetAnchor(BOTTOMLEFT, control, BOTTOMLEFT, 0, 0) + else + container:SetWidth(MIN_WIDTH * 3.2) + end + + if editboxData.isMultiline then + container:SetHeight(MIN_HEIGHT * 3) + else + container:SetHeight(MIN_HEIGHT) + end + + if control.isHalfWidth ~= true and editboxData.isExtraWide ~= true then + control:SetHeight(container:GetHeight()) + else + control:SetHeight(container:GetHeight() + control.label:GetHeight()) + end + + editbox:ClearAnchors() + editbox:SetAnchor(TOPLEFT, container, TOPLEFT, 2, 2) + editbox:SetAnchor(BOTTOMRIGHT, container, BOTTOMRIGHT, -2, -2) + + if editboxData.warning then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + if editboxData.isExtraWide then + control.warning:SetAnchor(BOTTOMRIGHT, control.bg, TOPRIGHT, 2, 0) + else + control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0) + end + control.warning.data = {tooltipText = LAM.util.GetStringFromValue(editboxData.warning)} + end + + control.UpdateValue = UpdateValue + control:UpdateValue() + if editboxData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control end diff --git a/lib/LibAddonMenu-2.0/controls/header.lua b/lib/LibAddonMenu-2.0/controls/header.lua index 72ead4b..eadff38 100644 --- a/lib/LibAddonMenu-2.0/controls/header.lua +++ b/lib/LibAddonMenu-2.0/controls/header.lua @@ -1,45 +1,42 @@ --[[headerData = { - type = "header", - name = "My Header", -- or string id or function returning a string - width = "full", --or "half" (optional) - reference = "MyAddonHeader" -- unique global reference to control (optional) -} ]] + type = "header", + name = "My Header", -- or string id or function returning a string + width = "full", --or "half" (optional) + reference = "MyAddonHeader" -- unique global reference to control (optional) +} ]] -local widgetVersion = 7 +local widgetVersion = 8 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(LAM.util.GetStringFromValue(control.data.name)) + control.header:SetText(LAM.util.GetStringFromValue(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(LAM.util.GetStringFromValue(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 \ No newline at end of file + 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(LAM.util.GetStringFromValue(headerData.name)) + + control.UpdateValue = UpdateValue + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/lib/LibAddonMenu-2.0/controls/iconpicker.lua b/lib/LibAddonMenu-2.0/controls/iconpicker.lua index de720e9..df93550 100644 --- a/lib/LibAddonMenu-2.0/controls/iconpicker.lua +++ b/lib/LibAddonMenu-2.0/controls/iconpicker.lua @@ -1,441 +1,433 @@ --[[iconpickerData = { - type = "iconpicker", - name = "My Icon Picker", -- or string id or function returning a string - choices = {"texture path 1", "texture path 2", "texture path 3"}, - getFunc = function() return db.var end, - setFunc = function(var) db.var = var doStuff() end, - tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) - choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) - maxColumns = 5, -- number of icons in one row (optional) - visibleRows = 4.5, -- number of visible rows (optional) - iconSize = 28, -- size of the icons (optional) - defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional) - 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.", -- or string id or function returning a string (optional) - default = defaults.var, -- default value or function that returns the default value (optional) - reference = "MyAddonIconPicker" -- unique global reference to control (optional) -} ]] - -local widgetVersion = 5 + type = "iconpicker", + name = "My Icon Picker", -- or string id or function returning a string + choices = {"texture path 1", "texture path 2", "texture path 3"}, + getFunc = function() return db.var end, + setFunc = function(var) db.var = var doStuff() end, + tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) + choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) + maxColumns = 5, -- number of icons in one row (optional) + visibleRows = 4.5, -- number of visible rows (optional) + iconSize = 28, -- size of the icons (optional) + defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional) + 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.", -- or string id or function returning a string (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonIconPicker" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 6 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 + 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 + 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) + 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.GetStringFromValue(icon.tooltip)) - InformationTooltipTopLevel:BringWindowToTop() + InitializeTooltip(InformationTooltip, icon, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(icon.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() end function IconPickerMenu:OnMouseExit(icon) - ClearTooltip(InformationTooltip) + ClearTooltip(InformationTooltip) end function IconPickerMenu:SetMaxColumns(value) - self.maxCols = value ~= nil and value or 5 + 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 + 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 + self.visibleRows = value ~= nil and value or 4.5 end function IconPickerMenu:SetMouseHandlers(onEnter, onExit) - self.customOnMouseEnter = onEnter - self.customOnMouseExit = 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 + 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 + 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 + 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 + 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 + 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 + 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 or {} - 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, LAM.util.GetStringFromValue(choicesTooltips[i])) - addedChoices[texture] = true - end - end + local data = control.data + if not choices then + choices, choicesTooltips = data.choices, data.choicesTooltips or {} + 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) + LAM.util.RequestRefreshIfNeeded(control) + end, LAM.util.GetStringFromValue(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 + 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 + 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 + 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 = LAM.util.GetDefaultValue(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 + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(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 + LAM.util.RequestRefreshIfNeeded(control) + 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 + 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 = LAM.util.GetStringFromValue(iconpickerData.warning)} - end - - if iconpickerData.disabled ~= nil 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 + 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 = LAM.util.GetStringFromValue(iconpickerData.warning)} + end + + control.UpdateChoices = UpdateChoices + control.UpdateValue = UpdateValue + control:UpdateValue() + control.SetColor = SetColor + control:SetColor() + control.SetIconSize = SetIconSize + control:SetIconSize(iconSize) + + if iconpickerData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control end diff --git a/lib/LibAddonMenu-2.0/controls/panel.lua b/lib/LibAddonMenu-2.0/controls/panel.lua index 315365a..124f9fe 100644 --- a/lib/LibAddonMenu-2.0/controls/panel.lua +++ b/lib/LibAddonMenu-2.0/controls/panel.lua @@ -1,15 +1,15 @@ --[[panelData = { - type = "panel", - name = "Window Title", -- or string id or function returning a string - displayName = "My Longer Window Title", -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it) - author = "Seerah", -- or string id or function returning a string (optional) - version = "2.0", -- or string id or function returning a string (optional) - keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional) - slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional) - 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 -} ]] + type = "panel", + name = "Window Title", -- or string id or function returning a string + displayName = "My Longer Window Title", -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it) + author = "Seerah", -- or string id or function returning a string (optional) + version = "2.0", -- or string id or function returning a string (optional) + keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional) + slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional) + 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 = 10 @@ -20,113 +20,109 @@ 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 + 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 and updateControl.UpdateValue then + updateControl:UpdateValue() + end + if updateControl.UpdateDisabled then + updateControl:UpdateDisabled() + end + end end local function ForceDefaults(panel) - local panelControls = panel.controlsToRefresh + 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 + 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 + if panel.data.resetFunc then + panel.data.resetFunc() + end - cm:FireCallbacks("LAM-RefreshPanel", panel) + 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, - }, - }, + 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(LAM.util.GetStringFromValue(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", LAM.util.GetStringFromValue(panelData.version), GetString(SI_ADDON_MANAGER_AUTHOR), LAM.util.GetStringFromValue(panelData.author))) - elseif panelData.author then - info:SetText(string.format("%s: %s", GetString(SI_ADDON_MANAGER_AUTHOR), LAM.util.GetStringFromValue(panelData.author))) - else - info:SetText("Version: " .. LAM.util.GetStringFromValue(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 + 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(LAM.util.GetStringFromValue(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", LAM.util.GetStringFromValue(panelData.version), GetString(SI_ADDON_MANAGER_AUTHOR), LAM.util.GetStringFromValue(panelData.author))) + elseif panelData.author then + info:SetText(string.format("%s: %s", GetString(SI_ADDON_MANAGER_AUTHOR), LAM.util.GetStringFromValue(panelData.author))) + else + info:SetText("Version: " .. LAM.util.GetStringFromValue(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 diff --git a/lib/LibAddonMenu-2.0/controls/separator.dds b/lib/LibAddonMenu-2.0/controls/separator.dds deleted file mode 100644 index 02bb2ab..0000000 Binary files a/lib/LibAddonMenu-2.0/controls/separator.dds and /dev/null differ diff --git a/lib/LibAddonMenu-2.0/controls/slider.lua b/lib/LibAddonMenu-2.0/controls/slider.lua index 801e16e..aef9438 100644 --- a/lib/LibAddonMenu-2.0/controls/slider.lua +++ b/lib/LibAddonMenu-2.0/controls/slider.lua @@ -1,166 +1,206 @@ --[[sliderData = { - type = "slider", - name = "My Slider", -- or string id or function returning a string - getFunc = function() return db.var end, - setFunc = function(value) db.var = value doStuff() end, - min = 0, - max = 20, - step = 1, --(optional) - decimals = 0, --(optional) - tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "Will need to reload the UI.", -- or string id or function returning a string (optional) - default = defaults.var, -- default value or function that returns the default value (optional) - reference = "MyAddonSlider" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 9 + type = "slider", + name = "My Slider", -- or string id or function returning a string + getFunc = function() return db.var end, + setFunc = function(value) db.var = value doStuff() end, + min = 0, + max = 20, + step = 1, --(optional) + clampInput = true, -- boolean, if set to false the input won't clamp to min and max and allow any number instead (optional) + decimals = 0, -- when specified the input value is rounded to the specified number of decimals (optional) + autoSelect = false, -- boolean, automatically select everything in the text input field when it gains focus (optional) + inputLocation = "below", -- or "right", determines where the input field is shown. This should not be used within the addon menu and is for custom sliders (optional) + tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional) + width = "full", --or "half" (optional) + disabled = function() return db.someBooleanSetting end, --or boolean (optional) + warning = "Will need to reload the UI.", -- or string id or function returning a string (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonSlider" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 10 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 RoundDecimalToPlace(d, place) + return tonumber(strformat("%." .. tostring(place) .. "f", d)) +end 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 + 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 = LAM.util.GetDefaultValue(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) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + elseif value then + if control.data.decimals then + value = RoundDecimalToPlace(value, control.data.decimals) + end + if control.data.clampInput ~= false then + value = math.max(math.min(value, control.data.max), control.data.min) + end + 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 + LAM.util.RequestRefreshIfNeeded(control) + 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 function RoundDecimalToPlace(d, place) - return tonumber(string.format("%." .. tostring(place) .. "f", d)) - 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 - local new_value = sliderData.decimals and RoundDecimalToPlace(value, sliderData.decimals) or value - self:SetValue(new_value) --do we actually need this line? - slidervalue:SetText(new_value) - end) - slider:SetHandler("OnSliderReleased", function(self, value) - --sliderData.setFunc(value) - local new_value = sliderData.decimals and RoundDecimalToPlace(value, sliderData.decimals) or value - control:UpdateValue(false, new_value) --does this work here instead? - end) - slider:SetHandler("OnMouseWheel", function(self, value) - local new_value = (tonumber(slidervalue:GetText()) or sliderData.min or 0) + ((sliderData.step or 1) * value) - control:UpdateValue(false, new_value) - 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 = LAM.util.GetStringFromValue(sliderData.warning)} - end - - if sliderData.disabled ~= nil 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 + local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName) + local isInputOnRight = sliderData.inputLocation == "right" + + --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:SetHeight(14) + if(isInputOnRight) then + slider:SetAnchor(TOPRIGHT, nil, nil, -60) + else + slider:SetAnchor(TOPRIGHT) + end + 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") + if(isInputOnRight) then + control.slidervalueBG:SetDimensions(60, 26) + control.slidervalueBG:SetAnchor(LEFT, slider, RIGHT, 5, 0) + else + control.slidervalueBG:SetDimensions(50, 16) + control.slidervalueBG:SetAnchor(TOP, slider, BOTTOM, 0, 0) + end + 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) + if(isInputOnRight) then + slidervalue:SetFont("ZoFontGameLarge") + else + slidervalue:SetFont("ZoFontGameSmall") + end + + local isHandlingChange = false + local function HandleValueChanged(value) + if isHandlingChange then return end + if sliderData.decimals then + value = RoundDecimalToPlace(value, sliderData.decimals) + end + isHandlingChange = true + slider:SetValue(value) + slidervalue:SetText(value) + isHandlingChange = false + end + + slidervalue:SetHandler("OnEscape", function(self) + HandleValueChanged(sliderData.getFunc()) + self:LoseFocus() + end) + slidervalue:SetHandler("OnEnter", function(self) + self:LoseFocus() + end) + slidervalue:SetHandler("OnFocusLost", function(self) + local value = tonumber(self:GetText()) + control:UpdateValue(false, value) + end) + slidervalue:SetHandler("OnTextChanged", function(self) + local value = tonumber(self:GetText()) + if(value) then + HandleValueChanged(value) + end + end) + if(sliderData.autoSelect) then + ZO_PreHookHandler(slidervalue, "OnFocusGained", function(self) + self:SelectAll() + end) + 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 + HandleValueChanged(value) + end) + slider:SetHandler("OnSliderReleased", function(self, value) + control:UpdateValue(false, value) + end) + slider:SetHandler("OnMouseWheel", function(self, value) + local new_value = (tonumber(slidervalue:GetText()) or sliderData.min or 0) + ((sliderData.step or 1) * value) + control:UpdateValue(false, new_value) + 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 = LAM.util.GetStringFromValue(sliderData.warning)} + end + + control.UpdateValue = UpdateValue + control:UpdateValue() + + if sliderData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control end diff --git a/lib/LibAddonMenu-2.0/controls/submenu.lua b/lib/LibAddonMenu-2.0/controls/submenu.lua index 2512753..1766a1f 100644 --- a/lib/LibAddonMenu-2.0/controls/submenu.lua +++ b/lib/LibAddonMenu-2.0/controls/submenu.lua @@ -1,10 +1,10 @@ --[[submenuData = { - type = "submenu", - name = "Submenu Title", -- or string id or function returning a string - tooltip = "My submenu tooltip", -- -- or string id or function returning a string (optional) - controls = {sliderData, buttonData} --(optional) used by LAM - reference = "MyAddonSubmenu" --(optional) unique global reference to control -} ]] + type = "submenu", + name = "Submenu Title", -- or string id or function returning a string + tooltip = "My submenu tooltip", -- -- or string id or function returning a string (optional) + controls = {sliderData, buttonData} --(optional) used by LAM + reference = "MyAddonSubmenu" --(optional) unique global reference to control +} ]] local widgetVersion = 11 local LAM = LibStub("LibAddonMenu-2.0") @@ -12,101 +12,97 @@ 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(LAM.util.GetStringFromValue(control.data.name)) - if control.data.tooltip then - control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip) - end + control.label:SetText(LAM.util.GetStringFromValue(control.data.name)) + if control.data.tooltip then + control.label.data.tooltipText = LAM.util.GetStringFromValue(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 + 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(LAM.util.GetStringFromValue(submenuData.name)) - label:SetMouseEnabled(true) - if submenuData.tooltip then - label.data = {tooltipText = LAM.util.GetStringFromValue(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, 0) - - 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 + 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(LAM.util.GetStringFromValue(submenuData.name)) + label:SetMouseEnabled(true) + if submenuData.tooltip then + label.data = {tooltipText = LAM.util.GetStringFromValue(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, 0) + + 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 + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control end diff --git a/lib/LibAddonMenu-2.0/controls/texture.lua b/lib/LibAddonMenu-2.0/controls/texture.lua index 077862e..a42a29b 100644 --- a/lib/LibAddonMenu-2.0/controls/texture.lua +++ b/lib/LibAddonMenu-2.0/controls/texture.lua @@ -1,12 +1,12 @@ --[[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.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - reference = "MyAddonTexture" --(optional) unique global reference to control -} ]] + 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.", -- or string id or function returning a string (optional) + width = "full", --or "half" (optional) + reference = "MyAddonTexture" --(optional) unique global reference to control +} ]] --add texture coords support? @@ -18,28 +18,28 @@ 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.GetStringFromValue(textureData.tooltip)} - texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseExit) - end - - return control -end \ No newline at end of file + 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.GetStringFromValue(textureData.tooltip)} + texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseExit) + end + + return control +end