diff --git a/api/ui-widgets.xml b/api/ui-widgets.xml
new file mode 100644
index 00000000..0d7b3940
--- /dev/null
+++ b/api/ui-widgets.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/init/api.xml b/init/api.xml
index 9d3a1735..acc19d0c 100644
--- a/init/api.xml
+++ b/init/api.xml
@@ -1,6 +1,7 @@
+
diff --git a/modules/addons.lua b/modules/addons.lua
index 28eb82ee..e5e9e35a 100644
--- a/modules/addons.lua
+++ b/modules/addons.lua
@@ -69,12 +69,42 @@ pfUI:RegisterModule("addons", function ()
pfUI.addons:Hide()
end)
+ -- installed addons, one entry per row of the addon list
+ local addons = {}
+ for i = 1, GetNumAddOns() do
+ local name, title, notes = GetAddOnInfo(i)
+ addons[i] = {
+ index = i,
+ name = name,
+ title = title,
+ notes = notes,
+ author = GetAddOnMetadata(name, "Author"),
+ version = GetAddOnMetadata(name, "Version"),
+ deps = { GetAddOnDependencies(i) }, -- required (.toc Dependencies)
+ optdeps = { C_AddOns.GetAddOnOptionalDependencies(i) }, -- optional (.toc OptionalDeps)
+ }
+ end
+
+ local function IsAddonEnabled(index)
+ local _, _, _, enabled = GetAddOnInfo(index)
+ return enabled
+ end
+
+ local function SetAddonEnabled(index, enabled)
+ if enabled then
+ EnableAddOn(index)
+ else
+ DisableAddOn(index)
+ end
+ pfUI.addons.hasChanged = true
+ end
+
-- addons profile
local function GetSelectedAddonsList()
local selected_addons = {}
- for i, frame in ipairs(pfUI.addons.list) do
- if frame.input:GetChecked() then
- table.insert(selected_addons, frame.aname)
+ for i, addon in ipairs(addons) do
+ if IsAddonEnabled(i) then
+ table.insert(selected_addons, addon.name)
end
end
return selected_addons
@@ -90,28 +120,20 @@ pfUI:RegisterModule("addons", function ()
pfUI.addons.profile.dropdown:SetSelectionByText(profile)
-- load profile
- local selected_list = pfUI_addon_profiles[profile]
- for i=1, GetNumAddOns() do
- local active = false
- local f = pfUI.addons.list[i]
+ local selected = {}
+ for _, name in ipairs(pfUI_addon_profiles[profile]) do
+ selected[name] = true
+ end
- for i_i, n in ipairs(selected_list) do
- if f.aname == n then
- active = true
- break
- end
- end
-
- if active then
- if not f.input:GetChecked() then
- f.input:Click()
- end
- else
- if f.input:GetChecked() then
- f.input:Click()
- end
+ for i, addon in ipairs(addons) do
+ if selected[addon.name] and not IsAddonEnabled(i) then
+ SetAddonEnabled(i, true)
+ elseif not selected[addon.name] and IsAddonEnabled(i) then
+ SetAddonEnabled(i, false)
end
end
+
+ pfUI.addons.scroll:ReinitializeFrames()
end
-- addon profiles
@@ -193,23 +215,6 @@ pfUI:RegisterModule("addons", function ()
return menu
end)
- -- addon list: scroll frame
- pfUI.addons.scroll = CreateScrollFrame("pfAddonListScroll", pfUI.addons)
- pfUI.addons.scroll:SetSize(360, 410)
- pfUI.addons.scroll:SetPoint("BOTTOM", 0, 10)
-
- pfUI.addons.scroll.backdrop = CreateFrame("Frame", nil, pfUI.addons.scroll)
- pfUI.addons.scroll.backdrop:SetFrameLevel(1)
- pfUI.addons.scroll.backdrop:SetPoint("TOPLEFT", pfUI.addons.scroll, "TOPLEFT", -5, 5)
- pfUI.addons.scroll.backdrop:SetPoint("BOTTOMRIGHT", pfUI.addons.scroll, "BOTTOMRIGHT", 5, -5)
- CreateBackdrop(pfUI.addons.scroll.backdrop, nil, true)
-
- -- addon list: scroll parent
- pfUI.addons.list = CreateScrollChild("pfAddonList", pfUI.addons.scroll)
- pfUI.addons.list:RegisterEvent("ADDON_LOADED")
- pfUI.addons.list:RegisterEvent("PLAYER_ENTERING_WORLD")
- pfUI.addons.list:SetHeight(GetNumAddOns() * 25 + 26)
-
local function AddDependencyLines(header, deps)
if not deps or table.getn(deps) == 0 then return end
GameTooltip:AddLine(" ")
@@ -225,137 +230,105 @@ pfUI:RegisterModule("addons", function ()
end
end
- local function AddonOnEnter()
- this:SetBackdropBorderColor(1,1,1,.08)
+ local function RowOnEnter(self)
+ local addon = self.addon
+ self:SetBackdropBorderColor(1,1,1,.08)
- GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
- GameTooltip:SetText(this.atitle)
- if this.aversion then
- GameTooltip:AddDoubleLine(T["Version"], this.aversion, 1,1,1, .2,1,.8)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
+ GameTooltip:SetText(addon.title)
+ if addon.version then
+ GameTooltip:AddDoubleLine(T["Version"], addon.version, 1,1,1, .2,1,.8)
end
- if this.aauthor then
- GameTooltip:AddDoubleLine(T["Author"], this.aauthor, 1,1,1, .2,1,.8)
+ if addon.author then
+ GameTooltip:AddDoubleLine(T["Author"], addon.author, 1,1,1, .2,1,.8)
end
- GameTooltip:AddLine(this.anote, .75,.75,.75,1)
- AddDependencyLines(T["Dependencies"], this.adeps)
- AddDependencyLines(T["Optional Dependencies"], this.aoptdeps)
+ GameTooltip:AddLine(addon.notes, .75,.75,.75,1)
+ AddDependencyLines(T["Dependencies"], addon.deps)
+ AddDependencyLines(T["Optional Dependencies"], addon.optdeps)
GameTooltip:SetWidth(180)
GameTooltip:Show()
end
- local function AddonOnLeave()
- this:SetBackdropBorderColor(1,1,1,.04)
+ local function RowOnLeave(self)
+ self:SetBackdropBorderColor(1,1,1,.04)
GameTooltip:Hide()
end
- local function AddonOnClick()
- this.input:Click()
+ local function RowOnClick(self)
+ self.input:Click()
end
- local function InputOnClick()
- if this:GetChecked() then
- EnableAddOn(this:GetID())
- else
- DisableAddOn(this:GetID())
- end
- pfUI.addons.hasChanged = true
+ local function InputOnClick(self)
+ SetAddonEnabled(self:GetParent().addon.index, self:GetChecked())
- local id, name = pfUI.addons.profile.dropdown:GetSelection()
+ local _, name = pfUI.addons.profile.dropdown:GetSelection()
name = name or T["Current"]
pfUI_addon_profiles[name] = GetSelectedAddonsList()
end
- pfUI.addons.list:SetScript("OnEvent", function()
- for i=1, GetNumAddOns() do
- local aname, atitle, anote = GetAddOnInfo(i)
- local aauthor = GetAddOnMetadata(aname, "Author")
- local aversion = GetAddOnMetadata(aname, "Version")
+ local function InitRow(row, addon)
+ -- one-time setup of a pooled row
+ if not row.input then
+ row:SetBackdrop(pfUI.backdrop_hover)
+ row:SetBackdropBorderColor(1,1,1,.04)
- -- basic frame
- if not pfUI.addons.list[i] then
- pfUI.addons.list[i] = CreateFrame("Button", nil, pfUI.addons.list)
- local frame = pfUI.addons.list[i]
- frame.aname = aname
- frame.atitle = atitle
- frame.anote = anote
- frame.aauthor = aauthor
- frame.aversion = aversion
- frame.adeps = { GetAddOnDependencies(i) } -- required (.toc Dependencies)
- frame.aoptdeps = { C_AddOns.GetAddOnOptionalDependencies(i) } -- optional (.toc OptionalDeps)
+ row:EnableMouse(true)
+ row:SetScript("OnEnter", RowOnEnter)
+ row:SetScript("OnLeave", RowOnLeave)
+ row:SetScript("OnClick", RowOnClick)
- frame:SetSize(340, 25)
- frame:SetPoint("TOPLEFT", 5, i * -25 + 20)
+ -- caption
+ row.caption = row:CreateFontString(nil, "LOW", "GameFontNormal")
+ row.caption:SetFont(pfUI.font_default, C.global.font_size + 2, "OUTLINE")
+ row.caption:SetPoint("LEFT", row, "LEFT", 2, 0)
+ row.caption:SetFontObject(GameFontWhite)
+ row.caption:SetJustifyH("LEFT")
- frame:SetBackdrop(pfUI.backdrop_hover)
- frame:SetBackdropBorderColor(1,1,1,.04)
-
- frame:EnableMouse(1)
- frame:SetScript("OnEnter", AddonOnEnter)
- frame:SetScript("OnLeave", AddonOnLeave)
- frame:SetScript("OnClick", AddonOnClick)
-
- -- caption
- frame.caption = frame:CreateFontString("Status", "LOW", "GameFontNormal")
- frame.caption:SetFont(pfUI.font_default, C.global.font_size + 2, "OUTLINE")
- frame.caption:SetPoint("LEFT", frame, "LEFT", 2, 0)
- frame.caption:SetFontObject(GameFontWhite)
- frame.caption:SetJustifyH("LEFT")
- frame.caption:SetText(atitle)
-
- -- input field
- frame.input = CreateFrame("CheckButton", nil, frame, "UICheckButtonTemplate")
- frame.input:SetFrameLevel(3)
- frame.input:SetNormalTexture("")
- frame.input:SetPushedTexture("")
- frame.input:SetHighlightTexture("")
- CreateBackdrop(frame.input, nil, true)
- frame.input:SetBackdropBorderColor(.3,.3,.3,1)
- frame.input:SetWidth(14)
- frame.input:SetHeight(14)
- frame.input:SetPoint("RIGHT" , -5, 1)
- frame.input:SetID(i)
- frame.input:SetScript("OnClick", InputOnClick)
- end
-
- if IsAddOnLoaded(i) then
- pfUI.addons.list[i].input:SetChecked()
- pfUI.addons.list[i].caption:SetAlpha(1)
- else
- pfUI.addons.list[i].caption:SetAlpha(.5)
- end
+ -- input field
+ row.input = CreateFrame("CheckButton", nil, row, "UICheckButtonTemplate")
+ row.input:SetNormalTexture("")
+ row.input:SetPushedTexture("")
+ row.input:SetHighlightTexture("")
+ CreateBackdrop(row.input, nil, true)
+ row.input:SetBackdropBorderColor(.3,.3,.3,1)
+ row.input:SetSize(14, 14)
+ row.input:SetPoint("RIGHT" , -5, 1)
+ row.input:SetScript("OnClick", InputOnClick)
end
- end)
- -- show only frames in visible range
- function pfUI.addons.scroll:ShowVisibleRange()
- local top_index, bottom_index, range
- range = floor(pfUI.addons.scroll:GetHeight() / 25) + 1
- top_index = floor(pfUI.addons.scroll:GetVerticalScroll() / 25) > 0 and floor(pfUI.addons.scroll:GetVerticalScroll() / 25) or 1
- bottom_index = top_index + range
- for i=1, GetNumAddOns() do
- if i >= top_index and i <= bottom_index then
- pfUI.addons.list[i]:Show()
- else
- pfUI.addons.list[i]:Hide()
- end
- end
+ row.addon = addon
+ row.caption:SetText(addon.title)
+ row.caption:SetAlpha(IsAddOnLoaded(addon.index) and 1 or .5)
+ row.input:SetChecked(IsAddonEnabled(addon.index))
end
- pfUI.addons.scroll.slider:SetScript("OnValueChanged", function()
- this:GetParent():SetVerticalScroll(this:GetValue())
- end)
- pfUI.addons.scroll:SetScript("OnScrollRangeChanged", function()
- this.slider:SetMinMaxValues(1, floor(this:GetVerticalScrollRange() + 25))
- end)
- pfUI.addons.scroll:SetScript("OnShow", function()
- this.slider:SetValue(floor(this:GetVerticalScroll()))
- pfUI.addons.scroll:ShowVisibleRange()
- end)
- pfUI.addons.scroll:SetScript("OnVerticalScroll", function()
- pfUI.addons.scroll:ShowVisibleRange()
- this.slider:SetValue(floor(this:GetVerticalScroll()))
+ -- addon list: a ScrollBox keeps rows only for the addons in view
+ pfUI.addons.scroll = CreateFrame("Frame", "pfAddonListScroll", pfUI.addons, "WowScrollBoxList")
+ pfUI.addons.scroll:SetSize(360, 410)
+ pfUI.addons.scroll:SetPoint("BOTTOM", 0, 10)
+
+ -- the ScrollBox clips its children, so the backdrop is a sibling
+ pfUI.addons.scroll.backdrop = CreateFrame("Frame", nil, pfUI.addons)
+ pfUI.addons.scroll.backdrop:SetPoint("TOPLEFT", pfUI.addons.scroll, "TOPLEFT", -5, 5)
+ pfUI.addons.scroll.backdrop:SetPoint("BOTTOMRIGHT", pfUI.addons.scroll, "BOTTOMRIGHT", 5, -5)
+ CreateBackdrop(pfUI.addons.scroll.backdrop, nil, true)
+
+ local scrollbar = CreateFrame("EventFrame", nil, pfUI.addons, "pfUIScrollBarTemplate")
+ scrollbar:SetPoint("TOPRIGHT", pfUI.addons.scroll, "TOPRIGHT")
+ scrollbar:SetPoint("BOTTOMRIGHT", pfUI.addons.scroll, "BOTTOMRIGHT")
+
+ local view = CreateScrollBoxListLinearView(5, 5, 5, 15)
+ view:SetElementExtent(25)
+ view:SetElementInitializer("Button", InitRow)
+ ScrollUtil.InitScrollBoxListWithScrollBar(pfUI.addons.scroll, scrollbar, view)
+ pfUI.addons.scroll:SetDataProvider(CreateDataProvider(addons))
+
+ -- a load-on-demand addon that loads brightens its row
+ pfUI.addons.scroll:RegisterEvent("ADDON_LOADED")
+ pfUI.addons.scroll:SetScript("OnEvent", function(self)
+ self:ReinitializeFrames()
end)
end)