diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..60bef33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Thumbs.db +*.zip diff --git a/ChangeLog.md b/ChangeLog.md index 1a78a02..d86a8ee 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,7 +1,12 @@ # Slightly Improved Attribute Bars Changelog +## Version 1.15 (by haggen) +* Updated LibAddonMenu to version 2.0r18 +* Updated API version number for 1.7 +* Fix the default vertical offset for target unit frame having too many decimal places + ## Version 1.14 -* Updated LibAddonMenu to version 2.0 r17 +* Updated LibAddonMenu to version 2.0r17 ## Version 1.13 * Updated API version number for 1.5 diff --git a/Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua index 2e7aa91..ef3def9 100644 --- a/Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua +++ b/Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua @@ -4,14 +4,14 @@ --Register LAM with LibStub -local MAJOR, MINOR = "LibAddonMenu-2.0", 17 +local MAJOR, MINOR = "LibAddonMenu-2.0", 18 local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR) if not lam then return end --the same or newer version of this lib is already loaded into memory local messages = {} local MESSAGE_PREFIX = "[LAM2] " local function PrintLater(msg) - if(CHAT_SYSTEM.primaryContainer) then + if CHAT_SYSTEM.primaryContainer then d(MESSAGE_PREFIX .. msg) else messages[#messages + 1] = msg @@ -25,23 +25,186 @@ local function FlushMessages() messages = {} end -if(LAMSettingsPanelCreated and not LAMCompatibilityWarning) then +if LAMSettingsPanelCreated and not LAMCompatibilityWarning then PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com") LAMCompatibilityWarning = true end --UPVALUES-- local wm = WINDOW_MANAGER +local em = EVENT_MANAGER +local sm = SCENE_MANAGER local cm = CALLBACK_MANAGER +local tconcat = table.concat local tinsert = table.insert -local optionsWindow = ZO_OptionsWindowSettingsScrollChild -local _ local addonsForList = {} local addonToOptionsMap = {} local optionsCreated = {} lam.widgets = lam.widgets or {} local widgets = lam.widgets +lam.util = {} +local util = lam.util + +local function GetTooltipText(tooltip) + if type(tooltip) == "string" then + return tooltip + elseif type(tooltip) == "function" then + return tostring(tooltip()) + end + return nil +end + +local function CreateBaseControl(parent, controlData, controlName) + local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL) + control.panel = parent.panel or parent -- if this is in a submenu, panel is the submenu's parent + control.data = controlData + + control.isHalfWidth = controlData.width == "half" + control:SetWidth(control.panel:GetWidth() - 60) + return control +end + +local MIN_HEIGHT = 26 +local HALF_WIDTH_LINE_SPACING = 2 +local function CreateLabelAndContainerControl(parent, controlData, controlName) + local control = CreateBaseControl(parent, controlData, controlName) + local width = control:GetWidth() + + local container = wm:CreateControl(nil, control, CT_CONTROL) + container:SetDimensions(width / 3, MIN_HEIGHT) + control.container = container + + local label = wm:CreateControl(nil, control, CT_LABEL) + label:SetFont("ZoFontWinH4") + label:SetHeight(MIN_HEIGHT) + label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + label:SetText(controlData.name) + control.label = label + + if control.isHalfWidth then + control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + label:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) + container:SetAnchor(TOPRIGHT, control.label, BOTTOMRIGHT, 0, HALF_WIDTH_LINE_SPACING) + else + control:SetDimensions(width, MIN_HEIGHT) + container:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + label:SetAnchor(TOPRIGHT, container, TOPLEFT, 5, 0) + end + + control.data.tooltipText = GetTooltipText(control.data.tooltip) + control:SetMouseEnabled(true) + control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + return control +end + +util.GetTooltipText = GetTooltipText +util.CreateBaseControl = CreateBaseControl +util.CreateLabelAndContainerControl = CreateLabelAndContainerControl + +local ADDON_DATA_TYPE = 1 +local RESELECTING_DURING_REBUILD = true +local USER_REQUESTED_OPEN = true + + +--INTERNAL FUNCTION +--scrolls ZO_ScrollList `list` to move the row corresponding to `data` +-- into view (does nothing if there is no such row in the list) +--unlike ZO_ScrollList_ScrollDataIntoView, this function accounts for +-- fading near the list's edges - it avoids the fading area by scrolling +-- a little further than the ZO function +local function ScrollDataIntoView(list, data) + local targetIndex = data.sortIndex + if not targetIndex then return end + + local scrollMin, scrollMax = list.scrollbar:GetMinMax() + local scrollTop = list.scrollbar:GetValue() + local controlHeight = list.controlHeight + local targetMin = controlHeight * (targetIndex - 1) - 64 + -- subtracting 64 ain't arbitrary, it's the maximum fading height + -- (libraries/zo_templates/scrolltemplates.lua/UpdateScrollFade) + + if targetMin < scrollTop then + ZO_ScrollList_ScrollAbsolute(list, zo_max(targetMin, scrollMin)) + else + local listHeight = ZO_ScrollList_GetHeight(list) + local targetMax = controlHeight * targetIndex + 64 - listHeight + + if targetMax > scrollTop then + ZO_ScrollList_ScrollAbsolute(list, zo_min(targetMax, scrollMax)) + end + end +end + + +--INTERNAL FUNCTION +--constructs a string pattern from the text in `searchEdit` control +-- * metacharacters are escaped, losing their special meaning +-- * whitespace matches anything (including empty substring) +--if there is nothing but whitespace, returns nil +--otherwise returns a filter function, which takes a `data` table argument +-- and returns true iff `data.filterText` matches the pattern +local function GetSearchFilterFunc(searchEdit) + local text = searchEdit:GetText():lower() + local pattern = text:match("(%S+.-)%s*$") + + if not pattern then -- nothing but whitespace + return nil + end + + -- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de" + pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0") + + -- replace whitespace with "match shortest anything" + pattern = pattern:gsub("%s+", ".-") + + return function(data) + return data.filterText:lower():find(pattern) ~= nil + end +end + + +--INTERNAL FUNCTION +--populates `addonList` with entries from `addonsForList` +-- addonList = ZO_ScrollList control +-- filter = [optional] function(data) +local function PopulateAddonList(addonList, filter) + local entryList = ZO_ScrollList_GetDataList(addonList) + local numEntries = 0 + local selectedData = nil + + ZO_ScrollList_Clear(addonList) + + for i, data in ipairs(addonsForList) do + if not filter or filter(data) then + local dataEntry = ZO_ScrollList_CreateDataEntry(ADDON_DATA_TYPE, data) + numEntries = numEntries + 1 + data.sortIndex = numEntries + entryList[numEntries] = dataEntry + -- select the first panel passing the filter, or the currently + -- shown panel, but only if it passes the filter as well + if selectedData == nil or data.panel == lam.currentAddonPanel then + selectedData = data + end + else + data.sortIndex = nil + end + end + + ZO_ScrollList_Commit(addonList) + + if selectedData then + if selectedData.panel == lam.currentAddonPanel then + ZO_ScrollList_SelectData(addonList, selectedData, nil, RESELECTING_DURING_REBUILD) + else + ZO_ScrollList_SelectData(addonList, selectedData, nil) + end + ScrollDataIntoView(addonList, selectedData) + end +end --METHOD: REGISTER WIDGET-- @@ -66,31 +229,57 @@ 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) - SCENE_MANAGER:Show("gameMenuInGame") - zo_callLater(function() - local settingsMenu = ZO_GameMenu_InGame.gameMenu.headerControls[locSettings] - settingsMenu:SetOpen(true) - SCENE_MANAGER:AddFragment(OPTIONS_WINDOW_FRAGMENT) - KEYBOARD_OPTIONS:ChangePanels(lam.panelID) - for i, child in pairs(settingsMenu.children) do - if type(child) == "table" and child.data.name == KEYBOARD_OPTIONS.panelNames[lam.panelID] then - ZO_TreeEntry_OnMouseUp(child.control, true) - break - 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 - local scroll = LAMAddonPanelsMenuScrollChild - for i = 1, scroll:GetNumChildren() do - local button = scroll:GetChild(i) - if button.panel == panel then - zo_callHandler(button, "OnClicked") - ZO_Scroll_ScrollControlToTop(LAMAddonPanelsMenu, button) - break + 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, 200) + end + + if sm:GetScene("gameMenuInGame"):GetState() == SCENE_SHOWN then + openAddonSettingsMenu() + else + sm:CallWhen("gameMenuInGame", SCENE_SHOWN, openAddonSettingsMenu) + sm:Show("gameMenuInGame") + end end @@ -102,86 +291,112 @@ local function CreateOptionsControls(panel) local optionsTable = addonToOptionsMap[addonID] if optionsTable then - local isHalf, widget - local lastAddedControl, lacAtHalfRow, oIndex, widgetData, widgetType - local submenu, subWidgetData, sIndex, subWidgetType, subWidget - local anchorOffset = 0 - local anchorOffsetSub - local lastAddedControlSub, lacAtHalfRowSub - for oIndex=1,#optionsTable do - widgetData = optionsTable[oIndex] - widgetType = widgetData.type - if widgetType == "submenu" then - submenu = LAMCreateControl[widgetType](panel, widgetData) - if lastAddedControl then - submenu:SetAnchor(TOPLEFT, lastAddedControl, BOTTOMLEFT, 0, 15 + anchorOffset) - else - submenu:SetAnchor(TOPLEFT) + local function CreateAndAnchorWidget(parent, widgetData, offsetX, offsetY, anchorTarget, wasHalf) + local widget + local status, err = pcall(function() widget = LAMCreateControl[widgetData.type](parent, widgetData) end) + if not status then + return err or true, offsetY, anchorTarget, wasHalf + else + local isHalf = (widgetData.width == "half") + if not anchorTarget then -- the first widget in a panel is just placed in the top left corner + widget:SetAnchor(TOPLEFT) + anchorTarget = widget + elseif wasHalf and isHalf then -- when the previous widget was only half width and this one is too, we place it on the right side + widget:SetAnchor(TOPLEFT, anchorTarget, TOPRIGHT, 5 + (offsetX or 0), 0) + widget.lineControl = anchorTarget + offsetY = zo_max(0, widget:GetHeight() - anchorTarget:GetHeight()) -- we need to get the common height of both widgets to know where the next row starts + isHalf = false + else -- otherwise we just put it below the previous one normally + widget:SetAnchor(TOPLEFT, anchorTarget, BOTTOMLEFT, 0, 15 + offsetY) + offsetY = 0 + anchorTarget = widget + end + return false, offsetY, anchorTarget, isHalf + end + end + + local THROTTLE_TIMEOUT, THROTTLE_COUNT = 10, 20 + local fifo = {} + local anchorOffset, lastAddedControl, wasHalf + local CreateWidgetsInPanel, err + + local function PrepareForNextPanel() + anchorOffset, lastAddedControl, wasHalf = 0, nil, false + end + + local function SetupCreationCalls(parent, widgetDataTable) + fifo[#fifo + 1] = PrepareForNextPanel + local count = #widgetDataTable + for i = 1, count, THROTTLE_COUNT do + fifo[#fifo + 1] = function() + CreateWidgetsInPanel(parent, widgetDataTable, i, zo_min(i + THROTTLE_COUNT - 1, count)) end - lastAddedControl = submenu - lacAtHalfRow = false - - anchorOffsetSub = 0 - lacAtHalfRowSub = nil - lastAddedControlSub = nil - for sIndex=1,#widgetData.controls do - subWidgetData = widgetData.controls[sIndex] - subWidgetType = subWidgetData.type - subWidget = LAMCreateControl[subWidgetType](submenu, subWidgetData) - isHalf = subWidgetData.width == "half" - if lastAddedControlSub then - if lacAtHalfRowSub and isHalf then - subWidget:SetAnchor(TOPLEFT, lastAddedControlSub, TOPRIGHT, 5, 0) - lacAtHalfRowSub = false - anchorOffsetSub = zo_max(0, subWidget:GetHeight() - lastAddedControlSub:GetHeight()) - else - subWidget:SetAnchor(TOPLEFT, lastAddedControlSub, BOTTOMLEFT, 0, 15 + anchorOffsetSub) - lacAtHalfRowSub = isHalf - anchorOffsetSub = 0 - lastAddedControlSub = subWidget + 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 - else - subWidget:SetAnchor(TOPLEFT) - lacAtHalfRowSub = isHalf - lastAddedControlSub = subWidget end end - else - widget = LAMCreateControl[widgetType](panel, widgetData) - isHalf = widgetData.width == "half" - if lastAddedControl then - if lacAtHalfRow and isHalf then - widget:SetAnchor(TOPLEFT, lastAddedControl, TOPRIGHT, 10, 0) - anchorOffset = zo_max(0, widget:GetHeight() - lastAddedControl:GetHeight()) - lacAtHalfRow = false - else - widget:SetAnchor(TOPLEFT, lastAddedControl, BOTTOMLEFT, 0, 15 + anchorOffset) - lacAtHalfRow = isHalf - anchorOffset = 0 - lastAddedControl = widget - end + end + end + + local function DoCreateSettings() + if #fifo > 0 then + local nextCall = table.remove(fifo, 1) + nextCall() + if(nextCall == PrepareForNextPanel) then + DoCreateSettings() else - widget:SetAnchor(TOPLEFT) - lacAtHalfRow = isHalf - lastAddedControl = widget + zo_callLater(DoCreateSettings, THROTTLE_TIMEOUT) end + else + optionsCreated[addonID] = true + cm:FireCallbacks("LAM-PanelControlsCreated", panel) end end - end - optionsCreated[addonID] = true - cm:FireCallbacks("LAM-PanelControlsCreated", panel) + if SetupCreationCalls(panel, optionsTable) then + PrintLater(("The settings menu of %s is missing some entries."):format(addonID)) + end + DoCreateSettings() + end end --INTERNAL FUNCTION --handles switching between panels local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel - local currentlySelected = LAMAddonPanelsMenu.currentlySelected + local currentlySelected = lam.currentAddonPanel if currentlySelected and currentlySelected ~= panel then currentlySelected:SetHidden(true) end - LAMAddonPanelsMenu.currentlySelected = panel + 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) @@ -190,8 +405,7 @@ local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel cm:FireCallbacks("LAM-RefreshPanel", panel) end -local Initialize -local hasInitialized = false +local CheckSafetyAndInitialize --METHOD: REGISTER ADDON PANEL --registers your addon with LibAddonMenu and creates a panel @@ -199,21 +413,36 @@ local hasInitialized = false -- 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) - if(not hasInitialized) then Initialize(addonID) end - local panel = lamcc.panel(nil, panelData, addonID) --addonID==global name of panel + CheckSafetyAndInitialize(addonID) + local container = lam:GetAddonPanelContainer() + local panel = lamcc.panel(container, panelData, addonID) --addonID==global name of panel panel:SetHidden(true) - panel:SetAnchor(TOPLEFT, LAMAddonPanelsMenu, TOPRIGHT, 10, 0) - panel:SetAnchor(BOTTOMLEFT, LAMAddonPanelsMenu, BOTTOMRIGHT, 10, 0) - panel:SetWidth(549) - panel:SetDrawLayer(DL_OVERLAY) - tinsert(addonsForList, {panel = addonID, name = panelData.name}) + 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 @@ -233,152 +462,348 @@ end --INTERNAL FUNCTION ---handles switching between LAM's Addon Settings panel and other panels in the Settings menu -local oldDefaultButton = ZO_OptionsWindowResetToDefaultButton -local oldCallback = oldDefaultButton.callback -local dummyFunc = function() end -local panelWindow = ZO_OptionsWindow -local bgL = ZO_OptionsWindowBGLeft -local bgR = ZO_OptionsWindowBGLeftBGRight -local function HandlePanelSwitching(self, panel) - if panel == lam.panelID then --our addon settings panel - oldDefaultButton:SetCallback(dummyFunc) - oldDefaultButton:SetHidden(true) - oldDefaultButton:SetAlpha(0) --just because it still bugs out - panelWindow:SetDimensions(999, 960) - bgL:SetWidth(666) - bgR:SetWidth(333) - else - local shown = LAMAddonPanelsMenu.currentlySelected - if shown then shown:SetHidden(true) end - oldDefaultButton:SetCallback(oldCallback) - oldDefaultButton:SetHidden(false) - oldDefaultButton:SetAlpha(1) - panelWindow:SetDimensions(768, 914) - bgL:SetWidth(512) - bgR:SetWidth(256) +--creates LAM's Addon Settings entry in ZO_GameMenu +local function CreateAddonSettingsMenuEntry() + --Russian for TERAB1T's RuESO addon, which creates an "ru" locale + --game font does not support Cyrillic, so they are using custom fonts + extended latin charset + --Spanish provided by Luisen75 for their translation project + local controlPanelNames = { + en = "Addon Settings", + fr = "Extensions", + de = "Erweiterungen", + ru = "Îacòpoéêè äoïoìîeîèé", + es = "Configura Addons", + } + + local panelData = { + id = KEYBOARD_OPTIONS.currentPanelId, + name = controlPanelNames[GetCVar("Language.2")] or controlPanelNames["en"], + } + + KEYBOARD_OPTIONS.currentPanelId = panelData.id + 1 + KEYBOARD_OPTIONS.panelNames[panelData.id] = panelData.name + + lam.panelId = panelData.id + + local addonListSorted = false + + function panelData.callback() + sm:AddFragment(lam:GetAddonSettingsFragment()) + KEYBOARD_OPTIONS:ChangePanels(lam.panelId) + + local title = LAMAddonSettingsWindow:GetNamedChild("Title") + title:SetText(panelData.name) + + if not addonListSorted and #addonsForList > 0 then + local searchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit") + --we're about to show our list for the first time - let's sort it + table.sort(addonsForList, function(a, b) return a.name < b.name end) + PopulateAddonList(lam.addonList, GetSearchFilterFunc(searchEdit)) + addonListSorted = true + end end + + function panelData.unselectedCallback() + sm:RemoveFragment(lam:GetAddonSettingsFragment()) + if SetCameraOptionsPreviewModeEnabled then -- available since API version 100011 + SetCameraOptionsPreviewModeEnabled(false) + end + end + + ZO_GameMenu_AddSettingPanel(panelData) end --INTERNAL FUNCTION ---creates LAM's Addon Settings panel -local function CreateAddonSettingsPanel() - if not LAMSettingsPanelCreated then - local controlPanelID = "LAM_ADDON_SETTINGS_PANEL" - --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", - } - - ZO_OptionsWindow_AddUserPanel(controlPanelID, controlPanelNames[GetCVar("Language.2")] or controlPanelNames["en"], PANEL_TYPE_SETTINGS) - - lam.panelID = _G[controlPanelID] - - ZO_PreHook(ZO_KeyboardOptions, "ChangePanels", HandlePanelSwitching) - - LAMSettingsPanelCreated = true +--creates the left-hand menu in LAM's window +local function CreateAddonList(name, parent) + local addonList = wm:CreateControlFromVirtual(name, parent, "ZO_ScrollList") + + local function addonListRow_OnMouseDown(control, button) + if button == 1 then + local data = ZO_ScrollList_GetData(control) + ZO_ScrollList_SelectData(addonList, data, control) + end + end + + local function addonListRow_OnMouseEnter(control) + ZO_ScrollList_MouseEnter(addonList, control) + end + + local function addonListRow_OnMouseExit(control) + ZO_ScrollList_MouseExit(addonList, control) + end + + local function addonListRow_Select(previouslySelectedData, selectedData, reselectingDuringRebuild) + if not reselectingDuringRebuild then + if previouslySelectedData then + previouslySelectedData.panel:SetHidden(true) + end + if selectedData then + selectedData.panel:SetHidden(false) + PlaySound(SOUNDS.MENU_SUBCATEGORY_SELECTION) + end + end + end + + local function addonListRow_Setup(control, data) + control:SetText(data.name) + control:SetSelected(not data.panel:IsHidden()) + end + + ZO_ScrollList_AddDataType(addonList, ADDON_DATA_TYPE, "ZO_SelectableLabel", 28, addonListRow_Setup) + -- I don't know how to make highlights clear properly; they often + -- get stuck and after a while the list is full of highlighted rows + --ZO_ScrollList_EnableHighlight(addonList, "ZO_ThinListHighlight") + ZO_ScrollList_EnableSelection(addonList, "ZO_ThinListHighlight", addonListRow_Select) + + local addonDataType = ZO_ScrollList_GetDataTypeTable(addonList, ADDON_DATA_TYPE) + local addonListRow_CreateRaw = addonDataType.pool.m_Factory + + local function addonListRow_Create(pool) + local control = addonListRow_CreateRaw(pool) + control:SetHandler("OnMouseDown", addonListRow_OnMouseDown) + --control:SetHandler("OnMouseEnter", addonListRow_OnMouseEnter) + --control:SetHandler("OnMouseExit", addonListRow_OnMouseExit) + control:SetHeight(28) + control:SetFont("ZoFontHeader") + control:SetHorizontalAlignment(TEXT_ALIGN_LEFT) + control:SetVerticalAlignment(TEXT_ALIGN_CENTER) + control:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + return control end + + addonDataType.pool.m_Factory = addonListRow_Create + + return addonList end --INTERNAL FUNCTION ---adds each registered addon to the menu in LAM's panel -local function CreateAddonButtons(list, addons) - for i = 1, #addons do - local button = wm:CreateControlFromVirtual("LAMAddonMenuButton"..i, list.scrollChild, "ZO_DefaultTextButton") - button.name = addons[i].name - button.panel = _G[addons[i].panel] - button:SetText(button.name) - button:SetHorizontalAlignment(TEXT_ALIGN_LEFT) - button:SetWidth(190) - if i == 1 then - button:SetAnchor(TOPLEFT, list.scrollChild, TOPLEFT, 5, 5) +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 - button:SetAnchor(TOPLEFT, _G["LAMAddonMenuButton"..i-1], BOTTOMLEFT) + srchBg:SetAlpha(srchHover and 0.6 or 0.0) end - button:SetHandler("OnClicked", function(self) self.panel:SetHidden(false) 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 the left-hand menu in LAM's panel -local function CreateAddonList() - local list - --check if an earlier loaded copy of LAM created it already - list = LAMAddonPanelsMenu or wm:CreateControlFromVirtual("LAMAddonPanelsMenu", optionsWindow, "ZO_ScrollContainer") - list:ClearAnchors() - list:SetAnchor(TOPLEFT) - list:SetHeight(675) - list:SetWidth(200) - - list.bg = list.bg or wm:CreateControl(nil, list, CT_BACKDROP) - local bg = list.bg - bg:SetAnchorFill() --offsets of 8? - bg:SetEdgeTexture("EsoUI\\Art\\miscellaneous\\borderedinsettransparent_edgefile.dds", 128, 16) - bg:SetCenterColor(0, 0, 0, 0) - - list.scrollChild = LAMAddonPanelsMenuScrollChild - list.scrollChild:SetResizeToFitPadding(0, 15) - - local generatedButtons - list:SetHandler("OnShow", function(self) - if not generatedButtons and #addonsForList > 0 then - --we're about to show our list for the first time - let's sort the buttons before creating them - table.sort(addonsForList, function(a, b) - return a.name < b.name - end) - CreateAddonButtons(list, addonsForList) - self.currentlySelected = LAMAddonMenuButton1 and LAMAddonMenuButton1.panel - --since our addon panels don't have a parent, let's make sure they hide when we're done with them - ZO_PreHookHandler(ZO_OptionsWindow, "OnHide", function() self.currentlySelected:SetHidden(true) end) - generatedButtons = true - end - if self.currentlySelected then self.currentlySelected:SetHidden(false) end - end) - - --list.controlType = OPTIONS_CUSTOM - --list.panel = lam.panelID - list.data = { - controlType = OPTIONS_CUSTOM, - panel = lam.panelID, - } - - ZO_OptionsWindow_InitializeControl(list) +--creates LAM's Addon Settings top-level window +local function CreateAddonSettingsWindow() + local tlw = wm:CreateTopLevelWindow("LAMAddonSettingsWindow") + tlw:SetHidden(true) + tlw:SetDimensions(1010, 914) -- same height as ZO_OptionsWindow + + ZO_ReanchorControlForLeftSidePanel(tlw) + + -- create black background for the window (mimic ZO_RightFootPrintBackground) + + local bgLeft = wm:CreateControl("$(parent)BackgroundLeft", tlw, CT_TEXTURE) + bgLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_left.dds") + bgLeft:SetDimensions(1024, 1024) + bgLeft:SetAnchor(TOPLEFT, nil, TOPLEFT) + bgLeft:SetDrawLayer(DL_BACKGROUND) + bgLeft:SetExcludeFromResizeToFitExtents(true) + + local bgRight = wm:CreateControl("$(parent)BackgroundRight", tlw, CT_TEXTURE) + bgRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_right.dds") + bgRight:SetDimensions(64, 1024) + bgRight:SetAnchor(TOPLEFT, bgLeft, TOPRIGHT) + bgRight:SetDrawLayer(DL_BACKGROUND) + bgRight:SetExcludeFromResizeToFitExtents(true) + + -- create gray background for addon list (mimic ZO_TreeUnderlay) + + local underlayLeft = wm:CreateControl("$(parent)UnderlayLeft", tlw, CT_TEXTURE) + underlayLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_left.dds") + underlayLeft:SetDimensions(256, 1024) + underlayLeft:SetAnchor(TOPLEFT, bgLeft, TOPLEFT) + underlayLeft:SetDrawLayer(DL_BACKGROUND) + underlayLeft:SetExcludeFromResizeToFitExtents(true) + + local underlayRight = wm:CreateControl("$(parent)UnderlayRight", tlw, CT_TEXTURE) + underlayRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_right.dds") + underlayRight:SetDimensions(128, 1024) + underlayRight:SetAnchor(TOPLEFT, underlayLeft, TOPRIGHT) + underlayRight:SetDrawLayer(DL_BACKGROUND) + underlayRight:SetExcludeFromResizeToFitExtents(true) + + -- create title bar (mimic ZO_OptionsWindow) + + local title = wm:CreateControl("$(parent)Title", tlw, CT_LABEL) + title:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 70) + title:SetFont("ZoFontWinH1") + title:SetModifyTextType(MODIFY_TEXT_TYPE_UPPERCASE) - return list + local divider = wm:CreateControlFromVirtual("$(parent)Divider", tlw, "ZO_Options_Divider") + divider:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 108) + + -- create search filter box + + local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw) + srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120) + srchBox:SetDimensions(260, 30) + + -- create scrollable addon list + + local addonList = CreateAddonList("$(parent)AddonList", tlw) + addonList:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 160) + addonList:SetDimensions(285, 665) + + lam.addonList = addonList -- for easy access from elsewhere + + -- create container for option panels + + local panelContainer = wm:CreateControl("$(parent)PanelContainer", tlw, CT_CONTROL) + panelContainer:SetAnchor(TOPLEFT, nil, TOPLEFT, 365, 120) + panelContainer:SetDimensions(645, 675) + + return tlw end + --INITIALIZING local safeToInitialize = false +local hasInitialized = false local eventHandle = table.concat({MAJOR, MINOR}, "r") local function OnLoad(_, addonName) -- wait for the first loaded event - EVENT_MANAGER:UnregisterForEvent(eventHandle, EVENT_ADD_ON_LOADED) + em:UnregisterForEvent(eventHandle, EVENT_ADD_ON_LOADED) safeToInitialize = true end -EVENT_MANAGER:RegisterForEvent(eventHandle, EVENT_ADD_ON_LOADED, OnLoad) +em:RegisterForEvent(eventHandle, EVENT_ADD_ON_LOADED, OnLoad) local function OnActivated(_, addonName) - EVENT_MANAGER:UnregisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED) + em:UnregisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED) FlushMessages() end -EVENT_MANAGER:RegisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED, OnActivated) +em:RegisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED, OnActivated) -function Initialize(addonID) - if(not safeToInitialize) then +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 - CreateAddonSettingsPanel() - CreateAddonList() - hasInitialized = true + if not hasInitialized then + hasInitialized = true + end +end + + +--TODO documentation +function lam:GetAddonPanelContainer() + local fragment = lam:GetAddonSettingsFragment() + local window = fragment:GetControl() + return window:GetNamedChild("PanelContainer") +end + + +--TODO documentation +function lam:GetAddonSettingsFragment() + assert(hasInitialized or safeToInitialize) + if not LAMAddonSettingsFragment then + local window = CreateAddonSettingsWindow() + LAMAddonSettingsFragment = ZO_FadeSceneFragment:New(window, true, 100) + CreateAddonSettingsMenuEntry() + end + return LAMAddonSettingsFragment end + + +-- vi: noexpandtab diff --git a/Libs/LibAddonMenu-2.0/controls/button.lua b/Libs/LibAddonMenu-2.0/controls/button.lua index 49d0059..7dad09e 100644 --- a/Libs/LibAddonMenu-2.0/controls/button.lua +++ b/Libs/LibAddonMenu-2.0/controls/button.lua @@ -11,7 +11,7 @@ } ]] -local widgetVersion = 6 +local widgetVersion = 7 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("button", widgetVersion) then return end @@ -26,19 +26,25 @@ local function UpdateDisabled(control) else disable = control.data.disabled end - + control.button:SetEnabled(not disable) end --controlName is optional +local MIN_HEIGHT = 28 -- default_button height +local HALF_WIDTH_LINE_SPACING = 2 function LAMCreateControl.button(parent, buttonData, controlName) - local control = wm:CreateControl(controlName or buttonData.reference, parent.scroll or parent, CT_CONTROL) - - local isHalfWidth = buttonData.width == "half" - control:SetDimensions(isHalfWidth and 250 or 510, isHalfWidth and 55 or 28) + local control = LAM.util.CreateBaseControl(parent, buttonData, controlName) control:SetMouseEnabled(true) + local width = control:GetWidth() + if control.isHalfWidth then + control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) + else + control:SetDimensions(width, MIN_HEIGHT) + end + if buttonData.icon then control.button = wm:CreateControl(nil, control, CT_BUTTON) control.button:SetDimensions(26, 26) @@ -47,33 +53,28 @@ function LAMCreateControl.button(parent, buttonData, controlName) else --control.button = wm:CreateControlFromVirtual(controlName.."Button", control, "ZO_DefaultButton") control.button = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultButton") - control.button:SetWidth(isHalfWidth and 180 or 200) + control.button:SetWidth(width / 3) control.button:SetText(buttonData.name) end local button = control.button - button:SetAnchor(isHalfWidth and CENTER or RIGHT) + button:SetAnchor(control.isHalfWidth and CENTER or RIGHT) button:SetClickSound("Click") - --button.tooltipText = buttonData.tooltip - button.data = {tooltipText = buttonData.tooltip} + button.data = {tooltipText = LAM.util.GetTooltipText(buttonData.tooltip)} button:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) button:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) button:SetHandler("OnClicked", function(self, ...) - buttonData.func(self, ...) - if control.panel.data.registerForRefresh then - cm:FireCallbacks("LAM-RefreshPanel", control) - end - end) + buttonData.func(self, ...) + if control.panel.data.registerForRefresh then + cm:FireCallbacks("LAM-RefreshPanel", control) + end + end) if buttonData.warning then control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") control.warning:SetAnchor(RIGHT, button, LEFT, -5, 0) - --control.warning.tooltipText = buttonData.warning control.warning.data = {tooltipText = buttonData.warning} end - control.panel = parent.panel or parent --if this is in a submenu, panel is its parent - control.data = buttonData - if buttonData.disabled then control.UpdateDisabled = UpdateDisabled control:UpdateDisabled() diff --git a/Libs/LibAddonMenu-2.0/controls/checkbox.lua b/Libs/LibAddonMenu-2.0/controls/checkbox.lua index a5142a9..8401dda 100644 --- a/Libs/LibAddonMenu-2.0/controls/checkbox.lua +++ b/Libs/LibAddonMenu-2.0/controls/checkbox.lua @@ -12,7 +12,7 @@ } ]] -local widgetVersion = 8 +local widgetVersion = 9 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("checkbox", widgetVersion) then return end @@ -101,60 +101,33 @@ local function OnMouseExit(control) control.checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) end - --controlName is optional function LAMCreateControl.checkbox(parent, checkboxData, controlName) - local control = wm:CreateControl(controlName or checkboxData.reference, parent.scroll or parent, CT_CONTROL) - control:SetMouseEnabled(true) - --control.tooltipText = checkboxData.tooltip + 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.label = wm:CreateControl(nil, control, CT_LABEL) - local label = control.label - label:SetFont("ZoFontWinH4") - label:SetText(checkboxData.name) - label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) - label:SetHeight(26) + 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, CT_LABEL) + 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() - local isHalfWidth = checkboxData.width == "half" - if isHalfWidth then - control:SetDimensions(250, 55) - checkbox:SetDimensions(100, 26) - checkbox:SetAnchor(BOTTOMRIGHT) - label:SetAnchor(TOPLEFT) - label:SetAnchor(TOPRIGHT) - else - control:SetDimensions(510, 30) - checkbox:SetDimensions(200, 26) - checkbox:SetAnchor(RIGHT) - label:SetAnchor(LEFT) - label:SetAnchor(RIGHT, checkbox, LEFT, -5, 0) - end - if checkboxData.warning then control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") control.warning:SetAnchor(RIGHT, checkbox, LEFT, -5, 0) - --control.warning.tooltipText = checkboxData.warning control.warning.data = {tooltipText = checkboxData.warning} end - control.panel = parent.panel or parent --if this is in a submenu, panel is its parent - control.data = checkboxData - control.data.tooltipText = checkboxData.tooltip + control.data.tooltipText = LAM.util.GetTooltipText(checkboxData.tooltip) if checkboxData.disabled then control.UpdateDisabled = UpdateDisabled diff --git a/Libs/LibAddonMenu-2.0/controls/colorpicker.lua b/Libs/LibAddonMenu-2.0/controls/colorpicker.lua index e820539..011b4b5 100644 --- a/Libs/LibAddonMenu-2.0/controls/colorpicker.lua +++ b/Libs/LibAddonMenu-2.0/controls/colorpicker.lua @@ -12,7 +12,7 @@ } ]] -local widgetVersion = 6 +local widgetVersion = 7 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end @@ -38,7 +38,7 @@ local function UpdateDisabled(control) control.isDisabled = disable end -local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA) +local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA) if forceDefault then --if we are forcing defaults local color = control.data.default valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a @@ -53,39 +53,14 @@ local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA valueR, valueG, valueB, valueA = control.data.getFunc() end - control.thumb:SetColor(valueR, valueG, valueB, valueA or 1) + control.thumb:SetColor(valueR, valueG, valueB, valueA or 1) end - function LAMCreateControl.colorpicker(parent, colorpickerData, controlName) - local control = wm:CreateControl(controlName or colorpickerData.reference, parent.scroll or parent, CT_CONTROL) - control:SetMouseEnabled(true) - control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - - control.label = wm:CreateControl(nil, control, CT_LABEL) - local label = control.label - label:SetDimensions(300, 26) - label:SetAnchor(TOPLEFT) - label:SetFont("ZoFontWinH4") - label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) - label:SetText(colorpickerData.name) - - control.color = wm:CreateControl(nil, control, CT_CONTROL) - local color = control.color + local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName) - local isHalfWidth = colorpickerData.width == "half" - if isHalfWidth then - control:SetDimensions(250, 55) - label:SetDimensions(250, 26) - color:SetDimensions(100, 24) - color:SetAnchor(TOPRIGHT, label, BOTTOMRIGHT) - else - control:SetDimensions(510, 30) - label:SetDimensions(300, 26) - color:SetDimensions(200, 24) - color:SetAnchor(TOPRIGHT) - end + control.color = control.container + local color = control.color control.thumb = wm:CreateControl(nil, color, CT_TEXTURE) local thumb = control.thumb @@ -100,28 +75,25 @@ function LAMCreateControl.colorpicker(parent, colorpickerData, controlName) border:SetAnchor(CENTER, thumb, CENTER, 0, 0) local function ColorPickerCallback(r, g, b, a) - control:UpdateValue(false, r, g, b, a) - end + control:UpdateValue(false, r, g, b, a) + end control:SetHandler("OnMouseUp", function(self, btn, upInside) - if self.isDisabled then return end + if self.isDisabled then return end - if upInside then - local r, g, b, a = colorpickerData.getFunc() - COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, colorpickerData.name) - end - end) + if upInside then + local r, g, b, a = colorpickerData.getFunc() + COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, colorpickerData.name) + end + end) if colorpickerData.warning then control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") control.warning:SetAnchor(RIGHT, control.color, LEFT, -5, 0) - --control.warning.tooltipText = colorpickerData.warning control.warning.data = {tooltipText = colorpickerData.warning} end - control.panel = parent.panel or parent --if this is in a submenu, panel is its parent - control.data = colorpickerData - control.data.tooltipText = colorpickerData.tooltip + control.data.tooltipText = LAM.util.GetTooltipText(colorpickerData.tooltip) if colorpickerData.disabled then control.UpdateDisabled = UpdateDisabled diff --git a/Libs/LibAddonMenu-2.0/controls/custom.lua b/Libs/LibAddonMenu-2.0/controls/custom.lua index bb1c2d1..e7b7312 100644 --- a/Libs/LibAddonMenu-2.0/controls/custom.lua +++ b/Libs/LibAddonMenu-2.0/controls/custom.lua @@ -5,7 +5,7 @@ width = "full", --or "half" (optional) } ]] -local widgetVersion = 5 +local widgetVersion = 6 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("custom", widgetVersion) then return end @@ -18,21 +18,17 @@ local function UpdateValue(control) end end +local MIN_HEIGHT = 26 function LAMCreateControl.custom(parent, customData, controlName) - local control = wm:CreateControl(controlName or customData.reference, parent.scroll or parent, CT_CONTROL) + local control = LAM.util.CreateBaseControl(parent, customData, controlName) + local width = control:GetWidth() control:SetResizeToFitDescendents(true) - local isHalfWidth = customData.width == "half" - if isHalfWidth then --note these restrictions - control:SetDimensionConstraints(250, 55, 250, 100) - control:SetDimensions(250, 55) + if control.isHalfWidth then --note these restrictions + control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) else - control:SetDimensionConstraints(510, 30, 510, 100) - control:SetDimensions(510, 30) + control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) end - - control.panel = parent.panel or parent --if this is in a submenu, panel is its parent - control.data = customData control.UpdateValue = UpdateValue diff --git a/Libs/LibAddonMenu-2.0/controls/description.lua b/Libs/LibAddonMenu-2.0/controls/description.lua index 795ac10..1929d5a 100644 --- a/Libs/LibAddonMenu-2.0/controls/description.lua +++ b/Libs/LibAddonMenu-2.0/controls/description.lua @@ -7,7 +7,7 @@ } ]] -local widgetVersion = 5 +local widgetVersion = 6 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("description", widgetVersion) then return end @@ -21,16 +21,17 @@ local function UpdateValue(control) control.desc:SetText(control.data.text) end +local MIN_HEIGHT = 26 function LAMCreateControl.description(parent, descriptionData, controlName) - local control = wm:CreateControl(controlName or descriptionData.reference, parent.scroll or parent, CT_CONTROL) + local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() control:SetResizeToFitDescendents(true) - local isHalfWidth = descriptionData.width == "half" + if isHalfWidth then - control:SetDimensionConstraints(250, 55, 250, 100) - control:SetDimensions(250, 55) + control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) else - control:SetDimensionConstraints(510, 40, 510, 100) - control:SetDimensions(510, 30) + control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) end control.desc = wm:CreateControl(nil, control, CT_LABEL) @@ -38,12 +39,12 @@ function LAMCreateControl.description(parent, descriptionData, controlName) desc:SetVerticalAlignment(TEXT_ALIGN_TOP) desc:SetFont("ZoFontGame") desc:SetText(descriptionData.text) - desc:SetWidth(isHalfWidth and 250 or 510) + 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 250 or 510) + title:SetWidth(isHalfWidth and width / 2 or width) title:SetAnchor(TOPLEFT, control, TOPLEFT) title:SetFont("ZoFontWinH4") title:SetText(descriptionData.title) @@ -52,9 +53,6 @@ function LAMCreateControl.description(parent, descriptionData, controlName) desc:SetAnchor(TOPLEFT) end - control.panel = parent.panel or parent --if this is in a submenu, panel is its parent - control.data = descriptionData - 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 diff --git a/Libs/LibAddonMenu-2.0/controls/dropdown.lua b/Libs/LibAddonMenu-2.0/controls/dropdown.lua index 346f23d..0731e94 100644 --- a/Libs/LibAddonMenu-2.0/controls/dropdown.lua +++ b/Libs/LibAddonMenu-2.0/controls/dropdown.lua @@ -14,7 +14,7 @@ } ]] -local widgetVersion = 8 +local widgetVersion = 9 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("dropdown", widgetVersion) then return end @@ -82,19 +82,8 @@ local function GrabSortingInfo(sortInfo) return t end - function LAMCreateControl.dropdown(parent, dropdownData, controlName) - local control = wm:CreateControl(controlName or dropdownData.reference, parent.scroll or parent, CT_CONTROL) - control:SetMouseEnabled(true) - control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - - control.label = wm:CreateControl(nil, control, CT_LABEL) - local label = control.label - label:SetAnchor(TOPLEFT) - label:SetFont("ZoFontWinH4") - label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) - label:SetText(dropdownData.name) + local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName) local countControl = parent local name = parent:GetName() @@ -104,9 +93,11 @@ function LAMCreateControl.dropdown(parent, dropdownData, controlName) end local comboboxCount = (countControl.comboboxCount or 0) + 1 countControl.comboboxCount = comboboxCount - control.combobox = wm:CreateControlFromVirtual(zo_strjoin(nil, name, "Combobox", comboboxCount), control, "ZO_ComboBox") + 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) @@ -117,29 +108,12 @@ function LAMCreateControl.dropdown(parent, dropdownData, controlName) 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 - local isHalfWidth = dropdownData.width == "half" - if isHalfWidth then - control:SetDimensions(250, 55) - label:SetDimensions(250, 26) - combobox:SetDimensions(225, 26) - combobox:SetAnchor(TOPRIGHT, label, BOTTOMRIGHT) - else - control:SetDimensions(510, 30) - label:SetDimensions(300, 26) - combobox:SetDimensions(200, 26) - combobox:SetAnchor(TOPRIGHT) - end - if dropdownData.warning then control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0) control.warning.data = {tooltipText = dropdownData.warning} end - control.panel = parent.panel or parent --if this is in a submenu, panel is its parent - control.data = dropdownData - control.data.tooltipText = dropdownData.tooltip - if dropdownData.disabled then control.UpdateDisabled = UpdateDisabled control:UpdateDisabled() diff --git a/Libs/LibAddonMenu-2.0/controls/editbox.lua b/Libs/LibAddonMenu-2.0/controls/editbox.lua index b473f23..78e7683 100644 --- a/Libs/LibAddonMenu-2.0/controls/editbox.lua +++ b/Libs/LibAddonMenu-2.0/controls/editbox.lua @@ -13,7 +13,7 @@ } ]] -local widgetVersion = 7 +local widgetVersion = 8 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("editbox", widgetVersion) then return end @@ -29,7 +29,7 @@ local function UpdateDisabled(control) 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()) @@ -41,7 +41,7 @@ local function UpdateDisabled(control) control.editbox:SetMouseEnabled(not disable) end -local function UpdateValue(control, forceDefault, value) +local function UpdateValue(control, forceDefault, value) if forceDefault then --if we are forcing defaults value = control.data.default control.data.setFunc(value) @@ -58,45 +58,37 @@ local function UpdateValue(control, forceDefault, value) end end - +local MIN_HEIGHT = 26 +local HALF_WIDTH_LINE_SPACING = 2 function LAMCreateControl.editbox(parent, editboxData, controlName) - local control = wm:CreateControl(controlName or editboxData.reference, parent.scroll or parent, CT_CONTROL) - control:SetMouseEnabled(true) - control:SetResizeToFitDescendents(true) - control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - - control.label = wm:CreateControl(nil, control, CT_LABEL) - local label = control.label - label:SetAnchor(TOPLEFT) - label:SetFont("ZoFontWinH4") - label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) - label:SetText(editboxData.name) - - control.bg = wm:CreateControlFromVirtual(nil, control, "ZO_EditBackdrop") + 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 + 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 - 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 @@ -108,36 +100,27 @@ function LAMCreateControl.editbox(parent, editboxData, controlName) editbox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) editbox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) - local isHalfWidth = editboxData.width == "half" - if isHalfWidth then - control:SetDimensions(250, 55) - label:SetDimensions(250, 26) - bg:SetDimensions(225, editboxData.isMultiline and 74 or 24) - bg:SetAnchor(TOPRIGHT, label, BOTTOMRIGHT) - if editboxData.isMultiline then - editbox:SetDimensionConstraints(210, 74, 210, 500) - end + if not editboxData.isMultiline then + container:SetHeight(24) else - control:SetDimensions(510, 30) - label:SetDimensions(300, 26) - bg:SetDimensions(200, editboxData.isMultiline and 100 or 24) - bg:SetAnchor(TOPRIGHT) - if editboxData.isMultiline then - editbox:SetDimensionConstraints(185, 100, 185, 500) + local width = container:GetWidth() + local height = control.isHalfWidth and 74 or 100 + container:SetHeight(height) + editbox:SetDimensionConstraints(width, height, width, 500) + + if control.lineControl then + control.lineControl:SetHeight(MIN_HEIGHT + height + HALF_WIDTH_LINE_SPACING) + else + control:SetHeight(height) end end if editboxData.warning then control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0) - --control.warning.tooltipText = editboxData.warning control.warning.data = {tooltipText = editboxData.warning} end - control.panel = parent.panel or parent --if this is in a submenu, panel is its parent - control.data = editboxData - control.data.tooltipText = editboxData.tooltip - if editboxData.disabled then control.UpdateDisabled = UpdateDisabled control:UpdateDisabled() diff --git a/Libs/LibAddonMenu-2.0/controls/header.lua b/Libs/LibAddonMenu-2.0/controls/header.lua index 14851ee..266ac55 100644 --- a/Libs/LibAddonMenu-2.0/controls/header.lua +++ b/Libs/LibAddonMenu-2.0/controls/header.lua @@ -6,7 +6,7 @@ } ]] -local widgetVersion = 5 +local widgetVersion = 6 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("header", widgetVersion) then return end @@ -17,14 +17,16 @@ local function UpdateValue(control) control.header:SetText(control.data.name) end +local MIN_HEIGHT = 30 function LAMCreateControl.header(parent, headerData, controlName) - local control = wm:CreateControl(controlName or headerData.reference, parent.scroll or parent, CT_CONTROL) - local isHalfWidth = headerData.width == "half" - control:SetDimensions(isHalfWidth and 250 or 510, 30) + 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 250 or 510) + divider:SetWidth(isHalfWidth and width / 2 or width) divider:SetAnchor(TOPLEFT) control.header = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") @@ -33,9 +35,6 @@ function LAMCreateControl.header(parent, headerData, controlName) header:SetAnchor(BOTTOMRIGHT) header:SetText(headerData.name) - control.panel = parent.panel or parent --if this is in a submenu, panel is its parent - control.data = headerData - 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 diff --git a/Libs/LibAddonMenu-2.0/controls/iconpicker.lua b/Libs/LibAddonMenu-2.0/controls/iconpicker.lua new file mode 100644 index 0000000..b8737c2 --- /dev/null +++ b/Libs/LibAddonMenu-2.0/controls/iconpicker.lua @@ -0,0 +1,441 @@ +--[[iconpickerData = { + type = "iconpicker", + name = "My Icon Picker", + tooltip = "Color Picker's tooltip text.", + choices = {"texture path 1", "texture path 2", "texture path 3"}, + choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, --(optional) + getFunc = function() return db.var end, + setFunc = function(var) db.var = var doStuff() end, + maxColumns = 5, --(optional) number of icons in one row + visibleRows = 4.5, --(optional) number of visible rows + iconSize = 28, --(optional) size of the icons + defaultColor = ZO_ColorDef:New("FFFFFF"), --(optional) default color of the icons + width = "full", --or "half" (optional) + beforeShow = function(control, iconPicker) return preventShow end, --(optional) + disabled = function() return db.someBooleanSetting end, --or boolean (optional) + warning = "Will need to reload the UI.", --(optional) + default = defaults.var, --(optional) + reference = "MyAddonIconPicker" --(optional) unique global reference to control +} ]] + +local widgetVersion = 2 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("iconpicker", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local cm = CALLBACK_MANAGER +local tinsert = table.insert + +local IconPickerMenu = ZO_Object:Subclass() +local iconPicker +LAM.util.GetIconPickerMenu = function() + if not iconPicker then + iconPicker = IconPickerMenu:New("LAMIconPicker") + local sceneFragment = LAM:GetAddonSettingsFragment() + ZO_PreHook(sceneFragment, "OnHidden", function() + if not iconPicker.control:IsHidden() then + iconPicker:Clear() + end + end) + end + return iconPicker +end + +function IconPickerMenu:New(...) + local object = ZO_Object.New(self) + object:Initialize(...) + return object +end + +function IconPickerMenu:Initialize(name) + local control = wm:CreateTopLevelWindow(name) + control:SetDrawTier(DT_HIGH) + control:SetHidden(true) + self.control = control + + local scrollContainer = wm:CreateControlFromVirtual(name .. "ScrollContainer", control, "ZO_ScrollContainer") + -- control:SetDimensions(control.container:GetWidth(), height) -- adjust to icon size / col count + scrollContainer:SetAnchorFill() + ZO_Scroll_SetUseFadeGradient(scrollContainer, false) + ZO_Scroll_SetHideScrollbarOnDisable(scrollContainer, false) + ZO_VerticalScrollbarBase_OnMouseExit(scrollContainer:GetNamedChild("ScrollBar")) -- scrollbar initialization seems to be broken so we force it to update the correct alpha value + local scroll = GetControl(scrollContainer, "ScrollChild") + self.scroll = scroll + self.scrollContainer = scrollContainer + + local bg = wm:CreateControl(nil, scrollContainer, CT_BACKDROP) + bg:SetAnchor(TOPLEFT, scrollContainer, TOPLEFT, 0, -3) + bg:SetAnchor(BOTTOMRIGHT, scrollContainer, BOTTOMRIGHT, 2, 5) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + + local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) + mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") + mungeOverlay:SetDrawLevel(1) + mungeOverlay:SetAddressMode(TEX_MODE_WRAP) + mungeOverlay:SetAnchorFill() + + local mouseOver = wm:CreateControl(nil, scrollContainer, CT_TEXTURE) + mouseOver:SetDrawLevel(2) + mouseOver:SetTexture("EsoUI/Art/Buttons/minmax_mouseover.dds") + mouseOver:SetHidden(true) + + local function IconFactory(pool) + local icon = wm:CreateControl(name .. "Entry" .. pool:GetNextControlId(), scroll, CT_TEXTURE) + icon:SetMouseEnabled(true) + icon:SetDrawLevel(3) + icon:SetHandler("OnMouseEnter", function() + mouseOver:SetAnchor(TOPLEFT, icon, TOPLEFT, 0, 0) + mouseOver:SetAnchor(BOTTOMRIGHT, icon, BOTTOMRIGHT, 0, 0) + mouseOver:SetHidden(false) + if self.customOnMouseEnter then + self.customOnMouseEnter(icon) + else + self:OnMouseEnter(icon) + end + end) + icon:SetHandler("OnMouseExit", function() + mouseOver:ClearAnchors() + mouseOver:SetHidden(true) + if self.customOnMouseExit then + self.customOnMouseExit(icon) + else + self:OnMouseExit(icon) + end + end) + icon:SetHandler("OnMouseUp", function(control, ...) + PlaySound("Click") + icon.OnSelect(icon, icon.texture) + self:Clear() + end) + return icon + end + + local function ResetFunction(icon) + icon:ClearAnchors() + end + + self.iconPool = ZO_ObjectPool:New(IconFactory, ResetFunction) + self:SetMaxColumns(1) + self.icons = {} + self.color = ZO_DEFAULT_ENABLED_COLOR + + EVENT_MANAGER:RegisterForEvent(name .. "_OnGlobalMouseUp", EVENT_GLOBAL_MOUSE_UP, function() + if self.refCount ~= nil then + local moc = wm:GetMouseOverControl() + if(moc:GetOwningWindow() ~= control) then + self.refCount = self.refCount - 1 + if self.refCount <= 0 then + self:Clear() + end + end + end + end) +end + +function IconPickerMenu:OnMouseEnter(icon) + InitializeTooltip(InformationTooltip, icon, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetTooltipText(icon.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() +end + +function IconPickerMenu:OnMouseExit(icon) + ClearTooltip(InformationTooltip) +end + +function IconPickerMenu:SetMaxColumns(value) + self.maxCols = value ~= nil and value or 5 +end + +local DEFAULT_SIZE = 28 +function IconPickerMenu:SetIconSize(value) + local iconSize = DEFAULT_SIZE + if value ~= nil then iconSize = math.max(iconSize, value) end + self.iconSize = iconSize +end + +function IconPickerMenu:SetVisibleRows(value) + self.visibleRows = value ~= nil and value or 4.5 +end + +function IconPickerMenu:SetMouseHandlers(onEnter, onExit) + self.customOnMouseEnter = onEnter + self.customOnMouseExit = onExit +end + +function IconPickerMenu:UpdateDimensions() + local iconSize = self.iconSize + local width = iconSize * self.maxCols + 20 + local height = iconSize * self.visibleRows + self.control:SetDimensions(width, height) + + local icons = self.icons + for i = 1, #icons do + local icon = icons[i] + icon:SetDimensions(iconSize, iconSize) + end +end + +function IconPickerMenu:UpdateAnchors() + local iconSize = self.iconSize + local col, maxCols = 1, self.maxCols + local previousCol, previousRow + local scroll = self.scroll + local icons = self.icons + + for i = 1, #icons do + local icon = icons[i] + icon:ClearAnchors() + if i == 1 then + icon:SetAnchor(TOPLEFT, scroll, TOPLEFT, 0, 0) + previousRow = icon + elseif col == 1 then + icon:SetAnchor(TOPLEFT, previousRow, BOTTOMLEFT, 0, 0) + previousRow = icon + else + icon:SetAnchor(TOPLEFT, previousCol, TOPRIGHT, 0, 0) + end + previousCol = icon + col = col >= maxCols and 1 or col + 1 + end +end + +function IconPickerMenu:Clear() + self.icons = {} + self.iconPool:ReleaseAllObjects() + self.control:SetHidden(true) + self.color = ZO_DEFAULT_ENABLED_COLOR + self.refCount = nil + self.parent = nil + self.customOnMouseEnter = nil + self.customOnMouseExit = nil +end + +function IconPickerMenu:AddIcon(texturePath, callback, tooltip) + local icon, key = self.iconPool:AcquireObject() + icon:SetTexture(texturePath) + icon:SetColor(self.color:UnpackRGBA()) + icon.texture = texturePath + icon.tooltip = tooltip + icon.OnSelect = callback + self.icons[#self.icons + 1] = icon +end + +function IconPickerMenu:Show(parent) + if #self.icons == 0 then return false end + if not self.control:IsHidden() then self:Clear() return false end + self:UpdateDimensions() + self:UpdateAnchors() + + local control = self.control + control:ClearAnchors() + control:SetAnchor(TOPLEFT, parent, BOTTOMLEFT, 0, 8) + control:SetHidden(false) + control:BringWindowToTop() + self.parent = parent + self.refCount = 2 + + return true +end + +function IconPickerMenu:SetColor(color) + local icons = self.icons + self.color = color + for i = 1, #icons do + local icon = icons[i] + icon:SetColor(color:UnpackRGBA()) + end +end + +------------------------------------------------------------- + +local function UpdateChoices(control, choices, choicesTooltips) + local data = control.data + if not choices then + choices, choicesTooltips = data.choices, data.choicesTooltips + end + local addedChoices = {} + + local iconPicker = LAM.util.GetIconPickerMenu() + iconPicker:Clear() + for i = 1, #choices do + local texture = choices[i] + if not addedChoices[texture] then -- remove duplicates + iconPicker:AddIcon(choices[i], function(self, texture) + control.icon:SetTexture(texture) + data.setFunc(texture) + if control.panel.data.registerForRefresh then + cm:FireCallbacks("LAM-RefreshPanel", control) + end + end, choicesTooltips[i]) + addedChoices[texture] = true + end + end +end + +local function IsDisabled(control) + if type(control.data.disabled) == "function" then + return control.data.disabled() + else + return control.data.disabled + end +end + +local function SetColor(control, color) + local icon = control.icon + if IsDisabled(control) then + icon:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + icon.color = color or control.data.defaultColor or ZO_DEFAULT_ENABLED_COLOR + icon:SetColor(icon.color:UnpackRGBA()) + end + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:SetColor(icon.color) + end +end + +local function UpdateDisabled(control) + local disable = IsDisabled(control) + + control.dropdown:SetMouseEnabled(not disable) + control.dropdownButton:SetEnabled(not disable) + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:Clear() + end + + SetColor(control) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = control.data.default + control.data.setFunc(value) + control.icon:SetTexture(value) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + if control.panel.data.registerForRefresh then + cm:FireCallbacks("LAM-RefreshPanel", control) + end + else + value = control.data.getFunc() + control.icon:SetTexture(value) + end +end + +local MIN_HEIGHT = 26 +local HALF_WIDTH_LINE_SPACING = 2 +local function SetIconSize(control, size) + local icon = control.icon + icon.size = size + icon:SetDimensions(size, size) + + local height = size + 4 + control.dropdown:SetDimensions(size + 20, height) + height = math.max(height, MIN_HEIGHT) + control.container:SetHeight(height) + if control.lineControl then + control.lineControl:SetHeight(MIN_HEIGHT + size + HALF_WIDTH_LINE_SPACING) + else + control:SetHeight(height) + end + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:SetIconSize(size) + iconPicker:UpdateDimensions() + iconPicker:UpdateAnchors() + end +end + +function LAMCreateControl.iconpicker(parent, iconpickerData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, iconpickerData, controlName) + + local function ShowIconPicker() + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container then + iconPicker:Clear() + else + iconPicker:SetMaxColumns(iconpickerData.maxColumns) + iconPicker:SetVisibleRows(iconpickerData.visibleRows) + iconPicker:SetIconSize(control.icon.size) + UpdateChoices(control) + iconPicker:SetColor(control.icon.color) + if iconpickerData.beforeShow then + if iconpickerData.beforeShow(control, iconPicker) then + iconPicker:Clear() + return + end + end + iconPicker:Show(control.container) + end + end + + local iconSize = iconpickerData.iconSize ~= nil and iconpickerData.iconSize or DEFAULT_SIZE + control.dropdown = wm:CreateControl(nil, control.container, CT_CONTROL) + local dropdown = control.dropdown + dropdown:SetAnchor(LEFT, control.container, LEFT, 0, 0) + dropdown:SetMouseEnabled(true) + dropdown:SetHandler("OnMouseUp", ShowIconPicker) + dropdown:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + dropdown:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + control.icon = wm:CreateControl(nil, dropdown, CT_TEXTURE) + local icon = control.icon + icon:SetAnchor(LEFT, dropdown, LEFT, 3, 0) + icon:SetDrawLevel(2) + + local dropdownButton = wm:CreateControlFromVirtual(nil, dropdown, "ZO_DropdownButton") + dropdownButton:SetDimensions(16, 16) + dropdownButton:SetHandler("OnClicked", ShowIconPicker) + dropdownButton:SetAnchor(RIGHT, dropdown, RIGHT, -3, 0) + control.dropdownButton = dropdownButton + + control.bg = wm:CreateControl(nil, dropdown, CT_BACKDROP) + local bg = control.bg + bg:SetAnchor(TOPLEFT, dropdown, TOPLEFT, 0, -3) + bg:SetAnchor(BOTTOMRIGHT, dropdown, BOTTOMRIGHT, 2, 5) + bg:SetEdgeTexture("EsoUI/Art/Tooltips/UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI/Art/Tooltips/UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) + mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") + mungeOverlay:SetDrawLevel(1) + mungeOverlay:SetAddressMode(TEX_MODE_WRAP) + mungeOverlay:SetAnchorFill() + + if iconpickerData.warning then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, control.container, LEFT, -5, 0) + control.warning.data = {tooltipText = iconpickerData.warning} + end + + if iconpickerData.disabled then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + control.UpdateChoices = UpdateChoices + control.UpdateValue = UpdateValue + control:UpdateValue() + control.SetColor = SetColor + control:SetColor() + control.SetIconSize = SetIconSize + control:SetIconSize(iconSize) + + if control.panel.data.registerForRefresh or control.panel.data.registerForDefaults then --if our parent window wants to refresh controls, then add this to the list + tinsert(control.panel.controlsToRefresh, control) + end + + return control +end diff --git a/Libs/LibAddonMenu-2.0/controls/panel.lua b/Libs/LibAddonMenu-2.0/controls/panel.lua index 46d39a0..0d698c7 100644 --- a/Libs/LibAddonMenu-2.0/controls/panel.lua +++ b/Libs/LibAddonMenu-2.0/controls/panel.lua @@ -4,6 +4,7 @@ displayName = "My Longer Window Title", --(optional) (can be useful for long addon names or if you want to colorize it) author = "Seerah", --(optional) version = "2.0", --(optional) + keywords = "settings", --(optional) additional keywords for search filter (it looks for matches in name..keywords..author) slashCommand = "/myaddon", --(optional) will register a keybind to open to this panel (don't forget to include the slash!) registerForRefresh = true, --boolean (optional) (will refresh all options controls when a setting is changed and when the panel is shown) registerForDefaults = true, --boolean (optional) (will set all options controls back to default values) @@ -11,7 +12,7 @@ } ]] -local widgetVersion = 8 +local widgetVersion = 9 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("panel", widgetVersion) then return end @@ -53,7 +54,7 @@ local function ForceDefaults(panel) end ESO_Dialogs["LAM_DEFAULTS"] = { title = { - text = SI_OPTIONS_RESET_TITLE, + text = SI_INTERFACE_OPTIONS_RESET_TO_DEFAULT_TOOLTIP, }, mainText = { text = SI_OPTIONS_RESET_PROMPT, @@ -73,29 +74,19 @@ ESO_Dialogs["LAM_DEFAULTS"] = { local callbackRegistered = false LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1 function LAMCreateControl.panel(parent, panelData, controlName) - local control = wm:CreateTopLevelWindow(controlName) - control:SetParent(parent) - - control.bg = wm:CreateControl(nil, control, CT_BACKDROP) - local bg = control.bg - bg:SetAnchorFill() - bg:SetEdgeTexture("EsoUI\\Art\\miscellaneous\\borderedinsettransparent_edgefile.dds", 128, 16) - bg:SetCenterColor(0, 0, 0, 0) + 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, 10, 10) - label:SetText(panelData.displayName and panelData.displayName or panelData.name) + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4) + label:SetText(panelData.displayName or panelData.name) if panelData.author or panelData.version then control.info = wm:CreateControl(nil, control, CT_LABEL) local info = control.info info:SetFont("$(CHAT_FONT)|14|soft-shadow-thin") - info:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA()) - info:SetHeight(13) - info:SetAnchor(TOPRIGHT, control, BOTTOMRIGHT, -5, 2) + info:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) if panelData.author and panelData.version then - --info:SetText("Version: "..panelData.version.." - "..GetString(SI_ADDON_MANAGER_AUTHOR)..": "..panelData.author) info:SetText(string.format("Version: %s - %s: %s", panelData.version, GetString(SI_ADDON_MANAGER_AUTHOR), panelData.author)) elseif panelData.author then info:SetText(string.format("%s: %s", GetString(SI_ADDON_MANAGER_AUTHOR), panelData.author)) @@ -107,7 +98,7 @@ function LAMCreateControl.panel(parent, panelData, controlName) control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer") LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1 local container = control.container - container:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 20) + 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) @@ -118,7 +109,7 @@ function LAMCreateControl.panel(parent, panelData, controlName) defaultButton:SetFont("ZoFontDialogKeybindDescription") defaultButton:SetHorizontalAlignment(TEXT_ALIGN_LEFT) --defaultButton:SetText("Reset To Defaults") - defaultButton:SetText(GetString(SI_OPTIONS_RESET_TITLE)) + defaultButton:SetText(GetString(SI_OPTIONS_DEFAULTS)) defaultButton:SetDimensions(200, 30) defaultButton:SetAnchor(TOPLEFT, control, BOTTOMLEFT, 0, 2) defaultButton:SetHandler("OnClicked", function() @@ -135,4 +126,7 @@ function LAMCreateControl.panel(parent, panelData, controlName) control.controlsToRefresh = {} return control -end \ No newline at end of file +end + + +-- vi: noexpandtab diff --git a/Libs/LibAddonMenu-2.0/controls/slider.lua b/Libs/LibAddonMenu-2.0/controls/slider.lua index e02cb5d..93eafd8 100644 --- a/Libs/LibAddonMenu-2.0/controls/slider.lua +++ b/Libs/LibAddonMenu-2.0/controls/slider.lua @@ -15,7 +15,7 @@ } ]] -local widgetVersion = 6 +local widgetVersion = 7 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("slider", widgetVersion) then return end @@ -68,39 +68,18 @@ end function LAMCreateControl.slider(parent, sliderData, controlName) - local control = wm:CreateControl(controlName or sliderData.reference, parent.scroll or parent, CT_CONTROL) - local isHalfWidth = sliderData.width == "half" - if isHalfWidth then - control:SetDimensions(250, 55) - else - control:SetDimensions(510, 40) - end - control:SetMouseEnabled(true) - --control.tooltipText = sliderData.tooltip - control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - - control.label = wm:CreateControl(nil, control, CT_LABEL) - local label = control.label - label:SetFont("ZoFontWinH4") - label:SetDimensions(isHalfWidth and 250 or 300, 26) - label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) - label:SetAnchor(isHalfWidth and TOPLEFT or LEFT) - label:SetText(sliderData.name) + local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName) --skipping creating the backdrop... Is this the actual slider texture? - control.slider = wm:CreateControl(nil, control, CT_SLIDER) + control.slider = wm:CreateControl(nil, control.container, CT_SLIDER) local slider = control.slider - slider:SetDimensions(190, 14) - if isHalfWidth then - slider:SetAnchor(TOPRIGHT, label, BOTTOMRIGHT, -5, 2) - else - slider:SetAnchor(RIGHT, control, RIGHT, -5, -5) - end + 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) + 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) @@ -132,8 +111,8 @@ function LAMCreateControl.slider(parent, sliderData, controlName) control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop") local slidervalue = control.slidervalue slidervalue:ClearAnchors() - slidervalue:SetAnchor(TOPLEFT, slidervaluebg, TOPLEFT, 3, 1) - slidervalue:SetAnchor(BOTTOMRIGHT, slidervaluebg, BOTTOMRIGHT, -3, -1) + 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) @@ -150,7 +129,7 @@ function LAMCreateControl.slider(parent, sliderData, controlName) slider:SetHandler("OnValueChanged", function(self, value, eventReason) if eventReason == EVENT_REASON_SOFTWARE then return end self:SetValue(value) --do we actually need this line? - slidervalue:SetText(value) + slidervalue:SetText(value) end) slider:SetHandler("OnSliderReleased", function(self, value) --sliderData.setFunc(value) @@ -160,14 +139,9 @@ function LAMCreateControl.slider(parent, sliderData, controlName) if sliderData.warning then control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") control.warning:SetAnchor(RIGHT, slider, LEFT, -5, 0) - --control.warning.tooltipText = sliderData.warning control.warning.data = {tooltipText = sliderData.warning} end - control.panel = parent.panel or parent --if this is in a submenu, panel is the submenu's parent - control.data = sliderData - control.data.tooltipText = sliderData.tooltip - if sliderData.disabled then control.UpdateDisabled = UpdateDisabled control:UpdateDisabled() diff --git a/Libs/LibAddonMenu-2.0/controls/submenu.lua b/Libs/LibAddonMenu-2.0/controls/submenu.lua index c456d49..8022809 100644 --- a/Libs/LibAddonMenu-2.0/controls/submenu.lua +++ b/Libs/LibAddonMenu-2.0/controls/submenu.lua @@ -6,7 +6,7 @@ reference = "MyAddonSubmenu" --(optional) unique global reference to control } ]] -local widgetVersion = 8 +local widgetVersion = 9 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("submenu", widgetVersion) then return end @@ -18,7 +18,7 @@ local tinsert = table.insert local function UpdateValue(control) control.label:SetText(control.data.name) if control.data.tooltip then - control.label.data = {tooltipText = control.data.tooltip} + control.label.data.tooltipText = LAM.util.GetTooltipText(control.data.tooltip) end end @@ -33,21 +33,21 @@ local function AnimateSubmenu(clicked) 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:SetDimensions(523, 40) + 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(520, 30) + label:SetDimensions(width, 30) label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) label:SetText(submenuData.name) label:SetMouseEnabled(true) if submenuData.tooltip then - label.data = {tooltipText = submenuData.tooltip} + label.data = {tooltipText = LAM.util.GetTooltipText(submenuData.tooltip)} label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) end @@ -56,7 +56,7 @@ function LAMCreateControl.submenu(parent, submenuData, controlName) local scroll = control.scroll scroll:SetParent(control) scroll:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 10) - scroll:SetDimensionConstraints(525, 0, 525, 2500) + scroll:SetDimensionConstraints(width + 5, 0, width + 5, 2500) control.bg = wm:CreateControl(nil, label, CT_BACKDROP) local bg = control.bg @@ -102,8 +102,6 @@ function LAMCreateControl.submenu(parent, submenuData, controlName) btmToggle:SetAlpha(0) btmToggle:SetHandler("OnMouseUp", AnimateSubmenu) - control.data = submenuData - 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 diff --git a/Libs/LibAddonMenu-2.0/controls/texture.lua b/Libs/LibAddonMenu-2.0/controls/texture.lua index d0e6905..c6ef95d 100644 --- a/Libs/LibAddonMenu-2.0/controls/texture.lua +++ b/Libs/LibAddonMenu-2.0/controls/texture.lua @@ -10,23 +10,22 @@ --add texture coords support? -local widgetVersion = 6 +local widgetVersion = 7 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("texture", widgetVersion) then return end local wm = WINDOW_MANAGER +local MIN_HEIGHT = 26 function LAMCreateControl.texture(parent, textureData, controlName) - local control = wm:CreateControl(controlName or textureData.reference, parent.scroll or parent, CT_CONTROL) + local control = LAM.util.CreateBaseControl(parent, textureData, controlName) + local width = control:GetWidth() control:SetResizeToFitDescendents(true) - local isHalfWidth = textureData.width == "half" - if isHalfWidth then - control:SetDimensionConstraints(250, 55, 250, 100) - control:SetDimensions(250, 55) + if control.isHalfWidth then --note these restrictions + control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) else - control:SetDimensionConstraints(510, 30, 510, 100) - control:SetDimensions(510, 30) + control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) end control.texture = wm:CreateControl(nil, control, CT_TEXTURE) @@ -37,14 +36,10 @@ function LAMCreateControl.texture(parent, textureData, controlName) if textureData.tooltip then texture:SetMouseEnabled(true) - --texture.tooltipText = textureData.tooltip - texture.data = {tooltipText = textureData.tooltip} + texture.data = {tooltipText = LAM.util.GetTooltipText(textureData.tooltip)} texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseExit) end - control.panel = parent.panel or parent --if this is in a submenu, panel is its parent - control.data = textureData - return control end \ No newline at end of file diff --git a/Libs/LibStub/LibStub.lua b/Libs/LibStub/LibStub.lua index 4c509a5..41293bc 100644 --- a/Libs/LibStub/LibStub.lua +++ b/Libs/LibStub/LibStub.lua @@ -3,7 +3,7 @@ -- LibStub developed for World of Warcraft by above members of the WowAce community. -- Ported to Elder Scrolls Online by Seerah -local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 1 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 3 local LibStub = _G[LIBSTUB_MAJOR] local strformat = string.format @@ -14,7 +14,9 @@ if not LibStub or LibStub.minor < LIBSTUB_MINOR then function LibStub:NewLibrary(major, minor) assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") - minor = assert(tonumber(zo_strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") + if type(minor) ~= "number" then + minor = assert(tonumber(zo_strmatch(minor, "%d+%.?%d*")), "Minor version must either be a number or contain a number.") + end local oldminor = self.minors[major] if oldminor and oldminor >= minor then return nil end @@ -24,7 +26,7 @@ if not LibStub or LibStub.minor < LIBSTUB_MINOR then function LibStub:GetLibrary(major, silent) if not self.libs[major] and not silent then - error(("Cannot find a library instance of %q."):strformat(tostring(major)), 2) + error(strformat("Cannot find a library instance of %q.", tostring(major)), 2) end return self.libs[major], self.minors[major] end diff --git a/ReadMe.md b/ReadMe.md index 42e4947..99431ae 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,18 +1,17 @@ -# Disclaimer +# Slightly Improved Attribute Bars -This Add-on is not created by, affiliated with or sponsored by ZeniMax Media -Inc. or its affiliates. The Elder Scrolls® and related logos are registered -trademarks or trademarks of ZeniMax Media Inc. in the United States and/or -other countries. All rights reserved. +## Disclaimer -# Details +This Add-on is not created by, affiliated with or sponsored by ZeniMax Media Inc. or its affiliates. The Elder Scrolls® and related logos are registered trademarks or trademarks of ZeniMax Media Inc. in the United States and/or other countries. All rights reserved. -This is an addon for Elder Scrolls Online. +## Details -The goal of this addon is to gently improve the attribute bars without taking too much away from their original design or intent. This slight improvement to the default attribute bars adds the following functionality: +This is an add-on for Elder Scrolls Online. + +The goal of this add-on is to gently improve the attribute bars without taking too much away from their original design or intent. This slight improvement to the default attribute bars adds the following functionality: ## Features -1. Prevents the bars from completely fading out. The amount of fade is configurable and defaults to 60% fade out. It can be set such that the health, stamina, and magicka bars never fade out (are always visible). -2. Shifts the magicka and stamina bars closer to the health bar. This is more useful on higher resolution displays. This feature is on by default and can be disabled. -3. Adds text over each attribute bar that shows current + maximum value and/or a percentage value. The default configuration is to show just the percentage. The current + maximum value can also be enabled. +1. Prevents the bars from completely fading out. The amount of fade is configurable and defaults to 60%. It can be set such that the health, stamina, and Magicka bars never fade out (always visible). +2. Shifts the Magicka and stamina bars closer to the health bar. This is more useful on higher resolution displays. This feature is on by default and can be disabled. +3. Adds text over each attribute bar that shows current and maximum value and/or the percentage value. The default configuration is to show just the percentage. 4. Moves the target reticle to the bottom of the screen just above the health bar. This is enabled by default and can be turned off. diff --git a/SlightlyImprovedAttributeBars.lua b/SlightlyImprovedAttributeBars.lua index 7f186e5..ad336a9 100644 --- a/SlightlyImprovedAttributeBars.lua +++ b/SlightlyImprovedAttributeBars.lua @@ -2,190 +2,190 @@ SIAB = {} SIAB.name = "SlightlyImprovedAttributeBars" -SIAB.version = "1.14" +SIAB.version = "1.15" SIAB.loaded = false SIAB.playerLabels = {} SIAB.configVersion = 3 SIAB.defaults = { - attributeBarAlpha = 0.4, - playerAttributeBarShift = 0, - showPercentageText = true, - showCurrentMaxText = false, - targetReticleOffset = -1, - targetReticleAlpha = 1.0, - moveTargetReticle = true, - lockAttributeBarWidth = false, + attributeBarAlpha = 0.4, + playerAttributeBarShift = 0, + showPercentageText = true, + showCurrentMaxText = false, + targetReticleOffset = -1, + targetReticleAlpha = 1.0, + moveTargetReticle = true, + lockAttributeBarWidth = false, } -- Create a one line text label for placing over an attribute or experience bar function SIAB.NewBarLabel(name, parent) - local label = WINDOW_MANAGER:CreateControl(name, parent, CT_LABEL) - label:SetDimensions(parent:GetWidth(), 20) - label:SetAnchor(CENTER, parent, CENTER, 0, -1) - label:SetFont("ZoFontGame") - label:SetColor(0.9, 0.9, 0.9, 1) - label:SetHorizontalAlignment(1) - label:SetVerticalAlignment(1) - return label + local label = WINDOW_MANAGER:CreateControl(name, parent, CT_LABEL) + label:SetDimensions(parent:GetWidth(), 20) + label:SetAnchor(CENTER, parent, CENTER, 0, -1) + label:SetFont("ZoFontGame") + label:SetColor(0.9, 0.9, 0.9, 1) + label:SetHorizontalAlignment(1) + label:SetVerticalAlignment(1) + return label end function SIAB.NewAttributeLabel(name, parent, powerType) - - local label = SIAB.NewBarLabel(name, parent) - - if powerType then - local powerCurrent, powerMax, powerEffectiveMax = GetUnitPower("player", powerType) - label:SetText(SIAB.FormatLabelText(powerCurrent, powerEffectiveMax)) - end - - return label - + + local label = SIAB.NewBarLabel(name, parent) + + if powerType then + local powerCurrent, powerMax, powerEffectiveMax = GetUnitPower("player", powerType) + label:SetText(SIAB.FormatLabelText(powerCurrent, powerEffectiveMax)) + end + + return label + end -- Create the controls for the configuration pannel function SIAB.CreateConfiguration() - local LAM = LibStub("LibAddonMenu-2.0") - - local panelData = { - type = "panel", - name = "Attribute Bars", - displayName = "Slightly Improved Attribute Bars", - author = "L8Knight", - version = SIAB.version, - registerForDefaults = true, - } - - LAM:RegisterAddonPanel(SIAB.name.."Config", panelData) - - -- Get the current screen dimensions (TODO: won't be accurate if they resize during play then try to reconfigure) - local screenWidth, screenHeight = GuiRoot:GetDimensions() - - local controlData = { - [1] = { - type = "slider", - name = "Attribute Bar Transparency", - tooltip = "Transparency value to use when player attribute bars are full and would normally be hidden", - min = 0, max = 10, step = 1, - getFunc = function() return SIAB.vars.attributeBarAlpha * 10 end, - setFunc = function(newValue) SIAB.vars.attributeBarAlpha = newValue / 10.0; SIAB.RefreshAll() end, - default = SIAB.defaults.attributeBarAlpha * 10, - }, - [2] = { - type = "slider", - name = "Horizontal Gap", - tooltip = "Horizontal gap between magicka, health, and stamina bars", - min = 0, max = SIAB.defaults.playerAttributeBarShift, step = 1, - getFunc = function() return SIAB.vars.playerAttributeBarShift end, - setFunc = function(newValue) SIAB.vars.playerAttributeBarShift = newValue; SIAB.RefreshAll() end, - default = SIAB.defaults.playerAttributeBarShift, - }, - [3] = { - type = "checkbox", - name = "Reposition Target Reticle", - tooltip = "Reposition target reticle to bottom of screen", - getFunc = function() return SIAB.vars.moveTargetReticle end, - setFunc = function(newValue) SIAB.vars.moveTargetReticle = newValue; SIAB.RefreshAll() end, - default = SIAB.defaults.moveTargetReticle, - }, - [4] = { - type = "slider", - name = "Target Reticle Verticle Offset", - tooltip = "Vertical offset for the target reticle from the original position", - min = 0, max = math.floor(screenHeight), step = 1, - getFunc = function() return SIAB.vars.targetReticleOffset end, - setFunc = function(newValue) SIAB.vars.targetReticleOffset = newValue; SIAB.RefreshAll() end, - default = SIAB.defaults.targetReticleOffset, - }, - [5] = { - type = "slider", - name = "Target Reticle Transparency", - tooltip = "Transparency value to use for the target reticle", - min = 0, max = 10, step = 1, - getFunc = function() return SIAB.vars.targetReticleAlpha * 10 end, - setFunc = function(newValue) SIAB.vars.targetReticleAlpha = newValue / 10.0; SIAB.RefreshAll() end, - default = SIAB.defaults.targetReticleAlpha * 10, - }, - [6] = { - type = "checkbox", - name = "Show Percentage Text", - tooltip = "Show attribute value as a percent", - getFunc = function() return SIAB.vars.showPercentageText end, - setFunc = function(newValue) SIAB.vars.showPercentageText = newValue; SIAB.RefreshAll() end, - default = SIAB.defaults.showPercentageText, - }, - [7] = { - type = "checkbox", - name = "Show Cur/Max Text", - tooltip = "Show current/maximum attribute values", - getFunc = function() return SIAB.vars.showCurrentMaxText end, - setFunc = function(newValue) SIAB.vars.showCurrentMaxText = newValue; SIAB.RefreshAll() end, - default = SIAB.defaults.showCurrentMaxText, - }, - [8] = { - type = "checkbox", - name = "Lock Attribute Bar Width", - tooltip = "Lock the attribute bar to prevent food buffs from changing the width", - getFunc = function() return SIAB.vars.lockAttributeBarWidth end, - setFunc = function(newValue) SIAB.vars.lockAttributeBarWidth = newValue; SIAB.RefreshAll() end, - default = SIAB.defaults.lockAttributeBarWidth, - warning = "Requires UI reload when turning off", - }, - } - - --SIAB.reticleSlider = LAM:AddSlider(panelId, "SIAB.ReticleOffsetConfig", - - LAM:RegisterOptionControls(SIAB.name.."Config", controlData) + local LAM = LibStub("LibAddonMenu-2.0") + + local panelData = { + type = "panel", + name = "Attribute Bars", + displayName = "Slightly Improved Attribute Bars", + author = "L8Knight", + version = SIAB.version, + registerForDefaults = true, + } + + LAM:RegisterAddonPanel(SIAB.name.."Config", panelData) + + -- Get the current screen dimensions (TODO: won't be accurate if they resize during play then try to reconfigure) + local screenWidth, screenHeight = GuiRoot:GetDimensions() + + local controlData = { + [1] = { + type = "slider", + name = "Attribute Bar Transparency", + tooltip = "Transparency value to use when player attribute bars are full and would normally be hidden", + min = 0, max = 10, step = 1, + getFunc = function() return SIAB.vars.attributeBarAlpha * 10 end, + setFunc = function(newValue) SIAB.vars.attributeBarAlpha = newValue / 10.0; SIAB.RefreshAll() end, + default = SIAB.defaults.attributeBarAlpha * 10, + }, + [2] = { + type = "slider", + name = "Horizontal Gap", + tooltip = "Horizontal gap between magicka, health, and stamina bars", + min = 0, max = SIAB.defaults.playerAttributeBarShift, step = 1, + getFunc = function() return SIAB.vars.playerAttributeBarShift end, + setFunc = function(newValue) SIAB.vars.playerAttributeBarShift = newValue; SIAB.RefreshAll() end, + default = SIAB.defaults.playerAttributeBarShift, + }, + [3] = { + type = "checkbox", + name = "Reposition Target Reticle", + tooltip = "Reposition target reticle to bottom of screen", + getFunc = function() return SIAB.vars.moveTargetReticle end, + setFunc = function(newValue) SIAB.vars.moveTargetReticle = newValue; SIAB.RefreshAll() end, + default = SIAB.defaults.moveTargetReticle, + }, + [4] = { + type = "slider", + name = "Target Reticle Verticle Offset", + tooltip = "Vertical offset for the target reticle from the original position", + min = 0, max = math.floor(screenHeight), step = 1, + getFunc = function() return SIAB.vars.targetReticleOffset end, + setFunc = function(newValue) SIAB.vars.targetReticleOffset = newValue; SIAB.RefreshAll() end, + default = SIAB.defaults.targetReticleOffset, + }, + [5] = { + type = "slider", + name = "Target Reticle Transparency", + tooltip = "Transparency value to use for the target reticle", + min = 0, max = 10, step = 1, + getFunc = function() return SIAB.vars.targetReticleAlpha * 10 end, + setFunc = function(newValue) SIAB.vars.targetReticleAlpha = newValue / 10.0; SIAB.RefreshAll() end, + default = SIAB.defaults.targetReticleAlpha * 10, + }, + [6] = { + type = "checkbox", + name = "Show Percentage Text", + tooltip = "Show attribute value as a percent", + getFunc = function() return SIAB.vars.showPercentageText end, + setFunc = function(newValue) SIAB.vars.showPercentageText = newValue; SIAB.RefreshAll() end, + default = SIAB.defaults.showPercentageText, + }, + [7] = { + type = "checkbox", + name = "Show Cur/Max Text", + tooltip = "Show current/maximum attribute values", + getFunc = function() return SIAB.vars.showCurrentMaxText end, + setFunc = function(newValue) SIAB.vars.showCurrentMaxText = newValue; SIAB.RefreshAll() end, + default = SIAB.defaults.showCurrentMaxText, + }, + [8] = { + type = "checkbox", + name = "Lock Attribute Bar Width", + tooltip = "Lock the attribute bar to prevent food buffs from changing the width", + getFunc = function() return SIAB.vars.lockAttributeBarWidth end, + setFunc = function(newValue) SIAB.vars.lockAttributeBarWidth = newValue; SIAB.RefreshAll() end, + default = SIAB.defaults.lockAttributeBarWidth, + warning = "Requires UI reload when turning off", + }, + } + + --SIAB.reticleSlider = LAM:AddSlider(panelId, "SIAB.ReticleOffsetConfig", + + LAM:RegisterOptionControls(SIAB.name.."Config", controlData) end -- Initializer functions that runs once when the game is loading addons function SIAB.Initialize(eventCode, addOnName) - -- Only initialize our own addon - if (SIAB.name ~= addOnName) then return end + -- Only initialize our own addon + if (SIAB.name ~= addOnName) then return end - -- Initialize values so their relative to in-game controls - local isValidAnchor, point, relativeTo, relativePoint, offsetX, offsetY = ZO_PlayerAttributeMagicka:GetAnchor(0) - SIAB.defaults.playerAttributeBarShift = math.abs(offsetX) + -- Initialize values so their relative to in-game controls + local isValidAnchor, point, relativeTo, relativePoint, offsetX, offsetY = ZO_PlayerAttributeMagicka:GetAnchor(0) + SIAB.defaults.playerAttributeBarShift = math.abs(offsetX) - -- Load the saved variables - SIAB.vars = ZO_SavedVars:NewAccountWide("SIABVars", SIAB.configVersion, nil, SIAB.defaults) + -- Load the saved variables + SIAB.vars = ZO_SavedVars:NewAccountWide("SIABVars", SIAB.configVersion, nil, SIAB.defaults) - -- Initialize the offset to be just above the health bar - if (SIAB.vars.targetReticleOffset == -1) then - SIAB.vars.targetReticleOffset = ZO_PlayerAttributeHealth:GetTop() - 175 - end + -- Initialize the offset to be just above the health bar + if (SIAB.vars.targetReticleOffset == -1) then + SIAB.vars.targetReticleOffset = zo_floor(ZO_PlayerAttributeHealth:GetTop() - 175) + end - -- Save the original offset in case this feature is disabled - local isValidAnchor, point, relativeTo, relativePoint, offsetX, offsetY = ZO_TargetUnitFramereticleover:GetAnchor(0) - SIAB.originalTargetReticleOffset = offsetY + -- Save the original offset in case this feature is disabled + local isValidAnchor, point, relativeTo, relativePoint, offsetX, offsetY = ZO_TargetUnitFramereticleover:GetAnchor(0) + SIAB.originalTargetReticleOffset = offsetY - -- Create config menu - SIAB.CreateConfiguration() + -- Create config menu + SIAB.CreateConfiguration() - -- Create labels for the player information - local stats = { "Health", "Stamina", "Magicka"} - local types = { POWERTYPE_HEALTH, POWERTYPE_STAMINA, POWERTYPE_MAGICKA } - for i = 1, #stats, 1 do - local parent = _G["ZO_PlayerAttribute"..stats[i]] - SIAB.playerLabels[types[i]] = SIAB.NewAttributeLabel("SIAB_"..stats[i].."Label", parent, types[i]) - end + -- Create labels for the player information + local stats = { "Health", "Stamina", "Magicka"} + local types = { POWERTYPE_HEALTH, POWERTYPE_STAMINA, POWERTYPE_MAGICKA } + for i = 1, #stats, 1 do + local parent = _G["ZO_PlayerAttribute"..stats[i]] + SIAB.playerLabels[types[i]] = SIAB.NewAttributeLabel("SIAB_"..stats[i].."Label", parent, types[i]) + end - -- Create a label for the target information - SIAB.targetLabel = SIAB.NewBarLabel("SIAB_TargetHealthLabel", ZO_TargetUnitFramereticleover) + -- Create a label for the target information + SIAB.targetLabel = SIAB.NewBarLabel("SIAB_TargetHealthLabel", ZO_TargetUnitFramereticleover) - SIAB.attribWidth = ZO_PlayerAttributeHealth:GetWidth() - SIAB.attribHeight = ZO_PlayerAttributeHealth:GetHeight() + SIAB.attribWidth = ZO_PlayerAttributeHealth:GetWidth() + SIAB.attribHeight = ZO_PlayerAttributeHealth:GetHeight() - SIAB.RefreshAll() + SIAB.RefreshAll() - -- Register for future power updates - EVENT_MANAGER:RegisterForEvent("SIAB", EVENT_POWER_UPDATE, SIAB.PowerUpdate) - - SIAB.loaded = true + -- Register for future power updates + EVENT_MANAGER:RegisterForEvent("SIAB", EVENT_POWER_UPDATE, SIAB.PowerUpdate) + + SIAB.loaded = true end @@ -194,157 +194,156 @@ EVENT_MANAGER:RegisterForEvent("SIAB", EVENT_ADD_ON_LOADED, SIAB.Initialize) function SIAB.RefreshAll() - SIAB.UpdateAttributeLocking() - SIAB.RefreshAttributeBars() - SIAB.RefreshTargetReticle() + SIAB.UpdateAttributeLocking() + SIAB.RefreshAttributeBars() + SIAB.RefreshTargetReticle() end function SIAB.UpdateAttributeLocking() - if SIAB.vars.lockAttributeBarWidth then - --width = 237 - --height = 23 - width = SIAB.attribWidth - height = SIAB.attribHeight - else - width = nil - height = nil - end - - ZO_PlayerAttributeHealth:SetDimensionConstraints(width, height, width, height) - ZO_PlayerAttributeHealthBgContainer:SetDimensionConstraints(width, height, width, height) - ZO_PlayerAttributeMagicka:SetDimensionConstraints(width, height, width, height) - ZO_PlayerAttributeMagickaBgContainer:SetDimensionConstraints(width, height, width, height) - ZO_PlayerAttributeStamina:SetDimensionConstraints(width, height, width, height) - ZO_PlayerAttributeStaminaBgContainer:SetDimensionConstraints(width, height, width, height) + if SIAB.vars.lockAttributeBarWidth then + --width = 237 + --height = 23 + width = SIAB.attribWidth + height = SIAB.attribHeight + else + width = nil + height = nil + end + + ZO_PlayerAttributeHealth:SetDimensionConstraints(width, height, width, height) + ZO_PlayerAttributeHealthBgContainer:SetDimensionConstraints(width, height, width, height) + ZO_PlayerAttributeMagicka:SetDimensionConstraints(width, height, width, height) + ZO_PlayerAttributeMagickaBgContainer:SetDimensionConstraints(width, height, width, height) + ZO_PlayerAttributeStamina:SetDimensionConstraints(width, height, width, height) + ZO_PlayerAttributeStaminaBgContainer:SetDimensionConstraints(width, height, width, height) end function SIAB.RefreshTargetReticle() - local isValidAnchor, point, relativeTo, relativePoint, offsetX, offsetY = ZO_TargetUnitFramereticleover:GetAnchor(0) + local isValidAnchor, point, relativeTo, relativePoint, offsetX, offsetY = ZO_TargetUnitFramereticleover:GetAnchor(0) - -- Only adjust the target reticle if configured to do so. Allows for better integration with other addons - if (SIAB.vars.moveTargetReticle) then - --SIAB.reticleSlider:SetAlpha(1.0) - offsetY = SIAB.vars.targetReticleOffset - else - --SIAB.reticleSlider:SetAlpha(0.0) - offsetY = SIAB.originalTargetReticleOffset - end + -- Only adjust the target reticle if configured to do so. Allows for better integration with other addons + if (SIAB.vars.moveTargetReticle) then + --SIAB.reticleSlider:SetAlpha(1.0) + offsetY = SIAB.vars.targetReticleOffset + else + --SIAB.reticleSlider:SetAlpha(0.0) + offsetY = SIAB.originalTargetReticleOffset + end - ZO_TargetUnitFramereticleover:ClearAnchors() - ZO_TargetUnitFramereticleover:SetAnchor(point, relativeTo, relativePoint, offsetX, offsetY) - ZO_TargetUnitFramereticleover:SetAlpha(SIAB.vars.targetReticleAlpha) + ZO_TargetUnitFramereticleover:ClearAnchors() + ZO_TargetUnitFramereticleover:SetAnchor(point, relativeTo, relativePoint, offsetX, offsetY) + ZO_TargetUnitFramereticleover:SetAlpha(SIAB.vars.targetReticleAlpha) end function SIAB.RefreshAttributeBars() - - local stats = { "Health", "Stamina", "Magicka"} - local types = { POWERTYPE_HEALTH, POWERTYPE_STAMINA, POWERTYPE_MAGICKA } - for i = 1, #stats, 1 do + local stats = { "Health", "Stamina", "Magicka"} + local types = { POWERTYPE_HEALTH, POWERTYPE_STAMINA, POWERTYPE_MAGICKA } + + for i = 1, #stats, 1 do - local attribBar = _G["ZO_PlayerAttribute"..stats[i]] + local attribBar = _G["ZO_PlayerAttribute"..stats[i]] - -- Get the current anchor point and adjust it a bit more to the middle of the screen - local isValidAnchor, point, relativeTo, relativePoint, offsetX, offsetY = attribBar:GetAnchor(0) + -- Get the current anchor point and adjust it a bit more to the middle of the screen + local isValidAnchor, point, relativeTo, relativePoint, offsetX, offsetY = attribBar:GetAnchor(0) - -- Adjust both bars to the left/right by half of the width of the health bar - if (stats[i] == "Magicka") then - offsetX = 0 - SIAB.vars.playerAttributeBarShift - -- Set a new anchor point relative to the health bar in the center - attribBar:ClearAnchors() - attribBar:SetAnchor(point, ZO_PlayerAttributeHealth, relativePoint, offsetX, offsetY) - elseif (stats[i] == "Stamina") then - offsetX = 0 + SIAB.vars.playerAttributeBarShift - -- Set a new anchor point relative to the health bar in the center - attribBar:ClearAnchors() - attribBar:SetAnchor(point, ZO_PlayerAttributeHealth, relativePoint, offsetX, offsetY) - end + -- Adjust both bars to the left/right by half of the width of the health bar + if (stats[i] == "Magicka") then + offsetX = 0 - SIAB.vars.playerAttributeBarShift + -- Set a new anchor point relative to the health bar in the center + attribBar:ClearAnchors() + attribBar:SetAnchor(point, ZO_PlayerAttributeHealth, relativePoint, offsetX, offsetY) + elseif (stats[i] == "Stamina") then + offsetX = 0 + SIAB.vars.playerAttributeBarShift + -- Set a new anchor point relative to the health bar in the center + attribBar:ClearAnchors() + attribBar:SetAnchor(point, ZO_PlayerAttributeHealth, relativePoint, offsetX, offsetY) + end - -- Refresh the label text - local powerCurrent, powerMax, powerEffectiveMax = GetUnitPower("player", types[i]) - SIAB.playerLabels[types[i]]:SetText(SIAB.FormatLabelText(powerCurrent, powerEffectiveMax)) + -- Refresh the label text + local powerCurrent, powerMax, powerEffectiveMax = GetUnitPower("player", types[i]) + SIAB.playerLabels[types[i]]:SetText(SIAB.FormatLabelText(powerCurrent, powerEffectiveMax)) - attribBar:SetAlpha(SIAB.vars.attributeBarAlpha) + attribBar:SetAlpha(SIAB.vars.attributeBarAlpha) - end + end end -- Create the label string based on user preferences function SIAB.FormatLabelText(current, max) - local percent = 0 - if (max > 0) then - percent = math.floor((current/max) * 100) - end + local percent = 0 + if (max > 0) then + percent = math.floor((current/max) * 100) + end - local str = "" + local str = "" - if (SIAB.vars.showCurrentMaxText) then - str = str .. current .. " / " .. max - end + if (SIAB.vars.showCurrentMaxText) then + str = str .. current .. " / " .. max + end - if (SIAB.vars.showPercentageText) then - if (SIAB.vars.showCurrentMaxText) then - str = str .. " " - end - str = str .. percent .. "%" - end + if (SIAB.vars.showPercentageText) then + if (SIAB.vars.showCurrentMaxText) then + str = str .. " " + end + str = str .. percent .. "%" + end - return str + return str end -- Callback for the power update event function SIAB.PowerUpdate(eventCode, unitTag, powerIndex, powerType, powerValue, powerMax, powerEffectiveMax) - if (unitTag ~= "player" and unitTag ~= "reticleover") then return end + if (unitTag ~= "player" and unitTag ~= "reticleover") then return end - if (powerType ~= POWERTYPE_HEALTH and powerType ~= POWERTYPE_STAMINA and powerType ~= POWERTYPE_MAGICKA) then return end + if (powerType ~= POWERTYPE_HEALTH and powerType ~= POWERTYPE_STAMINA and powerType ~= POWERTYPE_MAGICKA) then return end - -- Find the correct label to use (either player or targeting reticle) - local label = nil - if (unitTag == "player") then - label = SIAB.playerLabels[powerType] - elseif (unitTag == "reticleover") then - label = SIAB.targetLabel - end + -- Find the correct label to use (either player or targeting reticle) + local label = nil + if (unitTag == "player") then + label = SIAB.playerLabels[powerType] + elseif (unitTag == "reticleover") then + label = SIAB.targetLabel + end - label:SetText(SIAB.FormatLabelText(powerValue, powerEffectiveMax)) + label:SetText(SIAB.FormatLabelText(powerValue, powerEffectiveMax)) end -- Callback for the gui control from the xml file function SIAB.OnUpdate() - -- Update was triggered before the saved variables were loaded - if (SIAB.loaded == false) then return end + -- Update was triggered before the saved variables were loaded + if (SIAB.loaded == false) then return end - -- Emulate the default UI behavior if alpha is 0 - if (SIAB.vars.attributeBarAlpha == 0.0) then return end + -- Emulate the default UI behavior if alpha is 0 + if (SIAB.vars.attributeBarAlpha == 0.0) then return end - -- Continuously set the alpha of the three player attribute bars so they - -- don't fade out completely - local stats = { "Health", "Stamina", "Magicka"} - for i = 1, #stats, 1 do - local control = _G["ZO_PlayerAttribute"..stats[i]] - local curAlpha = control:GetAlpha() - if (curAlpha < SIAB.vars.attributeBarAlpha) then - control:SetAlpha(SIAB.vars.attributeBarAlpha) - end - end + -- Continuously set the alpha of the three player attribute bars so they + -- don't fade out completely + local stats = { "Health", "Stamina", "Magicka"} + for i = 1, #stats, 1 do + local control = _G["ZO_PlayerAttribute"..stats[i]] + local curAlpha = control:GetAlpha() + if (curAlpha < SIAB.vars.attributeBarAlpha) then + control:SetAlpha(SIAB.vars.attributeBarAlpha) + end + end - -- Update the target reticle text if there is a target - local powerCurrent, powerMax, powerEffectiveMax = GetUnitPower("reticleover", POWERTYPE_HEALTH) - if (powerEffectiveMax > 0) then - SIAB.targetLabel:SetText(SIAB.FormatLabelText(powerCurrent, powerEffectiveMax)) - end + -- Update the target reticle text if there is a target + local powerCurrent, powerMax, powerEffectiveMax = GetUnitPower("reticleover", POWERTYPE_HEALTH) + if (powerEffectiveMax > 0) then + SIAB.targetLabel:SetText(SIAB.FormatLabelText(powerCurrent, powerEffectiveMax)) + end - ZO_TargetUnitFramereticleover:SetAlpha(SIAB.vars.targetReticleAlpha) + ZO_TargetUnitFramereticleover:SetAlpha(SIAB.vars.targetReticleAlpha) end - diff --git a/SlightlyImprovedAttributeBars.txt b/SlightlyImprovedAttributeBars.txt index 8b8ca59..e2f0441 100644 --- a/SlightlyImprovedAttributeBars.txt +++ b/SlightlyImprovedAttributeBars.txt @@ -1,6 +1,7 @@ ## Title: Slightly Improved Attribute Bars +## Version: 1.15 ## Description: Adds numerical values to the player attribute bars and prevents them from fading outside of combat. -## APIVersion: 100011 +## APIVersion: 100013 ## OptionalDependsOn: LibAddonMenu-2.0 ## SavedVariables: SIABVars diff --git a/Todo.md b/Todo.md new file mode 100644 index 0000000..c1d713b --- /dev/null +++ b/Todo.md @@ -0,0 +1,6 @@ +# Todo + +- [x] Update compatibility to API 100013 version (check changelog) +- [ ] Reports: sometimes one of the three bar labels gets stuck at a fixed percentage +- [ ] Request: also apply size constraint on target health bar +- [ ] Check the performance during heavy combat with multiple enemies diff --git a/package.bat b/package.bat new file mode 100644 index 0000000..ea2abc2 --- /dev/null +++ b/package.bat @@ -0,0 +1,53 @@ +:: Package your ESO add-on ready for distribution. +:: Version 1.3 Sat, 14 Nov 2015 22:36:23 +0000 +@echo off +setlocal enableextensions enabledelayedexpansion + +set zip=%ProgramFiles%\7-Zip\7z.exe +if not exist "%zip%" goto :zipnotfound + +for %%* in (.) do set name=%%~nx* + +if not exist %name%.txt ( + echo * Please enter the name of your add-on: + set /P name=^> +) + +for /F "tokens=3" %%i in ('findstr /C:"## Version:" %name%.txt') do set version=%%i + +set archive=%name%-%version%.zip + +echo * Packaging %archive%... + +md .package\%name% + +set files=%name%.txt + +for /F %%i in ('findstr /B /R "[^#;]" %name%.txt') do ( + set file=%%~nxi + set files=!files! !file:$^(language^)=*! +) + +if exist package.manifest ( + for /F "tokens=*" %%i in (package.manifest) do ( + set files=!files! %%~nxi + ) +) + +robocopy . .package\%name% %files% /S /XD .* /NJH /NJS /NFL /NDL > nul + +cd .package +"%zip%" a -tzip -bd ..\%archive% %name% > nul +cd .. +rd /S /Q .package + +echo * Done^^! +echo. + +pause +exit /B + +:zipnotfound +echo 7-Zip cannot be found, get it free at http://www.7-zip.org +pause +exit /B diff --git a/package.manifest b/package.manifest new file mode 100644 index 0000000..b9a903d --- /dev/null +++ b/package.manifest @@ -0,0 +1,3 @@ +ReadMe.md +ChangeLog.md +License.md