diff --git a/Config.lua b/Config.lua index 2e01a1d..025eeab 100644 --- a/Config.lua +++ b/Config.lua @@ -4,9 +4,20 @@ F.Config = { -- Display Options showAtMaxLevel = false, showIncompleteQuestBar = true, + questTrackingEnabled = true, -- Master visibility toggle (can be flipped with /nxp toggle) enabled = true, + -- Bar Size + barWidth = 600, + barHeight = 24, + + -- Bar Colors (RGBA) + colorMain = { r = 0.76, g = 0.38, b = 1, a = 1 }, + colorRested = { r = 0.34, g = 0.61, b = 0.99, a = 0.8 }, + colorQuest = { r = 1, g = 0.64, b = 0.0078, a = 0.25 }, + colorQuestComplete = { r = 1, g = 0.64, b = 0.0078, a = 0.8 }, + -- Text Toggles showLevelText = true, showXPText = true, diff --git a/NixxnuxXPBar.toc b/NixxnuxXPBar.toc index c8bd2c6..522034e 100644 --- a/NixxnuxXPBar.toc +++ b/NixxnuxXPBar.toc @@ -15,6 +15,7 @@ ## Author: Nixxnux ## Category: Interface Enhancements ## IconTexture: Interface\Icons\Inv_cape_special_treasure_c_01 +## SavedVariables: NXP_DB Init.lua Config.lua diff --git a/Options.lua b/Options.lua index d164ae2..84656bc 100644 --- a/Options.lua +++ b/Options.lua @@ -3,7 +3,17 @@ local _, F = ... F.Options = F.Options or {} local panel +local content local controls = {} +local questRelatedKeys = { + trackedOnly = true, + showQuestRestedText = true, + showIncompleteQuestXPText = true, + showCompletedQuestXPText = true, + showIncompleteQuestBar = true, + colorQuest = true, + colorQuestComplete = true, +} local function SetOption(key, value) if F.InitDB then F.InitDB() end @@ -25,6 +35,44 @@ local function SetOption(key, value) end if F.UpdateUI then F.UpdateUI() end + + if key == "questTrackingEnabled" or key == "trackedOnly" then + if F.State and F.State.UpdateQuestXP then + F.State:UpdateQuestXP() + end + if key == "questTrackingEnabled" and panel and panel:IsShown() then + F.Options.Refresh() + end + end +end + +local function SetNumericOption(key, value) + if F.InitDB then F.InitDB() end + if not F.DB then return end + F.DB[key] = value + if F.UpdateUI then F.UpdateUI() end +end + +local function SetColorOption(key, r, g, b, a) + if F.InitDB then F.InitDB() end + if not F.DB then return end + F.DB[key] = { r = r, g = g, b = b, a = a } + if F.UpdateUI then F.UpdateUI() end +end + +local function GetColorOption(key, fallback) + if F.InitDB then F.InitDB() end + if not F.DB then return fallback[1], fallback[2], fallback[3], fallback[4] end + local color = F.DB[key] + if type(color) == "table" then + if color.r then + return color.r or 1, color.g or 1, color.b or 1, color.a or 1 + end + if color[1] then + return color[1] or 1, color[2] or 1, color[3] or 1, color[4] or 1 + end + end + return fallback[1], fallback[2], fallback[3], fallback[4] end local function CreateHeader(parent, text, y) @@ -42,16 +90,159 @@ local function CreateCheckbox(parent, key, label, y) SetOption(key, self:GetChecked()) end) - controls[key] = cb + controls[key] = { type = "checkbox", widget = cb } return y - 28 end +local function CreateSlider(parent, key, label, y, minValue, maxValue, step) + local name = "NXP_Options_" .. key .. "Slider" + local slider = CreateFrame("Slider", name, parent, "OptionsSliderTemplate") + slider:SetPoint("TOPLEFT", parent, "TOPLEFT", 16, y) + slider:SetMinMaxValues(minValue, maxValue) + slider:SetValueStep(step) + slider:SetObeyStepOnDrag(true) + + local labelText = _G[name .. "Text"] + local lowText = _G[name .. "Low"] + local highText = _G[name .. "High"] + if labelText then labelText:SetText(label) end + if lowText then lowText:SetText(tostring(minValue)) end + if highText then highText:SetText(tostring(maxValue)) end + + slider:SetScript("OnValueChanged", function(self, value) + if self._updating then return end + local rounded = math.floor(value + 0.5) + if step and step < 1 then + rounded = value + end + self._updating = true + self:SetValue(rounded) + self._updating = false + SetNumericOption(key, rounded) + end) + + controls[key] = { type = "slider", widget = slider } + return y - 52 +end + +local function CreateColorPicker(parent, key, label, y, fallback) + local labelText = parent:CreateFontString(nil, "ARTWORK", "GameFontHighlight") + labelText:SetPoint("TOPLEFT", parent, "TOPLEFT", 16, y) + labelText:SetText(label) + + local swatch = CreateFrame("Button", nil, parent) + swatch:SetSize(16, 16) + swatch:SetPoint("LEFT", labelText, "RIGHT", 8, 0) + swatch:SetNormalTexture("Interface\\Buttons\\WHITE8x8") + swatch:SetHighlightTexture("Interface\\Buttons\\WHITE8x8", "ADD") + local swatchTex = swatch:GetNormalTexture() + + local border = swatch:CreateTexture(nil, "BORDER") + border:SetPoint("TOPLEFT", swatch, "TOPLEFT", -1, 1) + border:SetPoint("BOTTOMRIGHT", swatch, "BOTTOMRIGHT", 1, -1) + border:SetColorTexture(0, 0, 0, 1) + if swatchTex then + swatchTex:SetPoint("TOPLEFT", swatch, "TOPLEFT", 1, -1) + swatchTex:SetPoint("BOTTOMRIGHT", swatch, "BOTTOMRIGHT", -1, 1) + end + + swatch:SetScript("OnClick", function() + local r, g, b, a = GetColorOption(key, fallback) + local previous = { r = r, g = g, b = b, a = a } + + local function getPickerAlpha() + if ColorPickerFrame.GetColorAlpha then + return ColorPickerFrame:GetColorAlpha() + end + return 1 - (ColorPickerFrame.opacity or 0) + end + + local function applyColor() + local nr, ng, nb = ColorPickerFrame:GetColorRGB() + local na = getPickerAlpha() + SetColorOption(key, nr, ng, nb, na) + F.Options.Refresh() + end + + local function cancelColor() + local pv = previous + if pv then + SetColorOption(key, pv.r, pv.g, pv.b, pv.a) + F.Options.Refresh() + end + end + + if ColorPickerFrame.SetupColorPickerAndShow then + ColorPickerFrame:SetupColorPickerAndShow({ + r = r, + g = g, + b = b, + opacity = 1 - (a or 1), + hasOpacity = true, + swatchFunc = applyColor, + opacityFunc = applyColor, + cancelFunc = cancelColor, + }) + else + ColorPickerFrame.hasOpacity = true + ColorPickerFrame.opacity = 1 - (a or 1) + ColorPickerFrame.previousValues = previous + ColorPickerFrame.func = applyColor + ColorPickerFrame.opacityFunc = applyColor + ColorPickerFrame.cancelFunc = cancelColor + ColorPickerFrame:SetColorRGB(r, g, b) + ColorPickerFrame:Hide() + ColorPickerFrame:Show() + end + end) + + controls[key] = { type = "color", widget = swatch, label = labelText, fallback = fallback } + return y - 24 +end + function F.Options.Refresh() if F.InitDB then F.InitDB() end if not F.DB then return end - for key, cb in pairs(controls) do - cb:SetChecked(F.DB[key] and true or false) + local defaults = F.Config or {} + + for key, control in pairs(controls) do + if control.type == "checkbox" then + control.widget:SetChecked(F.DB[key] and true or false) + elseif control.type == "slider" then + local value = F.DB[key] + if value == nil then value = defaults[key] end + if value == nil then value = 0 end + control.widget._updating = true + control.widget:SetValue(tonumber(value) or 0) + control.widget._updating = false + elseif control.type == "color" then + local r, g, b, a = GetColorOption(key, control.fallback) + local tex = control.widget:GetNormalTexture() + if tex then tex:SetColorTexture(r, g, b, a) end + end + end + + local questEnabled = F.DB.questTrackingEnabled ~= false + for key, _ in pairs(questRelatedKeys) do + local control = controls[key] + if control then + if control.type == "checkbox" or control.type == "slider" then + control.widget:SetEnabled(questEnabled) + if control.widget.Text then + local color = questEnabled and NORMAL_FONT_COLOR or GRAY_FONT_COLOR + control.widget.Text:SetTextColor(color.r, color.g, color.b) + end + elseif control.type == "color" then + if questEnabled then + control.widget:Enable() + control.label:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b) + else + control.widget:Disable() + control.label:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b) + end + end + end end end @@ -72,25 +263,50 @@ function F.Options.Create() panel = CreateFrame("Frame", "NXP_OptionsPanel", UIParent) panel.name = "NixxnuxXPBar" - local title = panel:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge") - title:SetPoint("TOPLEFT", panel, "TOPLEFT", 16, -16) + local scroll = CreateFrame("ScrollFrame", "NXP_OptionsScrollFrame", panel, "UIPanelScrollFrameTemplate") + scroll:SetPoint("TOPLEFT", panel, "TOPLEFT", 0, -8) + scroll:SetPoint("BOTTOMRIGHT", panel, "BOTTOMRIGHT", -30, 8) + + content = CreateFrame("Frame", nil, scroll) + content:SetSize(1, 1) + scroll:SetScrollChild(content) + + local title = content:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge") + title:SetPoint("TOPLEFT", content, "TOPLEFT", 16, -8) title:SetText("NixxnuxXPBar") - local y = -48 - y = CreateHeader(panel, "General", y) - y = CreateCheckbox(panel, "enabled", "Enable addon", y) - y = CreateCheckbox(panel, "trackedOnly", "Count tracked (pinned) quests only", y) + local y = -40 + y = CreateHeader(content, "General", y) + y = CreateCheckbox(content, "enabled", "Enable addon", y) + y = CreateCheckbox(content, "questTrackingEnabled", "Enable quest tracking", y) + y = CreateCheckbox(content, "trackedOnly", "Count tracked (pinned) quests only", y) + y = CreateCheckbox(content, "showIncompleteQuestBar", "Show uncompleted quest XP bar", y) + + y = y - 10 + y = CreateHeader(content, "Bar Size", y) + y = y - 6 + y = CreateSlider(content, "barWidth", "Bar width", y, 200, 900, 1) + y = CreateSlider(content, "barHeight", "Bar height", y, 8, 60, 1) + + y = y - 6 + y = CreateHeader(content, "Bar Colors", y) + y = CreateColorPicker(content, "colorMain", "Normal XP", y, { 0.76, 0.38, 1, 1 }) + y = CreateColorPicker(content, "colorRested", "Rested XP", y, { 0.34, 0.61, 0.99, 0.8 }) + y = CreateColorPicker(content, "colorQuest", "Uncompleted Quest XP", y, { 1, 0.64, 0.0078, 0.25 }) + y = CreateColorPicker(content, "colorQuestComplete", "Completed Quest XP", y, { 1, 0.64, 0.0078, 0.8 }) y = y - 10 - y = CreateHeader(panel, "Text Labels", y) - y = CreateCheckbox(panel, "showLevelText", "Level text", y) - y = CreateCheckbox(panel, "showXPText", "XP text", y) - y = CreateCheckbox(panel, "showPercentText", "Percent text", y) - y = CreateCheckbox(panel, "showQuestRestedText", "Quest/rested percent text", y) - y = CreateCheckbox(panel, "showLevelingText", "Leveling info text", y) - y = CreateCheckbox(panel, "showIncompleteQuestXPText", "Uncompleted quest XP text", y) - y = CreateCheckbox(panel, "showCompletedQuestXPText", "Completed quest XP text", y) - y = CreateCheckbox(panel, "showRestedXPText", "Rested XP text", y) + y = CreateHeader(content, "Text Labels", y) + y = CreateCheckbox(content, "showLevelText", "Level text", y) + y = CreateCheckbox(content, "showXPText", "XP text", y) + y = CreateCheckbox(content, "showPercentText", "Percent text", y) + y = CreateCheckbox(content, "showQuestRestedText", "Quest/rested percent text", y) + y = CreateCheckbox(content, "showLevelingText", "Leveling info text", y) + y = CreateCheckbox(content, "showIncompleteQuestXPText", "Uncompleted quest XP text", y) + y = CreateCheckbox(content, "showCompletedQuestXPText", "Completed quest XP text", y) + y = CreateCheckbox(content, "showRestedXPText", "Rested XP text", y) + + content:SetHeight(-y + 20) panel:SetScript("OnShow", function() F.Options.Refresh() diff --git a/State.lua b/State.lua index a0a6d63..9f19964 100644 --- a/State.lua +++ b/State.lua @@ -65,6 +65,13 @@ function F.State:UpdatePlayerXP() end function F.State:UpdateQuestXP() + if F.DB and F.DB.questTrackingEnabled == false then + self.questXP = 0 + self.completeXP = 0 + self.incompleteXP = 0 + return + end + local numEntries = C_QuestLog.GetNumQuestLogEntries() local qXP, cXP, iXP = 0, 0, 0 diff --git a/UI.lua b/UI.lua index 30f339c..4923312 100644 --- a/UI.lua +++ b/UI.lua @@ -216,6 +216,29 @@ function F.UI.Update() local s = F.State local db = F.DB + if db and db.barWidth and db.barHeight then + F.Frame:SetSize(db.barWidth, db.barHeight) + end + + local function resolveColor(color, fallback) + if type(color) == "table" then + if color.r then + return color.r or 1, color.g or 1, color.b or 1, color.a or 1 + end + if color[1] then + return color[1] or 1, color[2] or 1, color[3] or 1, color[4] or 1 + end + end + return fallback[1], fallback[2], fallback[3], fallback[4] + end + + if db then + F.BarMain:SetStatusBarColor(resolveColor(db.colorMain, CFG.colorMain)) + F.BarRested:SetStatusBarColor(resolveColor(db.colorRested, CFG.colorRested)) + F.BarQuest:SetStatusBarColor(resolveColor(db.colorQuest, CFG.colorQuest)) + F.BarQuestComplete:SetStatusBarColor(resolveColor(db.colorQuestComplete, CFG.colorQuestComplete)) + end + if s.isMaxLevel and not db.showAtMaxLevel then F.Frame:Hide() return @@ -316,7 +339,7 @@ function F.UI.Update() local infoParts = {} if db.showQuestRestedText and s.maxXP > 0 then - if (s.completeXP or 0) > 0 then + if db.questTrackingEnabled ~= false and (s.completeXP or 0) > 0 then table.insert(infoParts, string.format("Completed Quests: %.1f%%", ((s.completeXP or 0) / s.maxXP * 100))) end if (s.restedXP or 0) > 0 then @@ -350,11 +373,13 @@ function F.UI.Update() do local xpParts = {} - if db.showIncompleteQuestXPText and (s.incompleteXP or 0) > 0 then - table.insert(xpParts, string.format("Uncompleted Quest XP: %s", FormatLargeNumber(s.incompleteXP or 0))) - end - if db.showCompletedQuestXPText and (s.completeXP or 0) > 0 then - table.insert(xpParts, string.format("Completed Quest XP: %s", FormatLargeNumber(s.completeXP or 0))) + if db.questTrackingEnabled ~= false then + if db.showIncompleteQuestXPText and (s.incompleteXP or 0) > 0 then + table.insert(xpParts, string.format("Uncompleted Quest XP: %s", FormatLargeNumber(s.incompleteXP or 0))) + end + if db.showCompletedQuestXPText and (s.completeXP or 0) > 0 then + table.insert(xpParts, string.format("Completed Quest XP: %s", FormatLargeNumber(s.completeXP or 0))) + end end if db.showRestedXPText and (s.restedXP or 0) > 0 then table.insert(xpParts, string.format("Rested XP: %s", FormatLargeNumber(s.restedXP or 0)))