--[[iconpickerData = { type = "iconpicker", name = "My Icon Picker", -- or string id or function returning a string choices = {"texture path 1", "texture path 2", "texture path 3"}, getFunc = function() return db.var end, setFunc = function(var) db.var = var doStuff() end, tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) maxColumns = 5, -- number of icons in one row (optional) visibleRows = 4.5, -- number of visible rows (optional) iconSize = 28, -- size of the icons (optional) defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional) width = "full", --or "half" (optional) beforeShow = function(control, iconPicker) return preventShow end, -- (optional) disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.var, -- default value or function that returns the default value (optional) reference = "MyAddonIconPicker" -- unique global reference to control (optional) } ]] local widgetVersion = 8 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("iconpicker", widgetVersion) then return end local wm = WINDOW_MANAGER 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.GetStringFromValue(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 or {} end local addedChoices = {} local iconPicker = LAM.util.GetIconPickerMenu() iconPicker:Clear() for i = 1, #choices do local texture = choices[i] if not addedChoices[texture] then -- remove duplicates iconPicker:AddIcon(choices[i], function(self, texture) control.icon:SetTexture(texture) data.setFunc(texture) LAM.util.RequestRefreshIfNeeded(control) end, LAM.util.GetStringFromValue(choicesTooltips[i])) addedChoices[texture] = true end end end local function IsDisabled(control) if type(control.data.disabled) == "function" then return control.data.disabled() else return control.data.disabled end 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, control.icon.color) if disable then control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) else control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) end end local function UpdateValue(control, forceDefault, value) if forceDefault then --if we are forcing defaults value = LAM.util.GetDefaultValue(control.data.default) control.data.setFunc(value) control.icon:SetTexture(value) elseif value then control.data.setFunc(value) --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed LAM.util.RequestRefreshIfNeeded(control) else value = control.data.getFunc() control.icon:SetTexture(value) end end local MIN_HEIGHT = 26 local HALF_WIDTH_LINE_SPACING = 2 local function SetIconSize(control, size) local icon = control.icon icon.size = size icon:SetDimensions(size, size) local height = size + 4 control.dropdown:SetDimensions(size + 20, height) height = math.max(height, MIN_HEIGHT) control.container:SetHeight(height) if control.lineControl then control.lineControl:SetHeight(MIN_HEIGHT + size + HALF_WIDTH_LINE_SPACING) else control:SetHeight(height) end local iconPicker = LAM.util.GetIconPickerMenu() if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then iconPicker:SetIconSize(size) iconPicker:UpdateDimensions() iconPicker:UpdateAnchors() end 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 ~= nil or iconpickerData.requiresReload then control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") control.warning:SetAnchor(RIGHT, control.container, LEFT, -5, 0) control.UpdateWarning = LAM.util.UpdateWarning control:UpdateWarning() end control.UpdateChoices = UpdateChoices control.UpdateValue = UpdateValue control:UpdateValue() control.SetColor = SetColor control:SetColor() control.SetIconSize = SetIconSize control:SetIconSize(iconSize) if iconpickerData.disabled ~= nil then control.UpdateDisabled = UpdateDisabled control:UpdateDisabled() end LAM.util.RegisterForRefreshIfNeeded(control) LAM.util.RegisterForReloadIfNeeded(control) return control end