local detailsFramework = _G["DetailsFramework"] if (not detailsFramework or not DetailsFrameworkCanLoad) then return end local unpack = unpack local C_Timer = C_Timer local InCombatLockdown = InCombatLockdown local CreateFrame = CreateFrame local PixelUtil = PixelUtil local _ ---@class df_menu : frame ---@field RefreshOptions fun() ---@field widget_list table ---@field widget_list_by_type table ---@field widgetids table ---@field GetWidgetById fun(optionsFrame: df_menu, id: string): table this should return a widget from the widgetids table ---@class df_menu_table : table ---@field text_template table ---@field id string an unique string or number to identify the button, from parent.widgetids[id], parent is the first argument of BuildMenu and BuildMenuVolatile ---@field namePhraseId string the phrase id (from language localization) to use on the button ---@class df_menu_label : df_menu_table ---@field get function ---@field color table ---@field font string ---@field size number ---@field text string ---@class df_menu_dropdown : df_menu_table ---@field type string ---@field set function ---@field get function ---@field values table ---@field name string ---@field desc string ---@field descPhraseId string ---@field hooks table ---@field include_default boolean ---@class df_menu_toggle : df_menu_table ---@field set function ---@field get function ---@field name string ---@field desc string ---@field descPhraseId string ---@field hooks table ---@field width number ---@field height number ---@field boxfirst boolean ---@class df_menu_range : df_menu_table ---@field set function ---@field get function ---@field min number ---@field max number ---@field step number ---@field name string ---@field desc string ---@field descPhraseId string ---@field hooks table ---@field thumbscale number ---@field usedecimals boolean if true allow fraction values ---@class df_menu_color : df_menu_table ---@field set function ---@field get function ---@field name string ---@field desc string ---@field descPhraseId string ---@field hooks table ---@field boxfirst boolean ---@class df_menu_button : df_menu_table ---@field func function the function to execute when the button is pressed ---@field param1 any the first parameter to pass to the function ---@field param2 any the second parameter to pass to the function ---@field name string text to show on the button ---@field desc string text to show on the tooltip ---@field descPhraseId string the phrase id (from language localization) to use on the tooltip ---@field hooks table a table with hooks to add to the button ---@field width number ---@field height number ---@field inline boolean ---@field icontexture any ---@field icontexcoords table ---@class df_menu_textentry : df_menu_table ---@field func function the function to execute when enter key is pressed ---@field set function same as above 'func' ---@field get function ---@field name string text to show on the button ---@field desc string text to show on the tooltip ---@field descPhraseId string the phrase id (from language localization) to use on the tooltip ---@field hooks table a table with hooks to add to the button ---@field inline boolean if true, the widget is placed in the rigt side of the previous one ---@field align string "left", "center" or "right" ---@field nocombat boolean can't edit when in combat ---@field spacement boolean gives a little of more space from the next widget detailsFramework.OptionsFrameMixin = { } local onWidgetSetInUse = function(widget, widgetTable) if (widgetTable.childrenids) then widget.childrenids = widgetTable.childrenids end widget.children_follow_enabled = widgetTable.children_follow_enabled if (widgetTable.disabled) then widget:Disable() else if (widget.IsEnabled and not widget:IsEnabled()) then widget:Enable() end end end local setWidgetId = function(parent, widgetTable, widgetObject) if (widgetTable.id) then parent.widgetids[widgetTable.id] = widgetObject end widgetTable.widget = widgetObject end local onEnterHighlight = function(self) self.highlightTexture:Show() if (self.parent:GetScript("OnEnter")) then self.parent:GetScript("OnEnter")(self.parent) end end local onLeaveHighlight = function(self) self.highlightTexture:Hide() if (self.parent:GetScript("OnLeave")) then self.parent:GetScript("OnLeave")(self.parent) end end --control the highlight color, if true, use color one, if false, use color two --color one: .2, .2, .2, 0.5 --color two: .3, .3, .3, 0.5 local bHighlightColorOne = true ---create a button and a texture to highlight the button when the mouse is over it ---the button has the dimentions of the label and the widget ---@param frame frame ---@param label fontstring ---@param widgetWidth number ---@return unknown local createOptionHighlightFrame = function(frame, label, widgetWidth) frame = frame.widget or frame label = label.widget or label local highlightFrame = CreateFrame("button", nil, frame) highlightFrame:EnableMouse(true) highlightFrame:SetFrameLevel(frame:GetFrameLevel()-1) PixelUtil.SetSize(highlightFrame, widgetWidth, frame:GetHeight() + 1) PixelUtil.SetPoint(highlightFrame, "topleft", label, "topleft", -2, 5) highlightFrame:SetScript("OnEnter", onEnterHighlight) highlightFrame:SetScript("OnLeave", onLeaveHighlight) local highlightTexture = highlightFrame:CreateTexture(nil, "overlay") highlightTexture:SetColorTexture(1, 1, 1, 0.1) PixelUtil.SetPoint(highlightTexture, "topleft", highlightFrame, "topleft", 0, 0) PixelUtil.SetPoint(highlightTexture, "bottomright", highlightFrame, "bottomright", 0, 0) highlightTexture:Hide() local backgroundTexture = highlightFrame:CreateTexture(nil, "artwork") backgroundTexture:SetColorTexture(1, 1, 1, 0.5) backgroundTexture:SetVertexColor(.25, .25, .25, 0.5) if (bHighlightColorOne) then backgroundTexture:SetVertexColor(.2, .2, .2, 0.5) else backgroundTexture:SetVertexColor(.25, .25, .25, 0.5) end bHighlightColorOne = not bHighlightColorOne PixelUtil.SetPoint(backgroundTexture, "topleft", highlightFrame, "topleft", 0, 0) PixelUtil.SetPoint(backgroundTexture, "bottomright", highlightFrame, "bottomright", 0, 0) highlightFrame.highlightTexture = highlightTexture highlightFrame.parent = frame return highlightFrame end local setLabelProperties = function(parent, widget, widgetTable, currentXOffset, currentYOffset, template) widget._get = widgetTable.get widget.widget_type = "label" widget:SetPoint(currentXOffset, currentYOffset) if (widgetTable.text_template or template) then widget:SetTemplate(widgetTable.text_template or template) else widget.fontsize = widgetTable.size or 10 end if (widgetTable.font) then widget.fontface = widgetTable.font end setWidgetId(parent, widgetTable, widget) onWidgetSetInUse(widget, widgetTable) end local setDropdownProperties = function(parent, widget, widgetTable, currentXOffset, currentYOffset, template, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth) widget._get = widgetTable.get widget.widget_type = "select" widget:Refresh() widget:Select(widgetTable.get()) widget:SetTemplate(template) if (widgetWidth) then widget:SetWidth(widgetWidth) end if (widgetHeight) then widget:SetHeight(widgetHeight) end setWidgetId(parent, widgetTable, widget) local label = widget.hasLabel.widget widget:ClearAllPoints() label:ClearAllPoints() if (bAlignAsPairs) then --regular PixelUtil.SetPoint(label, "topleft", widget:GetParent(), "topleft", currentXOffset, currentYOffset) PixelUtil.SetPoint(widget.widget, "left", label, "left", nAlignAsPairsLength, 0) if (not widget.highlightFrame) then local highlightFrame = createOptionHighlightFrame(widget, label, (widgetWidth or 140) + nAlignAsPairsLength + 5) widget.highlightFrame = highlightFrame end else widget:SetPoint("left", label, "right", 2, 0) label:SetPoint("topleft", parent, "topleft", currentXOffset, currentYOffset) end --global callback if (valueChangeHook) then widget:SetHook("OnOptionSelected", valueChangeHook) end --hook list if (widgetTable.hooks) then for hookName, hookFunc in pairs(widgetTable.hooks) do widget:SetHook(hookName, hookFunc) end end local widgetTotalSize = label:GetStringWidth() + 144 if (widgetTotalSize > maxColumnWidth) then maxColumnWidth = widgetTotalSize end if (widget:GetWidth() > maxWidgetWidth) then maxWidgetWidth = widget:GetWidth() end onWidgetSetInUse(widget, widgetTable) return maxColumnWidth, maxWidgetWidth end local highlightFrameOnClickToggle = function(highlightFrame, mouseButton) local parent = highlightFrame:GetParent() local widget = parent.MyObject local bNewState = not widget._get() widget.OnSwitch(widget, nil, bNewState) --widget.OnSwitch = widgetTable.set if (bNewState) then widget:SetValue(true) else widget:SetValue(false) end if (widget._valueChangeHook) then widget._valueChangeHook() end end local setToggleProperties = function(parent, widget, widgetTable, currentXOffset, currentYOffset, template, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, switchIsCheckbox, bUseBoxFirstOnAllWidgets, menuOptions, index, maxWidgetWidth) widget._get = widgetTable.get widget._set = widgetTable.set widget.widget_type = "toggle" widget.OnSwitch = widgetTable.set if (switchIsCheckbox) then widget:SetAsCheckBox() end if (widgetTable.children_follow_enabled) then widget.SetValueOriginal = widget.SetValue --perhaps widgetTable.set() --perhaps setscrip OnClick widget._name = widgetTable.name local newSetFunc = function(thisWidget, value) --look for children ids local childrenids = widgetTable.childrenids --print(childrenids, type(childrenids)) if (type(childrenids) == "table") then for i, childId in ipairs(childrenids) do local childWidget = parent:GetWidgetById(childId) --print("childWidget", childWidget) if (childWidget) then --if the children_follow_reverse is true, then the children will be enabled when the toogle is disabeld --this is used when the main toggle is a kind of "Do This Automatically", if is not doing it automatically --then the children should be enabled to set the options if (widgetTable.children_follow_reverse) then if (value) then childWidget:Disable() else childWidget:Enable() end else if (value) then childWidget:Enable() else childWidget:Disable() end end end end end thisWidget.SetValueOriginal(thisWidget, value) return value end widget:SetValue(widgetTable.get()) rawset(widget, "SetValue", newSetFunc) else if (widget.SetValueOriginal) then rawset(widget, "SetValue", widget.SetValueOriginal) rawset(widget, "SetValueOriginal", nil) end widget:SetValue(widgetTable.get()) end if (widgetWidth) then PixelUtil.SetWidth(widget.widget, widgetWidth) end if (widgetHeight) then PixelUtil.SetHeight(widget.widget, widgetHeight) end widget:SetTemplate(template) setWidgetId(parent, widgetTable, widget) local label = widget.hasLabel.widget widget:ClearAllPoints() label:ClearAllPoints() local extraPaddingY = 0 if (bAlignAsPairs) then if (not widget.highlightFrame) then local highlightFrame = createOptionHighlightFrame(widget, label, (widgetWidth or 140) + nAlignAsPairsLength + 5) widget.highlightFrame = highlightFrame end widget._valueChangeHook = valueChangeHook widget.highlightFrame:SetScript("OnClick", highlightFrameOnClickToggle) PixelUtil.SetPoint(label, "topleft", widget:GetParent(), "topleft", currentXOffset, currentYOffset) PixelUtil.SetPoint(widget.widget, "right", widget.highlightFrame, "right", -3, 0) else if (widgetTable.boxfirst or bUseBoxFirstOnAllWidgets) then label:SetPoint("left", widget.widget or widget, "right", 2, 0) widget:SetPoint("topleft", parent, "topleft", currentXOffset, currentYOffset) local nextWidgetTable = menuOptions[index+1] if (nextWidgetTable) then if (nextWidgetTable.type ~= "blank" and nextWidgetTable.type ~= "breakline" and nextWidgetTable.type ~= "toggle" and nextWidgetTable.type ~= "color") then extraPaddingY = 4 end end else widget:SetPoint("left", label, "right", 2, 0) label:SetPoint("topleft", parent, "topleft", currentXOffset, currentYOffset) end end --global callback if (valueChangeHook) then widget:SetHook("OnSwitch", valueChangeHook) end --hook list if (widgetTable.hooks) then for hookName, hookFunc in pairs(widgetTable.hooks) do widget:SetHook(hookName, hookFunc) end end local widgetTotalSize = label:GetStringWidth() + 32 if (widgetTotalSize > maxColumnWidth) then maxColumnWidth = widgetTotalSize end if (widget:GetWidth() > maxWidgetWidth) then maxWidgetWidth = widget:GetWidth() end onWidgetSetInUse(widget, widgetTable) return maxColumnWidth, maxWidgetWidth, extraPaddingY end local setRangeProperties = function(parent, widget, widgetTable, currentXOffset, currentYOffset, template, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth, bIsDecimals, bAttachSliderButtonsToLeft) widget._get = widgetTable.get widget.widget_type = "range" widget:SetTemplate(template) widget.bAttachButtonsToLeft = bAttachSliderButtonsToLeft local currentValue = widgetTable.get() if (bIsDecimals) then widget.slider:SetValueStep(0.01) else widget.slider:SetValueStep(widgetTable.step or 1) currentValue = math.floor(currentValue) end widget.useDecimals = bIsDecimals widget.slider:SetMinMaxValues(widgetTable.min, widgetTable.max) widget.slider:SetValue(currentValue or 0) widget.ivalue = widget.slider:GetValue() if (widgetWidth) then widget:SetWidth(widgetWidth) end if (widgetHeight) then widget:SetHeight(widgetHeight) end widget:SetHook("OnValueChange", widgetTable.set) if (valueChangeHook) then widget:SetHook("OnValueChange", valueChangeHook) end if (widgetTable.thumbscale) then widget:SetThumbSize(widget.thumb.originalWidth * widgetTable.thumbscale, nil) else widget:SetThumbSize(widget.thumb.originalWidth * 1.3, nil) end --hook list if (widgetTable.hooks) then for hookName, hookFunc in pairs(widgetTable.hooks) do widget:SetHook(hookName, hookFunc) end end setWidgetId(parent, widgetTable, widget) local label = widget.hasLabel.widget widget:ClearAllPoints() label:ClearAllPoints() if (bAlignAsPairs) then PixelUtil.SetPoint(label, "topleft", widget:GetParent(), "topleft", currentXOffset, currentYOffset) PixelUtil.SetPoint(widget.widget, "left", label, "left", nAlignAsPairsLength, 0) if (not widget.highlightFrame) then local highlightFrame = createOptionHighlightFrame(widget, label, (widgetWidth or 140) + nAlignAsPairsLength + 5) widget.highlightFrame = highlightFrame end widget.bAttachButtonsToLeft = true else widget:SetPoint("left", label, "right", 2, 0) label:SetPoint("topleft", parent, "topleft", currentXOffset, currentYOffset) end local widgetTotalSize = label:GetStringWidth() + 146 if (widgetTotalSize > maxColumnWidth) then maxColumnWidth = widgetTotalSize end if (widget:GetWidth() > maxWidgetWidth) then maxWidgetWidth = widget:GetWidth() end onWidgetSetInUse(widget, widgetTable) return maxColumnWidth, maxWidgetWidth end local setColorProperties = function(parent, widget, widgetTable, currentXOffset, currentYOffset, template, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth, bUseBoxFirstOnAllWidgets, extraPaddingY) widget._get = widgetTable.get widget.widget_type = "color" local r, g, b, a = detailsFramework:ParseColors(widgetTable.get()) widget:SetColor(r, g, b, a) widget.color_callback = widgetTable.set --callback --[=[ if (widgetWidth) then widget:SetWidth(widgetWidth) else widget:SetWidth(18) end if (widgetHeight) then widget:SetHeight(widgetHeight) else widget:SetHeight(18) end --]=] widget:SetTemplate(template) widget:SetWidth(18) widget:SetHeight(18) widget:SetHook("OnColorChanged", widgetTable.set) if (valueChangeHook) then widget:SetHook("OnColorChanged", valueChangeHook) end --hook list if (widgetTable.hooks) then for hookName, hookFunc in pairs(widgetTable.hooks) do widget:SetHook(hookName, hookFunc) end end setWidgetId(parent, widgetTable, widget) local label = widget.hasLabel.widget widget:ClearAllPoints() label:ClearAllPoints() if (bAlignAsPairs) then if (not widget.highlightFrame) then local highlightFrame = createOptionHighlightFrame(widget, label, (widgetWidth or 140) + nAlignAsPairsLength + 5) widget.highlightFrame = highlightFrame end ---- widget._valueChangeHook = valueChangeHook --widget.highlightFrame:SetScript("OnClick", highlightFrameOnClickToggle) --todo make this function for color picker color pick start PixelUtil.SetPoint(label, "topleft", widget:GetParent(), "topleft", currentXOffset, currentYOffset) PixelUtil.SetPoint(widget.widget, "right", widget.highlightFrame, "right", -3, 0) else if (widgetTable.boxfirst or bUseBoxFirstOnAllWidgets) then label:SetPoint("left", widget.widget, "right", 2, 0) widget:SetPoint(currentXOffset, currentYOffset) extraPaddingY = 1 else widget:SetPoint("left", label, "right", 2, 0) label:SetPoint("topleft", parent, "topleft", currentXOffset, currentYOffset) end end local widgetTotalSize = label:GetStringWidth() + 32 if (widgetTotalSize > maxColumnWidth) then maxColumnWidth = widgetTotalSize end if (widget:GetWidth() > maxWidgetWidth) then maxWidgetWidth = widget:GetWidth() end onWidgetSetInUse(widget, widgetTable) return maxColumnWidth, maxWidgetWidth, extraPaddingY end local setExecuteProperties = function(parent, widget, widgetTable, currentXOffset, currentYOffset, template, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth, textTemplate, latestInlineWidget) ---@cast widget df_button widget._get = widgetTable.get widget.widget_type = "execute" widget:SetTemplate(template) widget:SetWidth(widgetWidth or widgetTable.width or 120, widgetHeight or widgetTable.height or 18) widget:SetClickFunction(widgetTable.func, widgetTable.param1, widgetTable.param2) --button icon if (widgetTable.icontexture) then widget:SetIcon(widgetTable.icontexture, widget:GetHeight()-2, widget:GetHeight()-2, nil, widgetTable.icontexcoords, nil, nil, 2) end textTemplate = widgetTable.text_template or textTemplate or detailsFramework.font_templates["ORANGE_FONT_TEMPLATE"] widget.textcolor = textTemplate.color widget.textfont = textTemplate.font widget.textsize = textTemplate.size --hook list if (widgetTable.hooks) then for hookName, hookFunc in pairs(widgetTable.hooks) do widget:SetHook(hookName, hookFunc) end end setWidgetId(parent, widgetTable, widget) local label = widget.hasLabel.widget widget:ClearAllPoints() label:ClearAllPoints() if (bAlignAsPairs) then PixelUtil.SetPoint(label, "topleft", widget:GetParent(), "topleft", currentXOffset, currentYOffset) PixelUtil.SetPoint(widget.widget, "left", label, "left", nAlignAsPairsLength, 0) if (not widget.highlightFrame) then local highlightFrame = createOptionHighlightFrame(widget, label, (widgetWidth or 140) + nAlignAsPairsLength + 5) widget.highlightFrame = highlightFrame end else if (widgetTable.inline) then if (latestInlineWidget) then widget:SetPoint("left", latestInlineWidget, "right", 2, 0) latestInlineWidget = widget else widget:SetPoint(currentXOffset, currentYOffset) latestInlineWidget = widget end else widget:SetPoint(currentXOffset, currentYOffset) end end local widgetTotalSize = widget:GetWidth() + 4 if (widgetTotalSize > maxColumnWidth) then maxColumnWidth = widgetTotalSize end if (widget:GetWidth() > maxWidgetWidth) then maxWidgetWidth = widget:GetWidth() end onWidgetSetInUse(widget, widgetTable) return maxColumnWidth, maxWidgetWidth, latestInlineWidget end local setImageProperties = function(parent, widget, widgetTable, currentXOffset, currentYOffset) --.texture .width .height .filterType .texcoord if (type(widgetTable.texture) == "table") then local r, g, b, a = detailsFramework:ParseColors(widgetTable.texture) widget:SetColorTexture(r, g, b, a) else widget:SetTexture(widgetTable.texture, "CLAMP", "CLAMP", widgetTable.filterType) end widget:SetSize(widgetTable.width, widgetTable.height) local left, right, top, bottom = 0, 1, 0, 1 if (widgetTable.texcoord) then left, right, top, bottom = unpack(widgetTable.texcoord) end widget:SetTexCoord(left, right, top, bottom) if (widgetTable.vertexcolor) then local r, g, b, a = detailsFramework:ParseColors(widgetTable.vertexcolor) widget:SetVertexColor(r, g, b, a) else widget:SetVertexColor(1, 1, 1, 1) end setWidgetId(parent, widgetTable, widget) widget:ClearAllPoints() widget:SetPoint("topleft", parent, "topleft", currentXOffset, currentYOffset) end local setTextEntryProperties = function(parent, widget, widgetTable, currentXOffset, currentYOffset, template, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth, textTemplate, latestInlineWidget) widget._get = widgetTable.get widget.text = widgetTable.get() widget.widget_type = "textentry" widget:SetTemplate(widgetTable.template or widgetTable.button_template or template) widget:SetWidth(widgetWidth or widgetTable.width or 120, widgetHeight or widgetTable.height or 18) widget:SetCommitFunction(widgetTable.func or widgetTable.set) widget:SetHook("OnEnterPressed", function(...) local upFunc = widgetTable.func or widgetTable.set upFunc(...) if (valueChangeHook) then valueChangeHook() end end) widget:SetHook("OnEditFocusLost", function(...) local upFunc = widgetTable.func or widgetTable.set upFunc(...) if (valueChangeHook) then valueChangeHook() end end) textTemplate = widgetTable.text_template or textTemplate or detailsFramework.font_templates["ORANGE_FONT_TEMPLATE"] widget.textcolor = textTemplate.color widget.textfont = textTemplate.font widget.textsize = textTemplate.size --hook list if (widgetTable.hooks) then for hookName, hookFunc in pairs(widgetTable.hooks) do widget:SetHook(hookName, hookFunc) end end setWidgetId(parent, widgetTable, widget) local label = widget.hasLabel.widget widget:ClearAllPoints() label:ClearAllPoints() if (bAlignAsPairs) then PixelUtil.SetPoint(label, "topleft", widget:GetParent(), "topleft", currentXOffset, currentYOffset) PixelUtil.SetPoint(widget.widget, "left", label, "left", nAlignAsPairsLength, 0) if (not widget.highlightFrame) then local highlightFrame = createOptionHighlightFrame(widget, label, (widgetWidth or 140) + nAlignAsPairsLength + 5) widget.highlightFrame = highlightFrame end else widget:SetPoint("left", label, "right", 2, 0) label:SetPoint("topleft", parent, "topleft", currentXOffset, currentYOffset) end local widgetTotalSize = label:GetStringWidth() + 64 --need review, might not be correct if (widgetTotalSize > maxColumnWidth) then maxColumnWidth = widgetTotalSize end if (widget:GetWidth() > maxWidgetWidth) then maxWidgetWidth = widget:GetWidth() end onWidgetSetInUse(widget, widgetTable) return maxColumnWidth, maxWidgetWidth end local onMenuBuilt = function(parent) --refresh the options to find children to disable or enable if (parent.build_menu_options) then for index, widgetTable in ipairs(parent.build_menu_options) do if (widgetTable.children_follow_enabled) then --not found, bug local widget = widgetTable.widget local childrenids = widgetTable.childrenids if (type(childrenids) == "table") then for i, childId in ipairs(childrenids) do local childWidget = parent:GetWidgetById(childId) if (childWidget) then local value = widget:GetValue() if (widgetTable.children_follow_reverse) then if (value) then childWidget:Disable() else childWidget:Enable() end else if (value) then childWidget:Enable() else childWidget:Disable() end end end end end end end end end local refreshOptions = function(self) for _, widget in ipairs(self.widget_list) do if (widget._get) then if (widget.widget_type == "label") then if (widget._get() and not widget.languageAddonId) then widget:SetText(widget._get()) end elseif (widget.widget_type == "select") then widget:Select(widget._get()) elseif (widget.widget_type == "toggle" or widget.widget_type == "range") then widget:SetValue(widget._get()) elseif (widget.widget_type == "textentry") then widget:SetText(widget._get()) elseif (widget.widget_type == "color") then local default_value, g, b, a = widget._get() if (type(default_value) == "table") then widget:SetColor (unpack(default_value)) else widget:SetColor (default_value, g, b, a) end end end end onMenuBuilt(self) end detailsFramework.internalFunctions.RefreshOptionsPanel = refreshOptions local parseOptionsTypes = function(menuOptions) --normalize format types for index, widgetTable in ipairs(menuOptions) do if (widgetTable.type == "space") then widgetTable.type = "blank" elseif (widgetTable.type == "fontdropdown") then widgetTable.type = "selectfont" elseif (widgetTable.type == "colordropdown") then widgetTable.type = "selectcolor" elseif (widgetTable.type == "outlinedropdown") then widgetTable.type = "selectoutline" elseif (widgetTable.type == "anchordropdown") then widgetTable.type = "selectanchor" elseif (widgetTable.type == "audiodropdown") then widgetTable.type = "selectaudio" elseif (widgetTable.type == "dropdown") then widgetTable.type = "select" elseif (widgetTable.type == "switch") then widgetTable.type = "toggle" elseif (widgetTable.type == "slider") then widgetTable.type = "range" elseif (widgetTable.type == "button") then widgetTable.type = "execute" end end end local parseOptionsTable = function(menuOptions) local bUseBoxFirstOnAllWidgets = menuOptions.always_boxfirst local widgetWidth = menuOptions.widget_width --a width to be used on all widgets local widgetHeight = menuOptions.widget_height --a height to be used on all widgets local bAlignAsPairs = menuOptions.align_as_pairs local nAlignAsPairsLength = menuOptions.align_as_pairs_string_space or 160 local nAlignAsPairsSpacing = menuOptions.align_as_pairs_spacing or 20 local bAttachSliderButtonsToLeft = menuOptions.slider_buttons_to_left --if a scrollbox is passed, the height can be ignored --the scrollBox child will be used as the parent, and the height of the child will be resized to fit the widgets local bUseScrollFrame = menuOptions.use_scrollframe local languageAddonId = menuOptions.language_addonId return bUseBoxFirstOnAllWidgets, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, nAlignAsPairsSpacing, bUseScrollFrame, languageAddonId, bAttachSliderButtonsToLeft end local parseParent = function(bUseScrollFrame, parent, height, yOffset) if (bUseScrollFrame) then local width, height = parent:GetSize() parent = parent:GetScrollChild() parent:SetSize(width, height) else if (height and type(height) == "number") then height = math.abs((height or parent:GetHeight()) - math.abs(yOffset) + 20) height = height * -1 else height = parent:GetHeight() end end return parent, height end local parseLanguageTable = function(languageAddonId) local languageTable if (languageAddonId) then languageTable = DetailsFramework.Language.GetLanguageTable(languageAddonId) end return languageTable end local getFrameById = function(self, id) return self.widgetids[id] end function detailsFramework:ClearOptionsPanel(frame) for i = 1, #frame.widget_list do frame.widget_list[i]:Hide() if (frame.widget_list[i].hasLabel) then frame.widget_list[i].hasLabel:SetText("") end end table.wipe(frame.widgetids) end function detailsFramework:SetAsOptionsPanel(frame) --print("refresh_options", refresh_options) frame.RefreshOptions = refreshOptions frame.widget_list = {} frame.widget_list_by_type = { ["dropdown"] = {}, -- "select" ["switch"] = {}, -- "toggle" ["slider"] = {}, -- "range" ["color"] = {}, -- ["button"] = {}, -- "execute" ["textentry"] = {}, -- ["label"] = {}, --"text" ["image"] = {}, } frame.widgetids = {} frame.GetWidgetById = getFrameById end local formatOptionNameWithColon = function(text, useColon) if (text) then if (useColon) then text = text .. ":" return text else return text end end end local widgetsToDisableOnCombat = {} local getMenuWidgetVolative = function(parent, widgetType, indexTable) local widgetObject if (widgetType == "label") then widgetObject = parent.widget_list_by_type[widgetType][indexTable[widgetType]] if (not widgetObject) then widgetObject = detailsFramework:CreateLabel(parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType], "overlay") table.insert(parent.widget_list, widgetObject) table.insert(parent.widget_list_by_type[widgetType], widgetObject) end indexTable[widgetType] = indexTable[widgetType] + 1 elseif (widgetType == "dropdown") then widgetObject = parent.widget_list_by_type[widgetType][indexTable[widgetType]] if (not widgetObject) then widgetObject = detailsFramework:CreateDropDown(parent, function() return {} end, nil, 120, 18, nil, "$parentWidget" .. widgetType .. indexTable[widgetType]) widgetObject.hasLabel = detailsFramework:CreateLabel(parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType] .. "label", "overlay") table.insert(parent.widget_list, widgetObject) table.insert(parent.widget_list_by_type[widgetType], widgetObject) else widgetObject:ClearHooks() widgetObject.hasLabel.text = "" end indexTable[widgetType] = indexTable[widgetType] + 1 elseif (widgetType == "switch") then widgetObject = parent.widget_list_by_type[widgetType][indexTable[widgetType]] if (not widgetObject) then widgetObject = detailsFramework:CreateSwitch(parent, nil, true, 20, 20, nil, nil, nil, "$parentWidget" .. widgetType .. indexTable[widgetType]) widgetObject.hasLabel = detailsFramework:CreateLabel(parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType] .. "label", "overlay") table.insert(parent.widget_list, widgetObject) table.insert(parent.widget_list_by_type[widgetType], widgetObject) else widgetObject:ClearHooks() end indexTable[widgetType] = indexTable[widgetType] + 1 elseif (widgetType == "slider") then widgetObject = parent.widget_list_by_type[widgetType][indexTable[widgetType]] if (not widgetObject) then widgetObject = detailsFramework:CreateSlider(parent, 120, 20, 1, 2, 1, 1, false, nil, "$parentWidget" .. widgetType .. indexTable[widgetType]) widgetObject.hasLabel = detailsFramework:CreateLabel(parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType] .. "label", "overlay") table.insert(parent.widget_list, widgetObject) table.insert(parent.widget_list_by_type[widgetType], widgetObject) else widgetObject:ClearHooks() end indexTable[widgetType] = indexTable[widgetType] + 1 elseif (widgetType == "color") then widgetObject = parent.widget_list_by_type[widgetType][indexTable[widgetType]] if (not widgetObject) then widgetObject = detailsFramework:CreateColorPickButton(parent, "$parentWidget" .. widgetType .. indexTable[widgetType], nil, function()end, 1) widgetObject.hasLabel = detailsFramework:CreateLabel(parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType] .. "label", "overlay") table.insert(parent.widget_list, widgetObject) table.insert(parent.widget_list_by_type[widgetType], widgetObject) else widgetObject:ClearHooks() end indexTable[widgetType] = indexTable[widgetType] + 1 elseif (widgetType == "button") then widgetObject = parent.widget_list_by_type[widgetType][indexTable[widgetType]] if (not widgetObject) then widgetObject = detailsFramework:CreateButton(parent, function()end, 120, 18, "", nil, nil, nil, nil, "$parentWidget" .. widgetType .. indexTable[widgetType]) widgetObject.hasLabel = detailsFramework:CreateLabel(parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType] .. "label", "overlay") table.insert(parent.widget_list, widgetObject) table.insert(parent.widget_list_by_type[widgetType], widgetObject) else widgetObject:ClearHooks() end indexTable[widgetType] = indexTable[widgetType] + 1 elseif (widgetType == "textentry") then widgetObject = parent.widget_list_by_type[widgetType][indexTable[widgetType]] if (not widgetObject) then widgetObject = detailsFramework:CreateTextEntry(parent, function()end, 120, 18, nil, "$parentWidget" .. widgetType .. indexTable[widgetType]) widgetObject.hasLabel = detailsFramework:CreateLabel(parent, "", 10, "white", "", nil, "$parentWidget" .. widgetType .. indexTable[widgetType] .. "label", "overlay") table.insert(parent.widget_list, widgetObject) table.insert(parent.widget_list_by_type[widgetType], widgetObject) else widgetObject:ClearHooks() end indexTable[widgetType] = indexTable[widgetType] + 1 elseif (widgetType == "image") then widgetObject = parent.widget_list_by_type[widgetType][indexTable[widgetType]] if (not widgetObject) then widgetObject = parent:CreateTexture("$parentWidget" .. widgetType .. indexTable[widgetType], "overlay") table.insert(parent.widget_list, widgetObject) table.insert(parent.widget_list_by_type[widgetType], widgetObject) end indexTable[widgetType] = indexTable[widgetType] + 1 end --if the widget is inside the no combat table, remove it for i = 1, #widgetsToDisableOnCombat do if (widgetsToDisableOnCombat[i] == widgetObject) then table.remove(widgetsToDisableOnCombat, i) break end end --clean children ids, children ids are used to disable or enable other widgets when a widget is disabled or enabled if (widgetObject.childrenids) then table.wipe(widgetObject.childrenids) end widgetObject.children_follow_enabled = nil return widgetObject end --get the description phrase from the language table or use the .desc or .deschraseid local getDescPhraseText = function(languageTable, widgetTable) local descPhraseId = languageTable and (languageTable[widgetTable.descPhraseId] or languageTable[widgetTable.desc]) return descPhraseId or widgetTable.descPhraseId or widgetTable.desc or widgetTable.name or "-?-" end local getNamePhraseID = function(widgetTable, languageAddonId, languageTable, bIgnoreEmbed) if (widgetTable.namePhraseId) then return widgetTable.namePhraseId end if (not languageTable) then return end local keyName = widgetTable.name if (widgetTable.type == "label" and widgetTable.get) then local key = widgetTable.get() if (key and type(key) == "string") then keyName = key end end --embed key is when the phraseId is inside a string surounded by @ local embedPhraseId = keyName:match("@(.-)@") local hasValue = detailsFramework.Language.DoesPhraseIDExistsInDefaultLanguage(languageAddonId, embedPhraseId or keyName) if (not hasValue) then return end if (embedPhraseId and not bIgnoreEmbed) then return embedPhraseId, true else return keyName end end local getNamePhraseText = function(languageTable, widgetTable, useColon, languageAddonId) local namePhraseId, bWasEmbed = getNamePhraseID(widgetTable, languageAddonId, languageTable) local namePhrase = languageTable and (languageTable[namePhraseId] or languageTable[widgetTable.namePhraseId] or languageTable[widgetTable.name]) if (bWasEmbed and widgetTable.name) then namePhrase = widgetTable.name:gsub("@" .. namePhraseId .. "@", namePhrase) end return namePhrase or formatOptionNameWithColon(widgetTable.name, useColon) or widgetTable.namePhraseId or widgetTable.name or "-?-" end --volatile menu can be called several times, each time all settings are reset and a new menu is built reusing the widgets function detailsFramework:BuildMenuVolatile(parent, menuOptions, xOffset, yOffset, height, useColon, textTemplate, dropdownTemplate, switchTemplate, switchIsCheckbox, sliderTemplate, buttonTemplate, valueChangeHook) if (not parent.widget_list) then detailsFramework:SetAsOptionsPanel(parent) end detailsFramework:ClearOptionsPanel(parent) bHighlightColorOne = true local amountLineWidgetAdded = 0 local biggestColumnHeight = 0 --used to resize the scrollbox child when a scrollbox is passed local latestInlineWidget local currentXOffset = xOffset or 0 local currentYOffset = yOffset or 0 local maxColumnWidth = 0 --biggest width of widget + text size on the current column loop pass local maxWidgetWidth = 0 --biggest widget width on the current column loop pass local canvasFrame = parent --which is the next widget to get from the pool local widgetIndexes = { label = 1, dropdown = 1, switch = 1, slider = 1, color = 1, button = 1, textentry = 1, } parseOptionsTypes(menuOptions) local bUseBoxFirstOnAllWidgets, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, nAlignAsPairsSpacing, bUseScrollFrame, languageAddonId, bAttachSliderButtonsToLeft = parseOptionsTable(menuOptions) parent, height = parseParent(bUseScrollFrame, parent, height, yOffset) local languageTable = parseLanguageTable(languageAddonId) parent.build_menu_options = menuOptions for index, widgetTable in ipairs(menuOptions) do if (not widgetTable.hidden) then local widgetCreated if (latestInlineWidget) then if (not widgetTable.inline) then latestInlineWidget = nil currentYOffset = currentYOffset - 20 end end local extraPaddingY = 0 if (not widgetTable.novolatile) then --step a line if (widgetTable.type == "blank" or widgetTable.type == "space") then --do nothing elseif (widgetTable.type == "label" or widgetTable.type == "text") then local label = getMenuWidgetVolative(parent, "label", widgetIndexes) label:ClearAllPoints() widgetCreated = label setLabelProperties(parent, label, widgetTable, currentXOffset, currentYOffset, textTemplate) local namePhraseId = getNamePhraseID(widgetTable, languageAddonId, languageTable) local namePhrase = (languageTable and (languageTable[namePhraseId] or languageTable[widgetTable.namePhraseId] or languageTable[widgetTable.name])) or (widgetTable.get and widgetTable.get()) or widgetTable.text or (widgetTable.namePhraseId) or "" label.text = namePhrase label.color = widgetTable.color amountLineWidgetAdded = amountLineWidgetAdded + 1 --dropdowns elseif (widgetTable.type:find("select")) then assert(widgetTable.get, "DetailsFramework:BuildMenu: .get() not found in the widget table for 'select'") local dropdown = getMenuWidgetVolative(parent, "dropdown", widgetIndexes) widgetCreated = dropdown local defaultHeight = 18 do if (widgetTable.type == "selectfont") then local func = detailsFramework:CreateFontListGenerator(widgetTable.set, widgetTable.include_default) dropdown:SetFunction(func) elseif (widgetTable.type == "selectcolor") then local func = detailsFramework:CreateColorListGenerator(widgetTable.set) dropdown:SetFunction(func) elseif (widgetTable.type == "selectanchor") then local func = detailsFramework:CreateAnchorPointListGenerator(widgetTable.set) dropdown:SetFunction(func) elseif (widgetTable.type == "selectoutline") then local func = detailsFramework:CreateOutlineListGenerator(widgetTable.set) dropdown:SetFunction(func) elseif (widgetTable.type == "selectaudio") then local func = detailsFramework:CreateAudioListGenerator(widgetTable.set) dropdown:SetFunction(func) else dropdown:SetFunction(widgetTable.values) end end local descPhrase = getDescPhraseText(languageTable, widgetTable) dropdown:SetTooltip(descPhrase) local namePhrase = getNamePhraseText(languageTable, widgetTable, useColon, languageAddonId) dropdown.hasLabel.text = namePhrase dropdown.hasLabel:SetTemplate(widgetTable.text_template or textTemplate) maxColumnWidth, maxWidgetWidth = setDropdownProperties(parent, dropdown, widgetTable, currentXOffset, currentYOffset, textTemplate, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth) amountLineWidgetAdded = amountLineWidgetAdded + 1 --switchs elseif (widgetTable.type == "toggle" or widgetTable.type == "switch") then local switch = getMenuWidgetVolative(parent, "switch", widgetIndexes) widgetCreated = switch local descPhrase = getDescPhraseText(languageTable, widgetTable) switch:SetTooltip(descPhrase) local namePhrase = getNamePhraseText(languageTable, widgetTable, useColon, languageAddonId) switch.hasLabel.text = namePhrase switch.hasLabel:SetTemplate(widgetTable.text_template or textTemplate) maxColumnWidth, maxWidgetWidth, extraPaddingY = setToggleProperties(parent, switch, widgetTable, currentXOffset, currentYOffset, switchTemplate, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, true, bUseBoxFirstOnAllWidgets, menuOptions, index, maxWidgetWidth) amountLineWidgetAdded = amountLineWidgetAdded + 1 --slider elseif (widgetTable.type == "range") then local slider = getMenuWidgetVolative(parent, "slider", widgetIndexes) widgetCreated = slider local descPhrase = getDescPhraseText(languageTable, widgetTable) slider:SetTooltip(descPhrase) local namePhrase = getNamePhraseText(languageTable, widgetTable, useColon, languageAddonId) slider.hasLabel.text = namePhrase slider.hasLabel:SetTemplate(widgetTable.text_template or textTemplate) maxColumnWidth, maxWidgetWidth = setRangeProperties(parent, slider, widgetTable, currentXOffset, currentYOffset, sliderTemplate, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth, widgetTable.usedecimals, bAttachSliderButtonsToLeft) amountLineWidgetAdded = amountLineWidgetAdded + 1 --color elseif (widgetTable.type == "color") then local colorpick = getMenuWidgetVolative(parent, "color", widgetIndexes) widgetCreated = colorpick local descPhrase = getDescPhraseText(languageTable, widgetTable) colorpick:SetTooltip(descPhrase) local label = colorpick.hasLabel local namePhrase = getNamePhraseText(languageTable, widgetTable, useColon, languageAddonId) label.text = namePhrase label:SetTemplate(widgetTable.text_template or textTemplate) maxColumnWidth, maxWidgetWidth, extraPaddingY = setColorProperties(parent, colorpick, widgetTable, currentXOffset, currentYOffset, switchTemplate, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth, bUseBoxFirstOnAllWidgets, extraPaddingY) amountLineWidgetAdded = amountLineWidgetAdded + 1 --button elseif (widgetTable.type == "execute" or widgetTable.type == "button") then local button = getMenuWidgetVolative(parent, "button", widgetIndexes) button.widget_type = "execute" widgetCreated = button maxColumnWidth, maxWidgetWidth, latestInlineWidget = setExecuteProperties(parent, button, widgetTable, currentXOffset, currentYOffset, buttonTemplate, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth, textTemplate, latestInlineWidget) local namePhrase = getNamePhraseText(languageTable, widgetTable, useColon, languageAddonId) button.text = namePhrase local descPhrase = getDescPhraseText(languageTable, widgetTable) button:SetTooltip(descPhrase) amountLineWidgetAdded = amountLineWidgetAdded + 1 --textentry elseif (widgetTable.type == "textentry") then local textentry = getMenuWidgetVolative(parent, "textentry", widgetIndexes) widgetCreated = textentry local descPhrase = getDescPhraseText(languageTable, widgetTable) textentry:SetTooltip(descPhrase) local namePhrase = getNamePhraseText(languageTable, widgetTable, useColon, languageAddonId) textentry.hasLabel.text = namePhrase textentry.hasLabel:SetTemplate(widgetTable.text_template or textTemplate) maxColumnWidth, maxWidgetWidth = setTextEntryProperties(parent, textentry, widgetTable, currentXOffset, currentYOffset, buttonTemplate, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth, textTemplate) amountLineWidgetAdded = amountLineWidgetAdded + 1 --image elseif (widgetTable.type == "image") then local image = getMenuWidgetVolative(parent, "image", widgetIndexes) widgetCreated = image setImageProperties(parent, image, widgetTable, currentXOffset, currentYOffset) amountLineWidgetAdded = amountLineWidgetAdded + 1 end --end loop if (widgetTable.nocombat) then table.insert(widgetsToDisableOnCombat, widgetCreated) end if (not widgetTable.inline) then if (widgetTable.spacement) then currentYOffset = currentYOffset - 30 else currentYOffset = currentYOffset - 20 end end if (extraPaddingY > 0) then currentYOffset = currentYOffset - extraPaddingY end if (bUseScrollFrame) then if (widgetTable.type == "breakline") then biggestColumnHeight = math.min(currentYOffset, biggestColumnHeight) currentYOffset = yOffset if (bAlignAsPairs) then currentXOffset = currentXOffset + nAlignAsPairsLength + (widgetWidth or maxWidgetWidth) + nAlignAsPairsSpacing else currentXOffset = currentXOffset + maxColumnWidth + 20 end amountLineWidgetAdded = 0 maxColumnWidth = 0 maxWidgetWidth = 0 end else if (widgetTable.type == "breakline" or currentYOffset < height) then currentYOffset = yOffset currentXOffset = currentXOffset + maxColumnWidth + 20 amountLineWidgetAdded = 0 maxColumnWidth = 0 end end if widgetCreated then widgetCreated:Show() end end end end if (bUseScrollFrame) then canvasFrame:GetParent().RefreshOptions = function() parent:RefreshOptions() end end detailsFramework.RefreshUnsafeOptionsWidgets() onMenuBuilt(parent) end local getDescripttionPhraseID = function(widgetTable, languageAddonId, languageTable) if (widgetTable.descPhraseId) then return widgetTable.descPhraseId end if (not languageTable) then return end local hasValue = detailsFramework.Language.DoesPhraseIDExistsInDefaultLanguage(languageAddonId, widgetTable.desc) if (not hasValue) then return end return widgetTable.desc end ---classes used by the menu builder on the menuOptions table on both functions BuildMenu and BuildMenuVolatile ---the menuOptions consists of a table with several tables inside in array, each table is a widget to be created ---class df_menu_label is used when the sub table of menuOptions has a key named "type" with the value "label" or "text" --[=[ function detailsFramework:BuildMenu(parent, menuOptions, xOffset, yOffset, height, useColon, textTemplate, dropdownTemplate, switchTemplate, switchIsCheckbox, sliderTemplate, buttonTemplate, valueChangeHook) local tNow = debugprofilestop() detailsFramework:BuildMenu22(parent, menuOptions, xOffset, yOffset, height, useColon, textTemplate, dropdownTemplate, switchTemplate, switchIsCheckbox, sliderTemplate, buttonTemplate, valueChangeHook) local tEnd = debugprofilestop() print("BuildMenu for", (menuOptions.Name or "--"), floor(tEnd - tNow), "ms") end --]=] function detailsFramework:BuildMenu(parent, menuOptions, xOffset, yOffset, height, useColon, textTemplate, dropdownTemplate, switchTemplate, switchIsCheckbox, sliderTemplate, buttonTemplate, valueChangeHook) --how many widgets has been created on this line loop pass local amountLineWidgetAdded = 0 local biggestColumnHeight = 0 --used to resize the scrollbox child when a scrollbox is passed local latestInlineWidget local currentXOffset = xOffset or 0 local currentYOffset = yOffset or 0 local maxColumnWidth = 0 --biggest width of widget + text size on the current column loop pass local maxWidgetWidth = 0 --biggest widget width on the current column loop pass local canvasFrame = parent bHighlightColorOne = true --parse settings and the options table parseOptionsTypes(menuOptions) local bUseBoxFirstOnAllWidgets, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, nAlignAsPairsSpacing, bUseScrollFrame, languageAddonId, bAttachSliderButtonsToLeft = parseOptionsTable(menuOptions) parent, height = parseParent(bUseScrollFrame, parent, height, yOffset) local languageTable = parseLanguageTable(languageAddonId) parent.build_menu_options = menuOptions if (not parent.widget_list) then detailsFramework:SetAsOptionsPanel(parent) end for index, widgetTable in ipairs(menuOptions) do if (not widgetTable.hidden) then local widgetCreated if (latestInlineWidget) then if (not widgetTable.inline) then latestInlineWidget = nil currentYOffset = currentYOffset - 28 end end local extraPaddingY = 0 if (widgetTable.type == "blank") then --do nothing elseif (widgetTable.type == "label" or widgetTable.type == "text") then ---@cast widgetTable df_menu_label local label = detailsFramework:CreateLabel(parent, "", widgetTable.text_template or textTemplate or widgetTable.size, widgetTable.color, widgetTable.font, nil, "$parentWidget" .. index, "overlay") setLabelProperties(parent, label, widgetTable, currentXOffset, currentYOffset) local namePhraseId = getNamePhraseID(widgetTable, languageAddonId, languageTable) if (namePhraseId) then DetailsFramework.Language.RegisterObject(languageAddonId, label.widget, namePhraseId) label.languageAddonId = languageAddonId else local textToSet = (widgetTable.get and widgetTable.get()) or widgetTable.text or "" label:SetText(textToSet) end --store the widget created into the overall table and the widget by type table.insert(parent.widget_list, label) table.insert(parent.widget_list_by_type.label, label) amountLineWidgetAdded = amountLineWidgetAdded + 1 elseif (widgetTable.type:find("select")) then ---@cast widgetTable df_menu_dropdown assert(widgetTable.get, "DetailsFramework:BuildMenu: .get not found in the widget table for 'select'") local defaultHeight = 18 local dropdown do if (widgetTable.type == "selectfont") then dropdown = detailsFramework:CreateFontDropDown(parent, widgetTable.set, widgetTable.get(), widgetWidth or 140, widgetHeight or defaultHeight, nil, "$parentWidget" .. index, dropdownTemplate, widgetTable.include_default) elseif (widgetTable.type == "selectcolor") then dropdown = detailsFramework:CreateColorDropDown(parent, widgetTable.set, widgetTable.get(), widgetWidth or 140, widgetHeight or defaultHeight, nil, "$parentWidget" .. index, dropdownTemplate) elseif (widgetTable.type == "selectanchor") then dropdown = detailsFramework:CreateAnchorPointDropDown(parent, widgetTable.set, widgetTable.get(), widgetWidth or 140, widgetHeight or defaultHeight, nil, "$parentWidget" .. index, dropdownTemplate) elseif (widgetTable.type == "selectoutline") then dropdown = detailsFramework:CreateOutlineDropDown(parent, widgetTable.set, widgetTable.get(), widgetWidth or 140, widgetHeight or defaultHeight, nil, "$parentWidget" .. index, dropdownTemplate) elseif (widgetTable.type == "selectaudio") then dropdown = detailsFramework:CreateAudioDropDown(parent, widgetTable.set, widgetTable.get(), widgetWidth or 140, widgetHeight or defaultHeight, nil, "$parentWidget" .. index, dropdownTemplate) else dropdown = detailsFramework:NewDropDown(parent, nil, "$parentWidget" .. index, nil, widgetWidth or 140, widgetHeight or defaultHeight, widgetTable.values, widgetTable.get(), dropdownTemplate) end end local descPhraseId = getDescripttionPhraseID(widgetTable, languageAddonId, languageTable) DetailsFramework.Language.RegisterTableKeyWithDefault(languageAddonId, dropdown, "have_tooltip", descPhraseId, widgetTable.desc) local label = detailsFramework:NewLabel(parent, nil, "$parentLabel" .. index, nil, "", "GameFontNormal", widgetTable.text_template or textTemplate or 12) dropdown.hasLabel = label local namePhraseId = getNamePhraseID(widgetTable, languageAddonId, languageTable, true) DetailsFramework.Language.RegisterObjectWithDefault(languageAddonId, label.widget, namePhraseId, formatOptionNameWithColon(widgetTable.name, useColon)) dropdown.addonId = languageAddonId if (languageAddonId) then detailsFramework.Language.RegisterCallback(languageAddonId, function(addonId, languageId, ...) dropdown:Select(dropdown:GetValue()) end) C_Timer.After(0.1, function() dropdown:Select(dropdown:GetValue()) end) end maxColumnWidth, maxWidgetWidth = setDropdownProperties(parent, dropdown, widgetTable, currentXOffset, currentYOffset, textTemplate, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth) --store the widget created into the overall table and the widget by type table.insert(parent.widget_list, dropdown) table.insert(parent.widget_list_by_type.dropdown, dropdown) widgetCreated = dropdown amountLineWidgetAdded = amountLineWidgetAdded + 1 elseif (widgetTable.type == "toggle") then ---@cast widgetTable df_menu_toggle local switch = detailsFramework:NewSwitch(parent, nil, "$parentWidget" .. index, nil, 60, 20, nil, nil, widgetTable.get(), nil, nil, nil, nil, switchTemplate) local descPhraseId = getDescripttionPhraseID(widgetTable, languageAddonId, languageTable) DetailsFramework.Language.RegisterTableKeyWithDefault(languageAddonId, switch, "have_tooltip", descPhraseId, widgetTable.desc) local label = detailsFramework:NewLabel(parent, nil, "$parentLabel" .. index, nil, "", "GameFontNormal", widgetTable.text_template or textTemplate or 12) switch.hasLabel = label local namePhraseId = getNamePhraseID(widgetTable, languageAddonId, languageTable, true) DetailsFramework.Language.RegisterObjectWithDefault(languageAddonId, label.widget, namePhraseId, formatOptionNameWithColon(widgetTable.name, useColon)) maxColumnWidth, maxWidgetWidth, extraPaddingY = setToggleProperties(parent, switch, widgetTable, currentXOffset, currentYOffset, switchTemplate, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, switchIsCheckbox, bUseBoxFirstOnAllWidgets, menuOptions, index, maxWidgetWidth) --store the widget created into the overall table and the widget by type table.insert(parent.widget_list, switch) table.insert(parent.widget_list_by_type.switch, switch) widgetCreated = switch amountLineWidgetAdded = amountLineWidgetAdded + 1 elseif (widgetTable.type == "range") then ---@cast widgetTable df_menu_range assert(widgetTable.get, "DetailsFramework:BuildMenu: .get not found in the widget table for 'range'") local bIsDecimals = widgetTable.usedecimals local slider = detailsFramework:NewSlider(parent, nil, "$parentWidget" .. index, nil, widgetWidth or 140, widgetHeight or 18, widgetTable.min, widgetTable.max, widgetTable.step, widgetTable.get(), bIsDecimals, nil, nil, sliderTemplate) local descPhraseId = getDescripttionPhraseID(widgetTable, languageAddonId, languageTable) DetailsFramework.Language.RegisterTableKeyWithDefault(languageAddonId, slider, "have_tooltip", descPhraseId, widgetTable.desc) local label = detailsFramework:NewLabel(parent, nil, "$parentLabel" .. index, nil, "", "GameFontNormal", widgetTable.text_template or textTemplate or 12) slider.hasLabel = label local namePhraseId = getNamePhraseID(widgetTable, languageAddonId, languageTable, true) DetailsFramework.Language.RegisterObjectWithDefault(languageAddonId, label.widget, namePhraseId, formatOptionNameWithColon(widgetTable.name, useColon)) maxColumnWidth, maxWidgetWidth = setRangeProperties(parent, slider, widgetTable, currentXOffset, currentYOffset, sliderTemplate, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth, bIsDecimals, bAttachSliderButtonsToLeft) --store the widget created into the overall table and the widget by type table.insert(parent.widget_list, slider) table.insert(parent.widget_list_by_type.slider, slider) widgetCreated = slider amountLineWidgetAdded = amountLineWidgetAdded + 1 elseif (widgetTable.type == "color") then ---@cast widgetTable df_menu_color assert(widgetTable.get, "DetailsFramework:BuildMenu: .get not found in the widget table for 'color'") local colorpick = detailsFramework:NewColorPickButton(parent, "$parentWidget" .. index, nil, widgetTable.set, nil, buttonTemplate) local descPhraseId = getDescripttionPhraseID(widgetTable, languageAddonId, languageTable) DetailsFramework.Language.RegisterTableKeyWithDefault(languageAddonId, colorpick, "have_tooltip", descPhraseId, widgetTable.desc) local label = detailsFramework:NewLabel(parent, nil, "$parentLabel" .. index, nil, "", "GameFontNormal", widgetTable.text_template or textTemplate or 12) colorpick.hasLabel = label local namePhraseId = getNamePhraseID(widgetTable, languageAddonId, languageTable, true) DetailsFramework.Language.RegisterObjectWithDefault(languageAddonId, label.widget, namePhraseId, formatOptionNameWithColon(widgetTable.name, useColon)) maxColumnWidth, maxWidgetWidth, extraPaddingY = setColorProperties(parent, colorpick, widgetTable, currentXOffset, currentYOffset, buttonTemplate, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth, bUseBoxFirstOnAllWidgets, extraPaddingY) --store the widget created into the overall table and the widget by type table.insert(parent.widget_list, colorpick) table.insert(parent.widget_list_by_type.color, colorpick) widgetCreated = colorpick amountLineWidgetAdded = amountLineWidgetAdded + 1 elseif (widgetTable.type == "execute") then ---@cast widgetTable df_menu_button local button = detailsFramework:NewButton(parent, nil, "$parentWidget" .. index, nil, widgetWidth or 120, widgetHeight or 18, widgetTable.func, widgetTable.param1, widgetTable.param2, nil, "", nil, buttonTemplate, textTemplate) button.widget_type = "execute" local label = detailsFramework:NewLabel(parent, nil, "$parentLabel" .. index, nil, "", "GameFontNormal", widgetTable.text_template or textTemplate or 12) button.hasLabel = label local namePhraseId = getNamePhraseID(widgetTable, languageAddonId, languageTable, true) DetailsFramework.Language.RegisterObjectWithDefault(languageAddonId, button.widget, namePhraseId, widgetTable.name) local descPhraseId = getDescripttionPhraseID(widgetTable, languageAddonId, languageTable) DetailsFramework.Language.RegisterTableKeyWithDefault(languageAddonId, button, "have_tooltip", descPhraseId, widgetTable.desc) maxColumnWidth, maxWidgetWidth, latestInlineWidget = setExecuteProperties(parent, button, widgetTable, currentXOffset, currentYOffset, buttonTemplate, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth, textTemplate, latestInlineWidget) --store the widget created into the overall table and the widget by type table.insert(parent.widget_list, button) table.insert(parent.widget_list_by_type.button, button) widgetCreated = button amountLineWidgetAdded = amountLineWidgetAdded + 1 elseif (widgetTable.type == "textentry") then ---@cast widgetTable df_menu_textentry local textentry = detailsFramework:CreateTextEntry(parent, widgetTable.func or widgetTable.set, widgetWidth or 120, widgetHeight or 18, nil, "$parentWidget" .. index, nil, buttonTemplate) local label = detailsFramework:NewLabel(parent, nil, "$parentLabel" .. index, nil, "", "GameFontNormal", widgetTable.text_template or textTemplate or 12) textentry.hasLabel = label textentry.align = widgetTable.align or "left" local descPhraseId = getDescripttionPhraseID(widgetTable, languageAddonId, languageTable) DetailsFramework.Language.RegisterTableKeyWithDefault(languageAddonId, textentry, "have_tooltip", descPhraseId, widgetTable.desc) local namePhraseId = getNamePhraseID(widgetTable, languageAddonId, languageTable, true) DetailsFramework.Language.RegisterObjectWithDefault(languageAddonId, label.widget, namePhraseId, formatOptionNameWithColon(widgetTable.name, useColon)) maxColumnWidth, maxWidgetWidth = setTextEntryProperties(parent, textentry, widgetTable, currentXOffset, currentYOffset, buttonTemplate, widgetWidth, widgetHeight, bAlignAsPairs, nAlignAsPairsLength, valueChangeHook, maxColumnWidth, maxWidgetWidth, textTemplate) --store the widget created into the overall table and the widget by type table.insert(parent.widget_list, textentry) table.insert(parent.widget_list_by_type.textentry, textentry) widgetCreated = textentry amountLineWidgetAdded = amountLineWidgetAdded + 1 elseif (widgetTable.type == "image") then local image = parent:CreateTexture("$parentMenuImage" .. index, "overlay") setImageProperties(parent, image, widgetTable, currentXOffset, currentYOffset) currentYOffset = currentYOffset - widgetTable.height + 10 --store the widget created into the overall table and the widget by type table.insert(parent.widget_list, image) table.insert(parent.widget_list_by_type.textentry, image) widgetCreated = image amountLineWidgetAdded = amountLineWidgetAdded + 1 end if (widgetTable.nocombat) then table.insert(widgetsToDisableOnCombat, widgetCreated) end if (not widgetTable.inline) then if (widgetTable.spacement) then currentYOffset = currentYOffset - 30 else currentYOffset = currentYOffset - 20 end end if (extraPaddingY > 0) then currentYOffset = currentYOffset - extraPaddingY end if (bUseScrollFrame) then if (widgetTable.type == "breakline") then biggestColumnHeight = math.min(currentYOffset, biggestColumnHeight) currentYOffset = yOffset if (bAlignAsPairs) then currentXOffset = currentXOffset + nAlignAsPairsLength + (widgetWidth or maxWidgetWidth) + nAlignAsPairsSpacing else currentXOffset = currentXOffset + maxColumnWidth + 20 end amountLineWidgetAdded = 0 maxColumnWidth = 0 maxWidgetWidth = 0 end else if (widgetTable.type == "breakline" or currentYOffset < height) then currentYOffset = yOffset currentXOffset = currentXOffset + maxColumnWidth + 20 amountLineWidgetAdded = 0 maxColumnWidth = 0 end end end --no widget.hidden end --end loop if (bUseScrollFrame) then parent:SetHeight(biggestColumnHeight * -1) canvasFrame:GetParent().RefreshOptions = function() parent:RefreshOptions() end end detailsFramework.RefreshUnsafeOptionsWidgets() onMenuBuilt(parent) end local lockNotSafeWidgetsForCombat = function() for _, widget in ipairs(widgetsToDisableOnCombat) do widget:Disable() end end local unlockNotSafeWidgetsForCombat = function() for _, widget in ipairs(widgetsToDisableOnCombat) do widget:Enable() end end function detailsFramework.RefreshUnsafeOptionsWidgets() if (detailsFramework.PlayerHasCombatFlag) then lockNotSafeWidgetsForCombat() else unlockNotSafeWidgetsForCombat() end end detailsFramework.PlayerHasCombatFlag = false local ProtectCombatFrame = CreateFrame("frame") ProtectCombatFrame:RegisterEvent("PLAYER_REGEN_ENABLED") ProtectCombatFrame:RegisterEvent("PLAYER_REGEN_DISABLED") ProtectCombatFrame:RegisterEvent("PLAYER_ENTERING_WORLD") ProtectCombatFrame:SetScript("OnEvent", function(self, event) if (event == "PLAYER_ENTERING_WORLD") then if (InCombatLockdown()) then detailsFramework.PlayerHasCombatFlag = true else detailsFramework.PlayerHasCombatFlag = false end detailsFramework.RefreshUnsafeOptionsWidgets() elseif (event == "PLAYER_REGEN_ENABLED") then detailsFramework.PlayerHasCombatFlag = false detailsFramework.RefreshUnsafeOptionsWidgets() elseif (event == "PLAYER_REGEN_DISABLED") then detailsFramework.PlayerHasCombatFlag = true detailsFramework.RefreshUnsafeOptionsWidgets() end end) function detailsFramework:CreateInCombatTexture(frame) if (detailsFramework.debug and not frame) then error("Details! Framework: CreateInCombatTexture invalid frame on parameter 1.") end local inCombatBackgroundTexture = detailsFramework:CreateImage(frame) inCombatBackgroundTexture:SetColorTexture(.6, 0, 0, .1) inCombatBackgroundTexture:Hide() local inCombatLabel = detailsFramework:CreateLabel(frame, "you are in combat", 24, "silver") inCombatLabel:SetPoint("right", inCombatBackgroundTexture, "right", -10, 0) inCombatLabel:Hide() frame:RegisterEvent("PLAYER_REGEN_DISABLED") frame:RegisterEvent("PLAYER_REGEN_ENABLED") frame:SetScript("OnEvent", function(self, event) if (event == "PLAYER_REGEN_DISABLED") then inCombatBackgroundTexture:Show() inCombatLabel:Show() elseif (event == "PLAYER_REGEN_ENABLED") then inCombatBackgroundTexture:Hide() inCombatLabel:Hide() end end) return inCombatBackgroundTexture end