local PA = _G.ProjectAzilroka local stAM = PA:NewModule('stAddonManager', 'AceEvent-3.0') PA.stAM, _G.stAddonManager = stAM, stAM _G.stAddonManagerProfilesDB = {} _G.stAddonManagerServerDB = {} stAM.Title = PA.ACL['|cFF16C3F2st|r|cFFFFFFFFAddonManager|r'] stAM.Description = PA.ACL['A simple and minimalistic addon to disable/enabled addons without logging out.'] stAM.Authors = 'Azilroka Safturento' stAM.isEnabled = false local _G = _G local unpack = unpack local tinsert = tinsert local wipe = wipe local pairs = pairs local sort = sort local format = format local strlen = strlen local strlower = strlower local strfind = strfind local min = min local max = max local concat = table.concat local select = select local gsub = gsub local GetNumAddOns = GetNumAddOns local GetAddOnInfo = GetAddOnInfo local GetAddOnDependencies = GetAddOnDependencies local GetAddOnOptionalDependencies = GetAddOnOptionalDependencies local DisableAddOn = DisableAddOn local EnableAddOn = EnableAddOn local GetAddOnMetadata = GetAddOnMetadata local DisableAllAddOns = DisableAllAddOns local EnableAllAddOns = EnableAllAddOns local CreateFrame = CreateFrame local UIParent = UIParent local GameTooltip = GameTooltip local IsShiftKeyDown = IsShiftKeyDown _G.StaticPopupDialogs.STADDONMANAGER_OVERWRITEPROFILE = { button1 = PA.ACL['Overwrite'], button2 = PA.ACL['Cancel'], timeout = 0, whileDead = 1, enterClicksFirstButton = 1, hideOnEscape = 1, } _G.StaticPopupDialogs.STADDONMANAGER_NEWPROFILE = { text = PA.ACL['Enter a name for your new Addon Profile:'], button1 = PA.ACL['Create'], button2 = PA.ACL['Cancel'], timeout = 0, hasEditBox = 1, whileDead = 1, OnAccept = function(self) stAM:NewAddOnProfile(self.editBox:GetText()) end, EditBoxOnEnterPressed = function(self) stAM:NewAddOnProfile(self:GetText()) self:GetParent():Hide() end, EditBoxOnEscapePressed = function(self) self:GetParent():Hide() end, } _G.StaticPopupDialogs.STADDONMANAGER_RENAMEPROFILE = { text = PA.ACL['Enter a name for your AddOn Profile:'], button1 = PA.ACL['Update'], button2 = PA.ACL['Cancel'], timeout = 0, hasEditBox = 1, whileDead = 1, EditBoxOnEscapePressed = function(self) self:GetParent():Hide() end, } _G.StaticPopupDialogs.STADDONMANAGER_DELETECONFIRMATION = { button1 = PA.ACL['Delete'], button2 = PA.ACL['Cancel'], timeout = 0, whileDead = 1, enterClicksFirstButton = 1, hideOnEscape = 1, } local function strtrim(str) return gsub(str, '^%s*(.-)%s*$', '%1') end function stAM:BuildFrame() local Frame = CreateFrame('Frame', 'stAMFrame', UIParent) local Close = CreateFrame('Button', 'stAMCloseButton', Frame) local Search = CreateFrame('EditBox', 'stAMSearchBox', Frame, 'SearchBoxTemplate') local Profiles = CreateFrame('Button', 'stAMProfiles', Frame) local AddOns = CreateFrame('Frame', 'stAMAddOns', Frame) local Slider = CreateFrame('Slider', nil, AddOns) local Reload = CreateFrame('Button', 'stAMReload', Frame) local RequiredAddons = CreateFrame('CheckButton', nil, Frame) local OptionalAddons = CreateFrame('CheckButton', nil, Frame) local CharacterSelect = CreateFrame('Button', nil, Frame) local Title = Frame:CreateFontString(nil, 'OVERLAY') -- Defines local font, fontSize, fontFlag = PA.LSM:Fetch('font', stAM.db.Font), stAM.db.FontSize, stAM.db.FontFlag local Texture = PA.LSM:Fetch('statusbar', stAM.db.CheckTexture) local FrameWidth = stAM.db.FrameWidth local NumAddOns = stAM.db.NumAddOns local Color = stAM.db.ClassColor and PA.ClassColor or stAM.db.CheckColor local Width, Height = stAM.db.ButtonWidth, stAM.db.ButtonHeight Frame:SetSize(FrameWidth, 10 + NumAddOns * 25 + 40) Frame:SetPoint('CENTER', UIParent, 'CENTER', 0, 0) PA:SetTemplate(Frame) Frame:Hide() Frame:SetFrameStrata('HIGH') Frame:SetClampedToScreen(true) Frame:SetMovable(true) Frame:EnableMouse(true) Frame:SetScript('OnMouseDown', Frame.StartMoving) Frame:SetScript('OnMouseUp', Frame.StopMovingOrSizing) Title:SetPoint('TOPLEFT', 0, -5) Title:SetPoint('TOPRIGHT', 0, -5) Title:SetFont(font, 14, fontFlag) Title:SetText(stAM.Title) Title:SetJustifyH('CENTER') Title:SetJustifyV('MIDDLE') PA:SetTemplate(Close) Close:SetPoint('TOPRIGHT', -3, -3) Close:SetSize(16, 16) Close:SetScript('OnEnter', function() Close:SetBackdropBorderColor(unpack(stAM.db.ClassColor and PA.ClassColor or stAM.db.CheckColor)) end) Close:SetScript('OnLeave', function() PA:SetTemplate(Close) end) Close:SetScript('OnClick', function() Frame:Hide() end) local Mask = Close:CreateMaskTexture() Mask:SetTexture('Interface/AddOns/ProjectAzilroka/Media/Textures/Close', 'CLAMPTOBLACKADDITIVE', 'CLAMPTOBLACKADDITIVE') Mask:SetSize(10, 10) Mask:SetPoint('CENTER') Close.Mask = Mask Close:SetNormalTexture(Texture) Close:SetPushedTexture(Texture) local Normal, Pushed = Close:GetNormalTexture(), Close:GetPushedTexture() PA:SetInside(Normal, Close) Normal:SetVertexColor(1, 1, 1) Normal:AddMaskTexture(Mask) PA:SetInside(Pushed, Close) Pushed:SetVertexColor(1, .2, .2) Pushed:AddMaskTexture(Mask) Search:SetPoint('TOPLEFT', Title, 'BOTTOMLEFT', 10, -10) Search:SetPoint('BOTTOMRIGHT', Profiles, 'BOTTOMLEFT', -5, 0) Search:SetSize(1, 20) Search.Left:SetTexture() Search.Middle:SetTexture() Search.Right:SetTexture() PA:SetTemplate(Search) Search.AddOns = {} Search:HookScript('OnEscapePressed', function() stAM:UpdateAddonList() end) Search:HookScript('OnTextChanged', function(_, userInput) stAM.scrollOffset = 0 stAM.searchQuery = userInput stAM:UpdateAddonList() end) Search:HookScript('OnEditFocusGained', function() Search:SetBackdropBorderColor(unpack(stAM.db.CheckColor)) Search:HighlightText() end) Search:HookScript('OnEditFocusLost', function() PA:SetTemplate(Search) Search:HighlightText(0, 0) PA:SetTemplate(Search) end) Search.clearButton:HookScript('OnClick', stAM.UpdateAddonList) PA:SetTemplate(Reload) Reload:SetSize(70, 20) Reload:SetScript('OnEnter', function() Reload:SetBackdropBorderColor(unpack(stAM.db.ClassColor and PA.ClassColor or stAM.db.CheckColor)) end) Reload:SetScript('OnLeave', function() PA:SetTemplate(Reload) end) Reload:SetScript('OnClick', _G.ReloadUI) Reload.Text = Reload:CreateFontString(nil, 'OVERLAY') Reload.Text:SetFont(font, 12, fontFlag) Reload.Text:SetText(PA.ACL['Reload']) Reload.Text:SetPoint('CENTER', 0, 0) Reload.Text:SetJustifyH('CENTER') Reload:SetPoint('TOPLEFT', AddOns, 'BOTTOMLEFT', 0, -10) RequiredAddons:SetPoint('LEFT', Reload, 'RIGHT', 50, 0) PA:SetTemplate(RequiredAddons) RequiredAddons:SetSize(20, 20) RequiredAddons:SetScript('OnClick', function() stAM.db.EnableRequiredAddons = not stAM.db.EnableRequiredAddons end) RequiredAddons:SetScript('OnEnter', function() GameTooltip:SetOwner(RequiredAddons, 'ANCHOR_TOPRIGHT', 0, 4) GameTooltip:ClearLines() GameTooltip:AddLine(PA.ACL['Enable Required AddOns'], 1, 1, 1) GameTooltip:AddLine(PA.ACL['This will attempt to enable all the "Required" AddOns for the selected AddOn.'], 1, 1, 1) GameTooltip:Show() end) RequiredAddons:SetScript('OnLeave', function() PA:SetTemplate(RequiredAddons) GameTooltip:Hide() end) RequiredAddons.CheckTexture = RequiredAddons:CreateTexture(nil, 'OVERLAY', nil, 1) RequiredAddons.CheckTexture:SetTexture(Texture) RequiredAddons.CheckTexture:SetVertexColor(unpack(Color)) PA:SetInside(RequiredAddons.CheckTexture, RequiredAddons) RequiredAddons:SetCheckedTexture(RequiredAddons.CheckTexture) RequiredAddons:SetHighlightTexture('') RequiredAddons.Text = RequiredAddons:CreateFontString(nil, 'OVERLAY') RequiredAddons.Text:SetPoint('LEFT', RequiredAddons, 'RIGHT', 5, 0) RequiredAddons.Text:SetFont(font, 12, fontFlag) RequiredAddons.Text:SetText(PA.ACL['Required']) RequiredAddons:SetChecked(stAM.db.EnableRequiredAddons) CharacterSelect:SetPoint('TOPRIGHT', AddOns, 'BOTTOMRIGHT', 0, -10) CharacterSelect.DropDown = CreateFrame('Frame', 'stAMCharacterSelectDropDown', CharacterSelect, 'UIDropDownMenuTemplate') CharacterSelect:SetSize(150, 20) PA:SetTemplate(CharacterSelect) CharacterSelect:SetScript('OnEnter', function() CharacterSelect:SetBackdropBorderColor(unpack(stAM.db.ClassColor and PA.ClassColor or stAM.db.CheckColor)) end) CharacterSelect:SetScript('OnLeave', function() PA:SetTemplate(CharacterSelect) end) CharacterSelect:SetScript('OnClick', function() _G.EasyMenu(stAM.Menu, CharacterSelect.DropDown, CharacterSelect, 0, 38 + (stAM.MenuOffset * 16), 'MENU', 5) end) CharacterSelect.Text = CharacterSelect:CreateFontString(nil, 'OVERLAY') CharacterSelect.Text:SetFont(font, 12, fontFlag) CharacterSelect.Text:SetText(PA.ACL['Character Select']) CharacterSelect.Text:SetPoint('CENTER', 0, 0) CharacterSelect.Text:SetJustifyH('CENTER') Profiles:SetPoint('TOPRIGHT', Title, 'BOTTOMRIGHT', -10, -10) PA:SetTemplate(Profiles) Profiles:SetSize(70, 20) Profiles:SetScript('OnEnter', function() Profiles:SetBackdropBorderColor(unpack(stAM.db.ClassColor and PA.ClassColor or stAM.db.CheckColor)) end) Profiles:SetScript('OnLeave', function() PA:SetTemplate(Profiles) end) Profiles:SetScript('OnClick', function() stAM:ToggleProfiles() end) Profiles.Text = Profiles:CreateFontString(nil, 'OVERLAY') Profiles.Text:SetFont(font, 12, fontFlag) Profiles.Text:SetText(PA.ACL['Profiles']) Profiles.Text:SetPoint('CENTER', 0, 0) Profiles.Text:SetJustifyH('CENTER') AddOns:SetPoint('TOPLEFT', Search, 'BOTTOMLEFT', 0, -5) AddOns:SetPoint('TOPRIGHT', Profiles, 'BOTTOMRIGHT', 0, -5) AddOns:SetHeight(NumAddOns * (Height + 5) + 15) PA:SetTemplate(AddOns) AddOns.Buttons = {} AddOns:EnableMouse(true) AddOns:EnableMouseWheel(true) Slider:SetPoint('RIGHT', -2, 0) Slider:SetWidth(12) Slider:SetHeight(NumAddOns * (Height + 5) + 11) Slider:SetThumbTexture(PA.LSM:Fetch('background', 'Solid')) Slider:SetOrientation('VERTICAL') Slider:SetValueStep(1) PA:SetTemplate(Slider) Slider:SetMinMaxValues(0, 1) Slider:SetValue(0) Slider:EnableMouse(true) Slider:EnableMouseWheel(true) local Thumb = Slider:GetThumbTexture() Thumb:SetSize(8, 16) Thumb:SetVertexColor(unpack(Color)) AddOns.ScrollBar = Slider local OnScroll = function(_, delta) local numAddons = stAM.searchQuery and #Search.AddOns or #stAM.AddOnInfo if numAddons < stAM.db.NumAddOns then return end if IsShiftKeyDown() then if delta == 1 then stAM.scrollOffset = max(0, stAM.scrollOffset - stAM.db.NumAddOns) elseif delta == -1 then stAM.scrollOffset = min(numAddons - stAM.db.NumAddOns, stAM.scrollOffset + stAM.db.NumAddOns) end else if delta == 1 and stAM.scrollOffset > 0 then stAM.scrollOffset = stAM.scrollOffset - 1 elseif delta == -1 then if stAM.scrollOffset < numAddons - stAM.db.NumAddOns then stAM.scrollOffset = stAM.scrollOffset + 1 end end end Slider:SetMinMaxValues(0, (numAddons - stAM.db.NumAddOns)) Slider:SetValue(stAM.scrollOffset) stAM:UpdateAddonList() end AddOns:SetScript('OnMouseWheel', OnScroll) Slider:SetScript('OnMouseWheel', OnScroll) Slider:SetScript('OnValueChanged', function(_, value) stAM.scrollOffset = value OnScroll() end) for i = 1, 30 do local CheckButton = CreateFrame('CheckButton', 'stAMCheckButton_'..i, AddOns) CheckButton:Hide() PA:SetTemplate(CheckButton) CheckButton:SetSize(Width, Height) CheckButton:SetPoint(unpack(i == 1 and {'TOPLEFT', AddOns, 'TOPLEFT', 10, -10} or {'TOP', AddOns.Buttons[i-1], 'BOTTOM', 0, -5})) CheckButton:SetScript('OnClick', function() if CheckButton.name then if PA:IsAddOnEnabled(CheckButton.name, stAM.SelectedCharacter) then DisableAddOn(CheckButton.name, stAM.SelectedCharacter) else EnableAddOn(CheckButton.name, stAM.SelectedCharacter) if stAM.db.EnableRequiredAddons and CheckButton.required then for _, AddOn in pairs(CheckButton.required) do EnableAddOn(AddOn) end end end stAM:UpdateAddonList() end end) CheckButton:SetScript('OnEnter', function() GameTooltip:SetOwner(CheckButton, 'ANCHOR_TOPRIGHT', 0, 4) GameTooltip:ClearLines() GameTooltip:AddDoubleLine('AddOn:', CheckButton.title, 1, 1, 1, 1, 1, 1) GameTooltip:AddDoubleLine(PA.ACL['Authors:'], CheckButton.authors, 1, 1, 1, 1, 1, 1) GameTooltip:AddDoubleLine(PA.ACL['Version:'], CheckButton.version, 1, 1, 1, 1, 1, 1) if CheckButton.notes ~= nil then GameTooltip:AddDoubleLine('Notes:', CheckButton.notes, 1, 1, 1, 1, 1, 1) end if CheckButton.required or CheckButton.optional then GameTooltip:AddLine(' ') end if CheckButton.required then GameTooltip:AddDoubleLine('Required Dependencies:', concat(CheckButton.required, ', '), 1, 1, 1, 1, 1, 1) end if CheckButton.optional then GameTooltip:AddDoubleLine('Optional Dependencies:', concat(CheckButton.optional, ', '), 1, 1, 1, 1, 1, 1) end GameTooltip:Show() CheckButton:SetBackdropBorderColor(unpack(stAM.db.ClassColor and PA.ClassColor or stAM.db.CheckColor)) end) CheckButton:SetScript('OnLeave', function() PA:SetTemplate(CheckButton) GameTooltip:Hide() end) local Checked = CheckButton:CreateTexture(nil, 'OVERLAY', nil, 1) Checked:SetTexture(Texture) Checked:SetVertexColor(unpack(Color)) PA:SetInside(Checked, CheckButton) CheckButton.CheckTexture = Checked CheckButton:SetCheckedTexture(Checked) CheckButton:SetHighlightTexture('') local Text = CheckButton:CreateFontString(nil, 'OVERLAY') Text:SetFont(font, fontSize, fontFlag) Text:SetText('') Text:SetJustifyH('CENTER') Text:ClearAllPoints() Text:SetPoint('LEFT', CheckButton, 'RIGHT', 10, 0) Text:SetPoint('TOP', CheckButton, 'TOP') Text:SetPoint('BOTTOM', CheckButton, 'BOTTOM') Text:SetPoint('RIGHT', AddOns, 'CENTER', 0, 0) Text:SetJustifyH('LEFT') CheckButton.Text = Text local StatusText = CheckButton:CreateFontString(nil, 'OVERLAY') StatusText:SetFont(font, fontSize, fontFlag) StatusText:SetText('') StatusText:SetJustifyH('CENTER') StatusText:ClearAllPoints() StatusText:SetPoint('LEFT', Text, 'RIGHT', 0, 0) StatusText:SetPoint('TOP', CheckButton, 'TOP') StatusText:SetPoint('BOTTOM', CheckButton, 'BOTTOM') StatusText:SetPoint('RIGHT', AddOns, 'RIGHT', -10, 0) StatusText:SetJustifyH('LEFT') CheckButton.StatusText = StatusText local Icon = CheckButton:CreateTexture(nil, 'OVERLAY') Icon:SetTexture('Interface/AddOns/ProjectAzilroka/Media/Textures/QuestBang') Icon:SetPoint('CENTER', CheckButton, 'RIGHT', 10, 0) Icon:SetSize(32, 32) CheckButton.Icon = Icon AddOns.Buttons[i] = CheckButton end Frame.Title = Title Frame.Close = Close Frame.Reload = Reload Frame.RequiredAddons = RequiredAddons Frame.OptionalAddons = OptionalAddons Frame.Search = Search Frame.CharacterSelect = CharacterSelect Frame.Profiles = Profiles Frame.AddOns = AddOns Frame.AddOns:SetHeight(stAM.db.NumAddOns * (stAM.db.ButtonHeight + 5) + 15) Frame:SetSize(stAM.db.FrameWidth, Frame.Title:GetHeight() + Frame.Search:GetHeight() + Frame.AddOns:GetHeight() + Frame.Profiles:GetHeight() + 40) stAM.Frame = Frame tinsert(_G.UISpecialFrames, stAM.Frame:GetName()) _G.GameMenuButtonAddons:SetScript('OnClick', function() stAM.Frame:Show() _G.HideUIPanel(_G.GameMenuFrame) end) end function stAM:NewAddOnProfile(name, overwrite) if _G.stAddonManagerProfilesDB[name] and (not overwrite) then _G.StaticPopupDialogs['STADDONMANAGER_OVERWRITEPROFILE'].text = format(PA.ACL['There is already a profile named %s. Do you want to overwrite it?'], name) _G.StaticPopupDialogs['STADDONMANAGER_OVERWRITEPROFILE'].OnAccept = function() stAM:NewAddOnProfile(name, true) end _G.StaticPopup_Show('STADDONMANAGER_OVERWRITEPROFILE') return end _G.stAddonManagerProfilesDB[name] = {} for i = 1, #stAM.AddOnInfo do local AddOn, isEnabled = stAM.AddOnInfo[i].Name, PA:IsAddOnEnabled(i, stAM.SelectedCharacter) if isEnabled then tinsert(_G.stAddonManagerProfilesDB[name], AddOn) end end stAM:UpdateProfiles() end function stAM:InitProfiles() local ProfileMenu = CreateFrame('Frame', 'stAMProfileMenu', stAM.Frame) ProfileMenu:SetPoint('TOPLEFT', stAM.Frame, 'TOPRIGHT', 3, 0) ProfileMenu:SetSize(250, 50) PA:SetTemplate(ProfileMenu) ProfileMenu:Hide() for _, name in pairs({'EnableAll', 'DisableAll', 'NewButton'}) do local Button = CreateFrame('Button', nil, ProfileMenu) PA:SetTemplate(Button) Button:SetSize(stAM.db.ButtonWidth, stAM.db.ButtonHeight) Button:SetScript('OnEnter', function() Button:SetBackdropBorderColor(unpack(stAM.db.ClassColor and PA.ClassColor or stAM.db.CheckColor)) end) Button:SetScript('OnLeave', function() PA:SetTemplate(Button) end) Button.Text = Button:CreateFontString(nil, 'OVERLAY') Button.Text:SetFont(PA.LSM:Fetch('font', stAM.db.Font), 12, 'OUTLINE') Button.Text:SetPoint('CENTER', 0, 0) Button.Text:SetJustifyH('CENTER') ProfileMenu[name] = Button end ProfileMenu.EnableAll.Text:SetText(PA.ACL['Enable All']) ProfileMenu.EnableAll:SetPoint('TOPLEFT', ProfileMenu, 'TOPLEFT', 10, -10) ProfileMenu.EnableAll:SetPoint('TOPRIGHT', ProfileMenu, 'TOP', -3, -10) ProfileMenu.EnableAll:SetScript('OnClick', function() EnableAllAddOns(stAM.SelectedCharacter) stAM:UpdateAddonList() end) ProfileMenu.DisableAll.Text:SetText(PA.ACL['Disable All']) ProfileMenu.DisableAll:SetPoint('TOPRIGHT', ProfileMenu, 'TOPRIGHT', -10, -10) ProfileMenu.DisableAll:SetPoint('TOPLEFT', ProfileMenu, 'TOP', 2, -10) ProfileMenu.DisableAll:SetScript('OnClick', function() DisableAllAddOns(stAM.SelectedCharacter) stAM:UpdateAddonList() end) ProfileMenu.NewButton.Text:SetText(PA.ACL['New Profile']) ProfileMenu.NewButton:SetPoint('TOPLEFT', ProfileMenu.EnableAll, 'BOTTOMLEFT', 0, -5) ProfileMenu.NewButton:SetPoint('TOPRIGHT', ProfileMenu.DisableAll, 'BOTTOMRIGHT', 0, -5) ProfileMenu.NewButton:SetScript('OnClick', function() _G.StaticPopup_Show('STADDONMANAGER_NEWPROFILE') end) ProfileMenu.Buttons = {} for i = 1, 30 do local Pullout = CreateFrame('Frame', nil, ProfileMenu) Pullout:SetWidth(210) Pullout:SetHeight(stAM.db.ButtonHeight) Pullout:Hide() for _, Frame in pairs({'Load', 'Delete', 'Update'}) do local Button = CreateFrame('Button', nil, Pullout) PA:SetTemplate(Button) Button:SetSize(73, stAM.db.ButtonHeight) Button:RegisterForClicks('AnyDown') Button:SetScript('OnEnter', function() Button:SetBackdropBorderColor(unpack(stAM.db.ClassColor and PA.ClassColor or stAM.db.CheckColor)) end) Button:SetScript('OnLeave', function() PA:SetTemplate(Button) end) Button.Text = Button:CreateFontString(nil, 'OVERLAY') Button.Text:SetFont(PA.LSM:Fetch('font', stAM.db.Font), 12, 'OUTLINE') Button.Text:SetPoint('CENTER', 0, 0) Button.Text:SetJustifyH('CENTER') Pullout[Frame] = Button end Pullout.Load:SetPoint('LEFT', Pullout, 0, 0) Pullout.Load.Text:SetText('Load') Pullout.Load:SetScript('OnClick', function(_, btn) if btn == 'RightButton' then local Dialog = _G.StaticPopupDialogs.STADDONMANAGER_RENAMEPROFILE Dialog.OnAccept = function(dialog) _G.stAddonManagerProfilesDB[Pullout.Name] = nil stAM:NewAddOnProfile(dialog.editBox:GetText()) stAM:UpdateProfiles() end Dialog.EditBoxOnEnterPressed = function(editBox) _G.stAddonManagerProfilesDB[Pullout.Name] = nil stAM:NewAddOnProfile(editBox:GetText()) stAM:UpdateProfiles() editBox:GetParent():Hide() end _G.StaticPopup_Show('STADDONMANAGER_RENAMEPROFILE') else if not IsShiftKeyDown() then DisableAllAddOns(stAM.SelectedCharacter) end for _, AddOn in pairs(_G.stAddonManagerProfilesDB[Pullout.Name]) do EnableAddOn(AddOn, stAM.SelectedCharacter) end stAM:UpdateAddonList() end end) Pullout.Update:SetPoint('LEFT', Pullout.Load, 'RIGHT', 5, 0) Pullout.Update.Text:SetText(PA.ACL['Update']) Pullout.Update:SetScript('OnClick', function() stAM:NewAddOnProfile(Pullout.Name, true) end) Pullout.Delete:SetPoint('LEFT', Pullout.Update, 'RIGHT', 5, 0) Pullout.Delete.Text:SetText(PA.ACL['Delete']) Pullout.Delete:SetScript('OnClick', function() local dialog = _G.StaticPopupDialogs['STADDONMANAGER_DELETECONFIRMATION'] dialog.text = format(PA.ACL['Are you sure you want to delete %s?'], Pullout.Name) dialog.OnAccept = function() _G.stAddonManagerProfilesDB[Pullout.Name] = nil stAM:UpdateProfiles() end _G.StaticPopup_Show('STADDONMANAGER_DELETECONFIRMATION') end) ProfileMenu.Buttons[i] = Pullout end stAM.ProfileMenu = ProfileMenu end function stAM:UpdateProfiles() local ProfileMenu = stAM.ProfileMenu wipe(stAM.Profiles) for name, _ in pairs(_G.stAddonManagerProfilesDB) do tinsert(stAM.Profiles, name) end sort(stAM.Profiles) local PreviousButton for i, Button in ipairs(ProfileMenu.Buttons) do local isShown = i <= min(#stAM.Profiles, 30) if isShown then Button.Load.Text:SetText(stAM.Profiles[i]) end Button.Name = isShown and stAM.Profiles[i] or nil Button:SetShown(isShown) if i == 1 then Button:SetPoint('TOPLEFT', ProfileMenu.NewButton, 'BOTTOMLEFT', 0, -5) else Button:SetPoint('TOP', PreviousButton, 'BOTTOM', 0, -5) end PreviousButton = Button end ProfileMenu:SetHeight((min(#stAM.Profiles, 30) + 2) * (stAM.db.ButtonHeight + 5) + 15) end function stAM:ToggleProfiles() _G.ToggleFrame(stAM.ProfileMenu) stAM:UpdateProfiles() end function stAM:UpdateAddonList() wipe(stAM.Frame.Search.AddOns) if stAM.searchQuery then local query = strlower(strtrim(stAM.Frame.Search:GetText())) if (strlen(query) == 0) then stAM.searchQuery = false end for i, AddOn in ipairs(stAM.AddOnInfo) do local name, title, authors = AddOn.Name, AddOn.Title, AddOn.Authors if strfind(strlower(name), query, nil, true) or strfind(strlower(title), query, nil, true) or (authors and strfind(strlower(authors), query, nil, true)) then tinsert(stAM.Frame.Search.AddOns, i) end end end for i, button in ipairs(stAM.Frame.AddOns.Buttons) do local addonIndex = (not stAM.searchQuery and (stAM.scrollOffset + i)) or stAM.Frame.Search.AddOns[stAM.scrollOffset + i] local info = stAM.AddOnInfo[addonIndex] if addonIndex and addonIndex <= #stAM.AddOnInfo then button.name, button.title, button.authors, button.version, button.notes, button.required, button.optional = info.Name, info.Title, info.Authors, info.Version, info.Notes, info.Required, info.Optional button.Text:SetText(button.title) button.Icon:SetShown(info.Missing or info.Disabled) button.StatusText:SetShown(info.Missing or info.Disabled) if info.Missing or info.Disabled then if info.Missing then button.Icon:SetVertexColor(.77, .12, .24) button.StatusText:SetVertexColor(.77, .12, .24) button.StatusText:SetText(PA.ACL['Missing: ']..concat(info.Missing, ', ')) else button.Icon:SetVertexColor(1, .8, .1) button.StatusText:SetVertexColor(1, .8, .1) button.StatusText:SetText(PA.ACL['Disabled: ']..concat(info.Disabled, ', ')) end button.Text:SetPoint('LEFT', button.Icon, 'CENTER', 5, 0) button.Text:SetPoint('RIGHT', stAM.Frame.AddOns, 'CENTER', 0, 0) else button.Text:SetPoint('LEFT', button, 'RIGHT', 5, 0) button.Text:SetPoint('RIGHT', stAM.Frame.AddOns, 'RIGHT', -10, 0) end button:SetChecked(PA:IsAddOnPartiallyEnabled(addonIndex, stAM.SelectedCharacter) or PA:IsAddOnEnabled(addonIndex, stAM.SelectedCharacter)) button.CheckTexture:SetVertexColor(unpack(PA:IsAddOnPartiallyEnabled(addonIndex, stAM.SelectedCharacter) and {.6, .6, .6} or stAM.db.ClassColor and PA.ClassColor or stAM.db.CheckColor)) button:SetShown(i <= min(#stAM.Frame.Search.AddOns > 0 and #stAM.Frame.Search.AddOns or stAM.db.NumAddOns, stAM.db.NumAddOns)) else button:SetShown(false) end end end function stAM:Update() if not stAM.Frame then return end stAM.Frame:SetSize(stAM.db.FrameWidth, stAM.Frame.Title:GetHeight() + 5 + stAM.Frame.Search:GetHeight() + 5 + stAM.Frame.AddOns:GetHeight() + 10 + stAM.Frame.Profiles:GetHeight() + 20) stAM.Frame.AddOns:SetHeight(stAM.db.NumAddOns * (stAM.db.ButtonHeight + 5) + 15) stAM.Frame.AddOns.ScrollBar:SetHeight(stAM.db.NumAddOns * (stAM.db.ButtonHeight + 5) + 11) local font, fontSize, fontFlag = PA.LSM:Fetch('font', stAM.db.Font), stAM.db.FontSize, stAM.db.FontFlag for _, CheckButton in ipairs(stAM.Frame.AddOns.Buttons) do CheckButton:SetSize(stAM.db.ButtonWidth, stAM.db.ButtonHeight) CheckButton.Text:SetFont(font, fontSize, fontFlag) CheckButton.StatusText:SetFont(font, fontSize, fontFlag) CheckButton.CheckTexture:SetTexture(PA.LSM:Fetch('statusbar', stAM.db.CheckTexture)) CheckButton.CheckTexture:SetVertexColor(unpack(stAM.db.ClassColor and PA.ClassColor or stAM.db.CheckColor)) CheckButton:SetCheckedTexture(CheckButton.CheckTexture) end stAM.Frame.AddOns.ScrollBar:GetThumbTexture():SetVertexColor(unpack(stAM.db.ClassColor and PA.ClassColor or stAM.db.CheckColor)) stAM.Frame.Title:SetFont(font, 14, fontFlag) stAM.Frame.Search:SetFont(font, 12, fontFlag) stAM.Frame.Reload.Text:SetFont(font, 12, fontFlag) stAM.Frame.Profiles.Text:SetFont(font, 12, fontFlag) stAM.Frame.CharacterSelect.Text:SetFont(font, 12, fontFlag) stAM.Frame.RequiredAddons.Text:SetFont(font, 12, fontFlag) stAM.Frame.RequiredAddons:SetChecked(stAM.db.EnableRequiredAddons) stAM.Frame.OptionalAddons:SetChecked(stAM.db.EnableOptionalAddons) stAM.ProfileMenu.EnableAll.Text:SetFont(font, 12, fontFlag) stAM.ProfileMenu.DisableAll.Text:SetFont(font, 12, fontFlag) stAM.ProfileMenu.NewButton.Text:SetFont(font, 12, fontFlag) for _, Button in ipairs(stAM.ProfileMenu.Buttons) do Button.Load.Text:SetFont(font, 12, fontFlag) Button.Update.Text:SetFont(font, 12, fontFlag) Button.Delete.Text:SetFont(font, 12, fontFlag) end stAM:UpdateAddonList() end function stAM:GetOptions() local stAddonManager = PA.ACH:Group(stAM.Title, stAM.Description, nil, nil, function(info) return stAM.db[info[#info]] end, function(info, value) stAM.db[info[#info]] = value stAM:Update() end) PA.Options.args.stAddonManager = stAddonManager stAddonManager.args.Description = PA.ACH:Description(stAM.Description, 0) stAddonManager.args.Enable = PA.ACH:Toggle(PA.ACL['Enable'], nil, 1, nil, nil, nil, nil, function(info, value) stAM.db[info[#info]] = value if not stAM.isEnabled then stAM:Initialize() else _G.StaticPopup_Show('PROJECTAZILROKA_RL') end end) stAddonManager.args.General = PA.ACH:Group(PA.ACL['General'], nil, 2) stAddonManager.args.General.inline = true stAddonManager.args.General.args.NumAddOns = PA.ACH:Range(PA.ACL['# Shown AddOns'], nil, 1, { min = 3, max = 30, step = 1 }) stAddonManager.args.General.args.FrameWidth = PA.ACH:Range(PA.ACL['Frame Width'], nil, 2, { min = 250, max = 2048, step = 2 }) stAddonManager.args.General.args.ButtonHeight = PA.ACH:Range(PA.ACL['Button Height'], nil, 3, { min = 3, max = 30, step = 1 }) stAddonManager.args.General.args.ButtonWidth = PA.ACH:Range(PA.ACL['Button Width'], nil, 4, { min = 3, max = 30, step = 1 }) stAddonManager.args.General.args.EnableRequiredAddons = PA.ACH:Toggle(PA.ACL['Enable Required AddOns'], PA.ACL['This will attempt to enable all the "Required" AddOns for the selected AddOn.'], 5) stAddonManager.args.General.args.CheckTexture = PA.ACH:SharedMediaStatusbar(PA.ACL['Texture'], nil, 6) stAddonManager.args.General.args.CheckColor = PA.ACH:Color(COLOR_PICKER, nil, 2, true, nil, function(info) return unpack(stAM.db[info[#info]]) end, function(info, r, g, b, a) stAM.db[info[#info]] = { r, g, b, a} stAM:Update() end, function() return stAM.db.ClassColor end) stAddonManager.args.General.args.ClassColor = PA.ACH:Toggle(PA.ACL['Class Color Check Texture'], nil, 8) stAddonManager.args.General.args.FontSettings = PA.ACH:Group(PA.ACL['Font Settings'], nil, -1) stAddonManager.args.General.args.FontSettings.inline = true stAddonManager.args.General.args.FontSettings.args.Font = PA.ACH:SharedMediaFont(PA.ACL['Font'], nil, 1) stAddonManager.args.General.args.FontSettings.args.FontSize = PA.ACH:Range(FONT_SIZE, nil, 2, { min = 6, max = 22, step = 1 }) stAddonManager.args.General.args.FontSettings.args.FontFlag = PA.ACH:FontFlags(PA.ACL['Font Outline'], nil, 3) stAddonManager.args.AuthorHeader = PA.ACH:Header(PA.ACL['Authors:'], -2) stAddonManager.args.Authors = PA.ACH:Description(stAM.Authors, -1, 'large') end function stAM:BuildProfile() PA.Defaults.profile.stAddonManager = { Enable = true, NumAddOns = 30, FrameWidth = 550, Font = 'PT Sans Narrow Bold', FontSize = 16, FontFlag = 'OUTLINE', ButtonHeight = 18, ButtonWidth = 22, CheckColor = { 0, .66, 1}, ClassColor = false, CheckTexture = 'Solid', EnableRequiredAddons = true, EnableOptionalAddons = false, } end function stAM:UpdateSettings() stAM.db = PA.db.stAddonManager end function stAM:Initialize() stAM:UpdateSettings() if stAM.db.Enable ~= true then return end stAM.isEnabled = true stAM.AddOnInfo = {} stAM.Profiles = {} for i = 1, GetNumAddOns() do local Name, Title, Notes = GetAddOnInfo(i) local Required, Optional = nil, nil local MissingAddons, DisabledAddons local HasRequired, HasOptional = GetAddOnDependencies(i), GetAddOnOptionalDependencies(i) if HasRequired then Required = { HasRequired } for _, addon in pairs(Required) do local Reason = select(5, GetAddOnInfo(addon)) if Reason == 'MISSING' then MissingAddons = MissingAddons or {} tinsert(MissingAddons, addon) elseif Reason == 'DISABLED' then DisabledAddons = DisabledAddons or {} tinsert(DisabledAddons, addon) end end end if HasOptional then Optional = { HasOptional } end local Authors = GetAddOnMetadata(i, 'Author') local Version = GetAddOnMetadata(i, 'Version') stAM.AddOnInfo[i] = { Name = Name, Title = Title, Authors = Authors, Version = Version, Notes = Notes, Required = Required, Optional = Optional, Missing = MissingAddons, Disabled = DisabledAddons } end stAM.SelectedCharacter = PA.MyName stAM.Menu = { { text = 'All', checked = function() return stAM.SelectedCharacter == true end, func = function() stAM.SelectedCharacter = true stAM:UpdateAddonList() end} } _G.stAddonManagerServerDB[PA.MyRealm] = _G.stAddonManagerServerDB[PA.MyRealm] or {} _G.stAddonManagerServerDB[PA.MyRealm][PA.MyName] = true local index = 2 for Character in PA:PairsByKeys(_G.stAddonManagerServerDB[PA.MyRealm]) do stAM.Menu[index] = { text = Character, checked = function() return stAM.SelectedCharacter == Character end, func = function() stAM.SelectedCharacter = Character stAM:UpdateAddonList() end } index = index + 1 end stAM.MenuOffset = index stAM.scrollOffset = 0 stAM:BuildFrame() stAM:InitProfiles() stAM:Update() end