NinjaPanel = {} -- Import Data Broker and bail if we can't find it for some reason local ldb = LibStub:GetLibrary("LibDataBroker-1.1") local jostle = LibStub:GetLibrary("LibJostle-3.0", true) local db local options = { panels = setmetatable({}, { __index = { TOP = { anchors = {"TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT"}, sizes = {25, 2, 23, 23, 23, nil}, offsets = {0, 0, 0, 0}, gradient = {"VERTICAL", 0.2, 0.2, 0.2, 0, 0, 0}, bgradient = {"HORIZONTAL", 203/255, 161/255, 53/255, 0, 0, 0}, }, RIGHT = { anchors = {"TOPRIGHT", "BOTTOMRIGHT", "TOPLEFT", "BOTTOMLEFT"}, sizes = {25, 2, 23, 23, 23, nil}, offsets = {0, 0, 0, 0}, gradient = {"HORIZONTAL", 0.2, 0.2, 0.2, 0, 0, 0}, bgradient = {"VERTICAL", 0, 0, 0, 203/255, 161/255, 53/255}, }, BOTTOM = { anchors = {"BOTTOMLEFT", "BOTTOMRIGHT", "TOPLEFT", "TOPRIGHT"}, sizes = {25, 2, 23, 23, 23, nil}, offsets = {0, 0, 0, 0}, gradient = {"VERTICAL", 0, 0, 0, 0.2, 0.2, 0.2}, bgradient = {"HORIZONTAL", 0, 0, 0, 203/255, 161/255, 53/255}, }, LEFT = { anchors = {"TOPLEFT", "BOTTOMLEFT", "TOPRIGHT", "BOTTOMRIGHT"}, sizes = {25, 2, 23, 23, 23, nil}, offsets = {0, 0, 0, 0}, gradient = {"HORIZONTAL", 0, 0, 0, 0.2, 0.2, 0.2}, bgradient = {"VERTICAL", 203/255, 161/255, 53/255, 0, 0, 0}, }, }}) } local eventFrame = CreateFrame("Frame", "NinjaPanelEventFrame", UIParent) eventFrame:RegisterEvent("ADDON_LOADED") eventFrame:SetScript("OnEvent", function(self, event, arg1, ...) if arg1 == "NinjaPanel" and event == "ADDON_LOADED" then self:UnregisterEvent("ADDON_LOADED") -- TODO: Set this to actually use the SV NinjaPanel.db = options NinjaPanel.panels = {} NinjaPanel:SpawnPanel("NinjaPanelTop", "TOP") NinjaPanel:SpawnPanel("NinjaPanelBottom", "BOTTOM") NinjaPanel:SpawnPanel("NinjaPanelRight", "RIGHT") NinjaPanel:SpawnPanel("NinjaPanelLeft", "LEFT") --ldb.RegisterCallback(NinjaPanel, "LibDataBroker_DataObjectCreated", "ScanForPlugins") end end) function NinjaPanel:SpawnPanel(name, position) local panel = CreateFrame("Frame", name, eventFrame) panel.bg = panel:CreateTexture(name .. "BG", "BACKGROUND") panel.border = panel:CreateTexture(name .. "Border", "BACKGROUND") panel.boxes = {} panel.left = CreateFrame("Button", nil, panel) panel.center = CreateFrame("Button", nil, panel) panel.right = CreateFrame("Button", nil, panel) panel.left.bg = panel.left:CreateTexture(nil, "BACKGROUND") panel.center.bg = panel.center:CreateTexture(nil, "BACKGROUND") panel.right.bg = panel.right:CreateTexture(nil, "BACKGROUND") panel.name = name panel.position = position local horizontal = (position == "TOP") or (position == "BOTTOM") local opts = self.db.panels[position] local anch = opts.anchors -- Anchor the panel in place panel:ClearAllPoints() panel:SetPoint(anch[1], UIParent, anch[1], opts.offsets[1], opts.offsets[2]) panel:SetPoint(anch[2], UIParent, anch[2], opts.offsets[3], opts.offsets[4]) local size = opts.sizes[1] + opts.sizes[2] if horizontal then panel:SetHeight(size) else panel:SetWidth(size) end -- Set the gradient/texture for the background panel.bg:SetTexture(1, 1, 1, 0.8) panel.bg:SetGradient(unpack(opts.gradient)) if horizontal then panel.bg:SetHeight(size) else panel.bg:SetWidth(size) end -- Set the border gradient/texture panel.border:SetTexture(1, 1, 1, 0.8) panel.border:SetGradient(unpack(opts.bgradient)) panel.border:SetPoint(anch[1], panel.bg, anch[3], opts.offsets[1], opts.offsets[2]) panel.border:SetPoint(anch[2], panel.bg, anch[4], opts.offsets[3], opts.offsets[4]) if horizontal then panel.border:SetHeight(opts.sizes[2]) else panel.border:SetWidth(opts.sizes[2]) end -- Anchor the drag receive boxes panel.left:SetPoint(anch[1]) panel.center:SetPoint("CENTER") panel.right:SetPoint(anch[2]) -- Spawn a test button on the panel local button = self:SpawnButton(name .. "Test") button:SetHeight(opts.sizes[1]) button.icon:SetPoint("LEFT", 2, 0) button.icon:SetWidth(opts.sizes[3]) button.icon:SetHeight(opts.sizes[4]) --button.text:SetHeight(opts[5]) --button.text:SetPoint("LEFT", button.icon, "RIGHT", 2) button:SetWidth(button.icon:GetWidth() + 4) button:SetPoint("LEFT", panel, "LEFT") button:SetParent(panel) table.insert(self.panels, panel) return panel end function NinjaPanel:SpawnButton(name) local button = CreateFrame("Button", "NinjaPanelButton_" .. name, eventFrame) button.icon = button:CreateTexture(nil, "BACKGROUND") button.text = button:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall") button.text:SetText("Test Button") button.icon:SetTexture("Interface\\Icons\\INV_RoseBouquet01") button:RegisterForClicks("AnyUp") button:SetMovable(true) return button end -- Local functions that are defined below local SortWeightName local Button_OnEnter, Button_OnLeave local Button_OnDragStart, Button_OnDragStop, Button_OnUpdateDragging local Button_Tooltip_OnEnter, Button_Tooltip_OnLeave local Panel_UpdateLayout function NinjaPanel:ActivateDragBoxes() for idx,panel in ipairs(self.panels) do print("Updating drag boxes for panel: " .. panel.name) panel.left.bg:SetTexture(1, 1, 1, 0.6) panel.center.bg:SetTexture(1, 1, 1, 0.6) panel.right.bg:SetTexture(1, 1, 1, 0.6) end end function NinjaPanel:HasPlugin(name) return self.plugins[name] and true end function NinjaPanel:SpawnPlugin(name, object, type) db.plugins[name] = db.plugins[name] or {} local opts = setmetatable(db.plugins[name], { __index = { weight = 0, alignRight = false, } }) local entry = {} self.plugins[name] = entry entry.type = type entry.object = object entry.name = name entry.weight = opts.weight -- Push all of the launchers to the right-hand side if object.type == "launcher" and rawget(opts, "alignRight") == nil then entry.alignRight = true else entry.alignRight = opts.alignRight end local button = CreateFrame("Button", "NinjaPanelButton_" .. name, eventFrame) button.icon = button:CreateTexture(nil, "BACKGROUND") button.text = button:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall") button.entry = entry button.object = object button:RegisterForClicks("AnyUp") button:SetMovable(true) entry.button = button ldb.RegisterCallback(self, "LibDataBroker_AttributeChanged_" .. name, "UpdatePlugin") end function NinjaPanel:PluginIsDisabled(name) if db.plugins[name] then return db.plugins[name].disabled else return false end end function NinjaPanel:ScanForPlugins() self.warned = self.warned or {} for name,dataobj in ldb:DataObjectIterator() do -- Make sure we add it to the full list of plugin names if not self.pluginNames[name] then self.pluginNames[name] = true table.insert(self.pluginNames, name) end -- Create any plugins that aren't disabled if not self:HasPlugin(name) and not self:PluginIsDisabled(name) then if dataobj.type == "data source" or dataobj.text then self:SpawnPlugin(name, dataobj, "data source") elseif dataobj.type == "launcher" or (dataobj.icon and dataobj.OnClick) then self:SpawnPlugin(name, dataobj, "launcher") elseif not self.warned[name] then print("Skipping unknown broker object for " .. name .. "(" .. tostring(dataobj.type) .. ")") self.warned[name] = true end end end self:UpdatePanels() end function NinjaPanel:UpdateButtonWidth(button) local iconWidth = button.icon:IsShown() and button.icon:GetWidth() or 0 local textWidth = button.text:IsShown() and button.text:GetWidth() or 0 button:SetWidth(textWidth + iconWidth + ((textWidth > 0) and 9 or 3)) end function NinjaPanel:UpdatePlugin(event, name, key, value, dataobj) -- name: The name of the plugin being updated -- key: The key that was updated in the plugin -- value: The new value of the given key -- dataobj: The actual data object -- Bail out early if necessary if not self:HasPlugin(name) then return end local entry = self.plugins[name] local button = entry.button if key == "text" then button.text:SetFormattedText("%s", value) self:UpdateButtonWidth(button) elseif key == "icon" then button.icon:SetTexture(value) elseif key == "tooltip" or key == "OnTooltipShow" or key == "OnEnter" or key == "OnLeave" then -- Update the tooltip handers on the frame self:UpdateTooltipHandlers(button, dataobj) elseif key == "OnClick" then button:SetScript("OnClick", value) end -- Update the icon coordinates if either the icon or the icon coords were if key == "icon" or key == "iconCoords" then -- Since the icon has changed, update texcoord and color if entry.object.iconCoords then button.icon:SetTexCoord(unpack(dataobj.iconCoords)) else button.icon:SetTexCoord(0, 1, 0, 1) end end -- Update the icon color if either the icon or the color attributes are changed if key == "icon" or key == "iconR" or key == "iconG" or key == "iconB" then if entry.object.iconR then local r = dataobj.iconR or 1 local g = dataobj.iconG or 1 local b = dataobj.iconB or 1 button.icon:SetVertexColor(r, g, b) else button.icon:SetVertexColor(1, 1, 1) end end end function NinjaPanel:UpdateTooltipHandlers(button, dataobj) -- It’s possible that a source addon may provide more that one tooltip method. -- The display addon should only use one of these (even if it support all -- three in the spec). The generally preferred order is: tooltip > -- OnEnter/OnLeave > OnTooltipShow. -- Generally speaking, tooltip is not likely to be implemented along with -- another render method. OnEnter may also provide (and use) OnTooltipShow, in -- this case it’s usually preferred that the display simply set the OnEnter -- handler directly to the frame, thus bypassing the display’s tooltip -- handling code and never calling OnTooltipShow from the display. if dataobj.tooltip then button:SetScript("OnEnter", Button_Tooltip_OnEnter) button:SetScript("OnLeave", Button_Tooltip_OnLeave) elseif dataobj.OnEnter and dataobj.OnLeave then button:SetScript("OnEnter", dataobj.OnEnter) button:SetScript("OnLeave", dataobj.OnLeave) elseif dataobj.OnTooltipShow then button:SetScript("OnEnter", Button_OnEnter) button:SetScript("OnLeave", Button_OnLeave) end end function NinjaPanel:UpdatePanels() -- Ensure the options table exists db.panels = db.panels or {} -- Iterate over the plugins that have been registered, and claim children local head = self.panels[1] for name,entry in pairs(self.plugins) do local opt = db.plugins[name] if not entry.panel then opt.panel = opt.panel and self.panels[opt.panel] or head end self:AttachPlugin(entry, opt.panel) end -- Loop through each of the panels, updating the visual display for idx,panel in ipairs(self.panels) do local name = panel.name db.panels[name] = db.panels[name] or {} local opt = db.panels[name] setmetatable(opt, { __index = { height = 15, border_height = 1, gradient = {0.2, 0.2, 0.2, 1.0, 0, 0, 0, 1.0}, gradient_dir = "VERTICAL", border_gradient = {203 / 255, 161 / 255, 53 / 255, 1.0, 0, 0, 0, 1.0}, border_gradient_dir = "HORIZONTAL", } }) -- DEFAULT OPTIONS HERE --[[ local height = opt.height local border_height = opt.border_height local gradient = opt.gradient local gradient_dir = opt.gradient_dir local border_gradient = opt.border_gradient local border_gradient_dir = opt.border_gradient_dir panel:SetHeight(height + border_height) panel.bg:SetHeight(height) panel.border:SetHeight(border_height) panel.bg:SetGradientAlpha(gradient_dir, unpack(gradient)) panel.border:SetGradientAlpha(border_gradient_dir, unpack(border_gradient)) --]] end -- Update the plugins on each panel for idx,panel in ipairs(self.panels) do Panel_UpdateLayout(panel) end end function NinjaPanel:AttachPlugin(plugin, panel) panel.plugins[plugin.name] = plugin plugin.panel = panel plugin.button:SetParent(panel) end function NinjaPanel:DetachPlugin(plugin) plugin.panel.plugins[plugin.name] = nil plugin.panel = nil plugin.button:ClearAllPoints() plugin.button:Hide() end function NinjaPanel:HardAnchorPlugins() for idx,panel in ipairs(self.panels) do local opt = db.panels[panel.name] local yoffset = opt.border_height for name,entry in pairs(panel.plugins) do local button = entry.button local left = button:GetLeft() button:ClearAllPoints() button:SetPoint("LEFT", panel, "LEFT", left, 0) end end end function Panel_UpdateLayout(self) local left, right = {}, {} -- Loop through all of the plugins in the given panel for name,entry in pairs(self.plugins) do local panel_opts = db.panels[self.name] table.insert(entry.alignRight and right or left, entry) local button = entry.button local height = panel_opts.height - (panel_opts.border_height * 2) button:SetHeight(height) button:Show() if entry.object.icon then -- Actually update the layout of the button button.icon:SetHeight(height) button.icon:SetWidth(height) button.icon:SetTexture(entry.object.icon) button.icon:ClearAllPoints() button.icon:SetPoint("LEFT", button, "LEFT", 3, panel_opts.border_height) button.icon:Show() -- Run a SetTexCoord on the icon if .iconCoords is set if entry.object.iconCoords then button.icon:SetTexCoord(unpack(entry.object.iconCoords)) else button.icon:SetTexCoord(0, 1, 0, 1) end if entry.object.iconR or entry.object.iconG or entry.object.iconB then local r = entry.object.iconR or 1.0 local g = entry.object.iconG or 1.0 local b = entry.object.iconB or 1.0 button.icon:SetVertexColor(r, g, b) end else button.icon:Hide() end NinjaPanel:UpdateTooltipHandlers(button, entry.object) button:SetScript("OnClick", entry.object.OnClick) button:SetScript("OnDragStart", Button_OnDragStart) button:SetScript("OnDragStop", Button_OnDragStop) button:RegisterForDrag("LeftButton") button.text:SetText(entry.object.text or "Waiting...") button.text:SetHeight(height) button.text:ClearAllPoints() if button.icon:IsShown() then button.text:SetPoint("LEFT", button.icon, "RIGHT", 5, 0) else button.text:SetPoint("LEFT", button, "LEFT", 3, panel_opts.border_height) end if entry.object.type == "launcher" then -- Hide the text button.text:Hide() else button.text:Show() end NinjaPanel:UpdateButtonWidth(button) end -- Sort the list of plugins into left/right table.sort(left, SortWeightName) table.sort(right, SortWeightName) -- Anchor everything that is left-aligned for idx,entry in ipairs(left) do local button = entry.button button:ClearAllPoints() if idx == 1 then button:SetPoint("LEFT", self, "LEFT", 3, 0) else button:SetPoint("LEFT", left[idx-1].button, "RIGHT", 3, 0) end end -- Anchor everything that is right-aligned for idx,entry in ipairs(right) do local button = entry.button button:ClearAllPoints() if idx == 1 then button:SetPoint("RIGHT", self, "RIGHT", -3, 0) else button:SetPoint("RIGHT", right[idx-1].button, "LEFT", -3, 0) end end end --[[----------------------------------------------------------------------- -- Locally defined functions -----------------------------------------------------------------------]]-- function SortWeightName(a,b) if a.weight and b.weight then return a.weight < b.weight else return a.name < b.name end end function Button_OnEnter(self, ...) GameTooltip:SetOwner(self, "ANCHOR_NONE") GameTooltip:SetPoint("TOPLEFT", self, "BOTTOMLEFT") GameTooltip:ClearLines() if self.object.OnTooltipShow then self.object.OnTooltipShow(GameTooltip) else GameTooltip:SetText(self.entry.name) end GameTooltip:Show() end function Button_OnLeave(self, ...) GameTooltip:Hide() end function Button_OnUpdateDragging(self, elapsed) self:ClearAllPoints() local left, right = GetCursorPosition() left = left / self:GetEffectiveScale() self:SetPoint("LEFT", self:GetParent(), "LEFT", left, 0) end function Button_OnDragStart(self, button, ...) NinjaPanel:HardAnchorPlugins() self:SetToplevel(true) self:SetScript("OnUpdate", Button_OnUpdateDragging) self.origLeft = self:GetLeft() end function Button_OnDragStop(self, button, ...) self:SetScript("OnUpdate", nil) self:StopMovingOrSizing() local p = self:GetParent() local left, right = {}, {} for name,entry in pairs(p.plugins) do if entry.button ~= self then table.insert(entry.alignRight and right or left, entry) end end table.sort(left, SortWeightName) table.sort(right, SortWeightName) local newLeft, newRight = self:GetLeft(), self:GetRight() local alignRight = false local leftPos, rightPos = {}, {} -- Store the positions for the right-most plugins first for idx,entry in ipairs(right) do rightPos[entry] = entry.button:GetLeft() end -- Store the positions for the left-most plugins for idx,entry in ipairs(left) do leftPos[entry] = entry.button:GetRight() end -- If we are moving to the right if self.origLeft <= newLeft then -- Check to see if we're on the right-hand side of the panel for idx, entry in ipairs(right) do if newRight > rightPos[entry] then rightPos[self.entry] = rightPos[entry] + 1 alignRight = true break end end if not alignRight then for idx=#left, 1, -1 do local entry = left[idx] if newRight > entry.button:GetLeft() and newRight <= entry.button:GetRight() then leftPos[self.entry] = leftPos[entry] + 1 alignRight = false break end end end else -- We are moving to the left -- Check to see if we're on the right-hand side of the panel if right[1] and newLeft > right[#right].button:GetLeft() then for idx=#right, 1, -1 do local entry = right[idx] if newLeft < entry.button:GetRight() then rightPos[self.entry] = rightPos[entry] - 1 alignRight = true break end end end if not alignRight then for idx,entry in ipairs(left) do if newLeft < leftPos[entry] then leftPos[self.entry] = leftPos[entry] - 1 alignRight = false break end end end end -- If we didn't get a position above if not leftPos[self.entry] and not rightPos[self.entry] then -- Handle the case where we're the first plugin to go to the right local panelRight = p:GetRight() if newRight >= panelRight - 100 then rightPos[self.entry] = panelRight alignRight = true end -- Handle the case where we're the first plugin to go to the left if not alignRight then if newLeft <= 100 then leftPos[self.entry] = 0 alignRight = false else -- Otherwise, just tag it onto the right of the left leftPos[self.entry] = panelRight alignRight = false end end end table.insert(alignRight and right or left, self.entry) self.entry.alignRight = alignRight table.sort(left, function(a,b) return leftPos[a] < leftPos[b] end) table.sort(right, function(a,b) return rightPos[a] > rightPos[b] end) for idx,entry in ipairs(left) do entry.weight = idx end for idx,entry in ipairs(right) do entry.weight = idx end -- Save the new weight information out to the database if not NinjaPanelDB.plugins then NinjaPanelDB.plugins = {} end local opts = NinjaPanelDB.plugins for name,entry in pairs(p.plugins) do opts[name].weight = entry.weight opts[name].enabled = entry.enabled opts[name].alignRight = entry.alignRight end Panel_UpdateLayout(p) end function Button_Tooltip_OnEnter(button) local tooltip = button.object.tooltip tooltip:ClearAllPoints() tooltip:SetPoint("TOPLEFT", button, "BOTTOMLEFT", 0, 0) tooltip:Show() end function Button_Tooltip_OnLeave(button) local tooltip = button.object.tooltip tooltip:Hide() end --[[------------------------------------------------------------------------- -- Interface Options using tekConfig with Ampere's code example -------------------------------------------------------------------------]]-- local frame = CreateFrame("Frame", nil, InterfaceOptionsFramePanelContainer) frame.name = "NinjaPanel" frame:Hide() frame:SetScript("OnShow", function(frame) local function MakeButton(parent) local button = CreateFrame("Button", nil, parent or frame) button:SetWidth(80) button:SetHeight(22) button:SetHighlightFontObject(GameFontHighlightSmall) button:SetNormalFontObject(GameFontNormalSmall) button:SetNormalTexture("Interface\\Buttons\\UI-Panel-Button-Up") button:SetPushedTexture("Interface\\Buttons\\UI-Panel-Button-Down") button:SetHighlightTexture("Interface\\Buttons\\UI-Panel-Button-Highlight") button:SetDisabledTexture("Interface\\Buttons\\UI-Panel-Button-Disabled") button:GetNormalTexture():SetTexCoord(0, 0.625, 0, 0.6875) button:GetPushedTexture():SetTexCoord(0, 0.625, 0, 0.6875) button:GetHighlightTexture():SetTexCoord(0, 0.625, 0, 0.6875) button:GetDisabledTexture():SetTexCoord(0, 0.625, 0, 0.6875) button:GetHighlightTexture():SetBlendMode("ADD") return button end local title = frame:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge") title:SetPoint("TOPLEFT", 16, -16) title:SetText("NinjaPanel Configuration") local subtitle = frame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall") --~ subtitle:SetHeight(32) subtitle:SetHeight(35) subtitle:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -8) subtitle:SetPoint("RIGHT", frame, -32, 0) subtitle:SetNonSpaceWrap(true) subtitle:SetJustifyH("LEFT") subtitle:SetJustifyV("TOP") --~ subtitle:SetMaxLines(3) subtitle:SetText("This panel can be used to configure the NinjaPanel LDB display.") local rows, anchor = {} local EDGEGAP, ROWHEIGHT, ROWGAP, GAP = 16, 20, 2, 4 local function OnEnter(self) local type = NinjaPanel.plugins[self.name].object.type or "Unknown" GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT") GameTooltip:AddLine(self.name, nil, nil, nil, true) GameTooltip:AddLine(type, 1, 1, 1, true) GameTooltip:Show() end local function OnLeave() GameTooltip:Hide() end local function OnClick(self) local opts = NinjaPanelDB.plugins[self.name] local plugin = NinjaPanel.plugins[self.name] if opts.disabled then opts.disabled = nil else opts.disabled = true NinjaPanel:DetachPlugin(plugin) end PlaySound(enabled and "igMainMenuOptionCheckBoxOff" or "igMainMenuOptionCheckBoxOn") NinjaPanel:ScanForPlugins() Refresh() end -- Create rows for each option for i=1,math.floor((305-22)/(ROWHEIGHT + ROWGAP)) do local row = CreateFrame("Button", nil, frame) if not anchor then row:SetPoint("TOP", subtitle, "BOTTOM", 0, -16) else row:SetPoint("TOP", anchor, "BOTTOM", 0, -ROWGAP) end row:SetPoint("LEFT", EDGEGAP, 0) row:SetPoint("RIGHT", -EDGEGAP*2-8, 0) row:SetHeight(ROWHEIGHT) anchor = row rows[i] = row local check = CreateFrame("CheckButton", nil, row) check:SetWidth(ROWHEIGHT+4) check:SetHeight(ROWHEIGHT+4) check:SetPoint("LEFT") check:SetNormalTexture("Interface\\Buttons\\UI-CheckBox-Up") check:SetPushedTexture("Interface\\Buttons\\UI-CheckBox-Down") check:SetHighlightTexture("Interface\\Buttons\\UI-CheckBox-Highlight") check:SetDisabledCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check-Disabled") check:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check") check:SetScript("OnClick", OnClick) row.check = check local title = row:CreateFontString(nil, "BACKGROUND", "GameFontNormal") title:SetPoint("LEFT", check, "RIGHT", 4, 0) row.title = title local status = row:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall") status:SetPoint("RIGHT", row, "RIGHT", -4, 0) status:SetPoint("LEFT", title, "RIGHT") status:SetJustifyH("RIGHT") row.status = status row:SetScript("OnEnter", OnEnter) row:SetScript("OnLeave", OnLeave) end local statusColors = { [true] = {0.1, 1.0, 0.1}, [false] = {1.0, 0.1, 0.1}, } local offset = 0 Refresh = function() if not frame:IsVisible() then return end table.sort(NinjaPanel.pluginNames) for i,row in ipairs(rows) do if (i + offset) <= #NinjaPanel.pluginNames then local name = NinjaPanel.pluginNames[i + offset] local entry = NinjaPanel.plugins[name] local opts = NinjaPanelDB.plugins[name] local enabled = not opts.disabled local color = statusColors[enabled] row.check:SetChecked(enabled) row.title:SetText(name) row.status:SetText(enabled and "Enabled" or "Disabled") row.status:SetTextColor(unpack(color)) row.name = name row.check.name = name row:Show() else row:Hide() end end end frame:SetScript("OnEvent", Refresh) frame:RegisterEvent("ADDON_LOADED") frame:SetScript("OnShow", Refresh) Refresh() local scrollbar = LibStub("tekKonfig-Scroll").new(frame, nil, #rows/2) scrollbar:ClearAllPoints() scrollbar:SetPoint("TOP", rows[1], 0, -16) scrollbar:SetPoint("BOTTOM", rows[#rows], 0, 16) scrollbar:SetPoint("RIGHT", -16, 0) scrollbar:SetMinMaxValues(0, math.max(0, #NinjaPanel.pluginNames - #rows)) scrollbar:SetValue(0) local f = scrollbar:GetScript("OnValueChanged") scrollbar:SetScript("OnValueChanged", function(self, value, ...) offset = value Refresh() return f(self, value, ...) end) frame:EnableMouseWheel() frame:SetScript("OnMouseWheel", function(self, val) scrollbar:SetValue(scrollbar:GetValue() - val*#rows/2) end) local enableall = MakeButton() enableall:SetPoint("BOTTOMLEFT", 16, 16) enableall:SetText("Enable All") enableall:SetScript("OnClick", function(button) for idx,name in ipairs(NinjaPanel.pluginNames) do NinjaPanelDB.plugins[name].disabled = nil end Refresh() end) local disableall = MakeButton() disableall:SetPoint("LEFT", enableall, "RIGHT", 4, 0) disableall:SetText("Disable All") disableall:SetScript("OnClick", function(button) for idx,name in ipairs(NinjaPanel.pluginNames) do NinjaPanelDB.plugins[name].disabled = true end Refresh() end) local reload = MakeButton() reload:SetPoint("BOTTOMRIGHT", -16, 16) reload:SetText("Refresh") reload:SetScript("OnClick", ReloadUI) end) InterfaceOptions_AddCategory(frame) LibStub("tekKonfig-AboutPanel").new("NinjaPanel", "NinjaPanel") ---------------------------------------- -- Quicklaunch registration -- ---------------------------------------- -- Icon provided by NinjaKiller (http://ninjakiller.deviantart.com/art/Ninja-Icon-Package-01-56129382) local dataobj = LibStub:GetLibrary("LibDataBroker-1.1"):NewDataObject("NinjaPanel-Launcher", { type = "launcher", icon = "Interface\\AddOns\\NinjaPanel\\NinjaLogo", OnClick = function() InterfaceOptionsFrame_OpenToCategory(frame) end, })