--[[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