From 02b55054431ce398117ba30a9b787323bdc35bdf Mon Sep 17 00:00:00 2001 From: pepopo978 Date: Mon, 27 May 2024 15:21:31 -0700 Subject: [PATCH] improve settings/ui and fix bugs --- core.lua | 14 +- filter.lua | 40 +++-- global.lua | 8 +- settings.lua | 306 +++++++++++++++++++++++++++++------ sounds/refresh.mp3 | Bin 0 -> 5318 bytes sounds/resist.mp3 | Bin 0 -> 42363 bytes ui.lua | 392 +++++++++++++++++++++++++-------------------- 7 files changed, 520 insertions(+), 240 deletions(-) create mode 100644 sounds/refresh.mp3 create mode 100644 sounds/resist.mp3 diff --git a/core.lua b/core.lua index 7f1bce7..3360e49 100644 --- a/core.lua +++ b/core.lua @@ -10,13 +10,12 @@ AURAADDEDSELFHARMFUL = "You are afflicted by %s (1)." AURAADDEDSELFHELPFUL = "You gain %s (1)." Cursive.core = CreateFrame("Frame", "Cursive", UIParent) -Cursive.core:RegisterEvent("ADDON_LOADED") Cursive.core.guids = {} Cursive.core.add = function(unit) local _, guid = UnitExists(unit) - if guid then + if guid and not UnitIsDead(unit) then Cursive.core.guids[guid] = GetTime() end end @@ -26,7 +25,9 @@ Cursive.core.addGuid = function(guid) if string.sub(guid, 1, 2) ~= "0x" then return end - Cursive.core.guids[guid] = GetTime() + if UnitExists(guid) and not UnitIsDead(guid) then + Cursive.core.guids[guid] = GetTime() + end end Cursive.core.remove = function(guid) @@ -47,12 +48,7 @@ Cursive.core.disable = function() end Cursive.core:SetScript("OnEvent", function() - if event == "ADDON_LOADED" and arg1 == "Cursive" then - Cursive.curses:LoadCurses() - if Cursive.db.profile.enabled then - Cursive.core.enable() - end - elseif event == "PLAYER_TARGET_CHANGED" then + if event == "PLAYER_TARGET_CHANGED" then this.add("target") else -- arg1 is guid diff --git a/filter.lua b/filter.lua index 5a214e0..f927883 100644 --- a/filter.lua +++ b/filter.lua @@ -2,12 +2,7 @@ if not Cursive.superwow then return end -local filter = { - "infight", - "alive", - "hostile", - "attackable", -} +local filter = {} filter.attackable = function(unit) return UnitCanAttack("player", unit) and true or false @@ -50,10 +45,20 @@ end Cursive.filter = filter function Cursive:ShouldDisplayGuid(guid) - local exists, targetGuid = UnitExists("target") + -- never display units that don't exist + if not UnitExists(guid) then + return false + end + + -- never display dead units + if not Cursive.filter.alive(guid) then + return false + end + + local _, targetGuid = UnitExists("target") -- always show target if attackable - if (targetGuid == guid) == true and filter.attackable(guid) then + if (targetGuid == guid) and filter.attackable(guid) then return true end @@ -65,11 +70,20 @@ function Cursive:ShouldDisplayGuid(guid) -- apply filters local shouldDisplay = true -- default to true - -- otherwise apply filters - for id, filter_name in pairs(Cursive.filter) do - if filter[filter_name] then - shouldDisplay = shouldDisplay and filter[filter_name](guid) - end + if Cursive.db.profile.filterincombat then + shouldDisplay = shouldDisplay and filter.infight(guid) + end + + if Cursive.db.profile.filterhostile then + shouldDisplay = shouldDisplay and filter.hostile(guid) + end + + if Cursive.db.profile.filterattackable then + shouldDisplay = shouldDisplay and filter.attackable(guid) + end + + if Cursive.db.profile.filterrange then + shouldDisplay = shouldDisplay and filter.range(guid) end return shouldDisplay diff --git a/global.lua b/global.lua index 58bada2..6197fed 100644 --- a/global.lua +++ b/global.lua @@ -11,7 +11,11 @@ if not GetPlayerBuffID or not CombatLogAdd or not SpellInfo then Cursive.superwow = false end --- onload -function Cursive:OnInitialize() +function Cursive:OnEnable() DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00Cursive:|cffffaaaa Loaded. /cursive for commands and minimap icon for options.") + + Cursive.curses:LoadCurses() + if Cursive.db.profile.enabled then + Cursive.core.enable() + end end diff --git a/settings.lua b/settings.lua index 7d66535..4aab9d6 100644 --- a/settings.lua +++ b/settings.lua @@ -5,20 +5,211 @@ end Cursive:RegisterDB("CursiveDB") Cursive:RegisterDefaults("profile", { enabled = true, + clickthrough = false, + showbackdrop = true, caption = "Cursive", anchor = "CENTER", x = -240, y = 120, - maxcol = 1, -- editable scale = 1, - width = 100, - height = 14, + healthwidth = 100, + height = 16, + raidiconsize = 16, + curseiconsize = 16, + maxcurses = 3, spacing = 4, maxrow = 10, + maxcol = 1, + textsize = 9, + + filterincombat = true, + filterhostile = true, + filterattackable = true, + filterrange = false, }) +local barOptions = { + ["barwidth"] = { + type = "range", + name = "Health Bar Width", + desc = "Health Bar Width", + order = 10, + min = 30, + max = 150, + step = 5, + get = function() + return Cursive.db.profile.healthwidth + end, + set = function(v) + if v ~= Cursive.db.profile.healthwidth then + Cursive.db.profile.healthwidth = v + Cursive.UpdateFramesFromConfig() + end + end, + }, + ["barheight"] = { + type = "range", + name = "Health Bar Height", + desc = "Health Bar Height", + order = 20, + min = 10, + max = 30, + step = 2, + get = function() + return Cursive.db.profile.height + end, + set = function(v) + if v ~= Cursive.db.profile.height then + Cursive.db.profile.height = v + Cursive.UpdateFramesFromConfig() + end + end, + }, + ["raidiconsize"] = { + type = "range", + name = "Raid Icon Size", + desc = "Raid Icon Size", + order = 30, + min = 10, + max = 30, + step = 1, + get = function() + return Cursive.db.profile.raidiconsize + end, + set = function(v) + if v ~= Cursive.db.profile.raidiconsize then + Cursive.db.profile.raidiconsize = v + Cursive.UpdateFramesFromConfig() + end + end, + }, + ["curseiconsize"] = { + type = "range", + name = "Curse Icon Size", + desc = "Curse Icon Size", + order = 40, + min = 10, + max = 30, + step = 1, + get = function() + return Cursive.db.profile.curseiconsize + end, + set = function(v) + if v ~= Cursive.db.profile.curseiconsize then + Cursive.db.profile.curseiconsize = v + Cursive.UpdateFramesFromConfig() + end + end, + }, + ["spacing"] = { + type = "range", + name = "Spacing", + desc = "Spacing", + order = 50, + min = 0, + max = 10, + step = 1, + get = function() + return Cursive.db.profile.spacing + end, + set = function(v) + if v ~= Cursive.db.profile.spacing then + Cursive.db.profile.spacing = v + Cursive.UpdateFramesFromConfig() + end + end, + }, + ["textsize"] = { + type = "range", + name = "Text Size", + desc = "Text Size", + order = 60, + min = 8, + max = 20, + step = 1, + get = function() + return Cursive.db.profile.textsize + end, + set = function(v) + if v ~= Cursive.db.profile.textsize then + Cursive.db.profile.textsize = v + Cursive.UpdateFramesFromConfig() + end + end, + }, + ["scale"] = { + type = "range", + name = "Scale", + desc = "Scale", + order = 70, + min = 0.5, + max = 2, + step = 0.1, + get = function() + return Cursive.db.profile.scale + end, + set = function(v) + if v ~= Cursive.db.profile.scale then + Cursive.db.profile.scale = v + Cursive.UpdateFramesFromConfig() + end + end, + }, +} + +local mobFilters = { + ["incombat"] = { + type = "toggle", + name = "In Combat", + desc = "In Combat", + order = 1, + get = function() + return Cursive.db.profile.filterincombat + end, + set = function(v) + Cursive.db.profile.filterincombat = v + end, + }, + ["hostile"] = { + type = "toggle", + name = "Hostile", + desc = "Hostile", + order = 2, + get = function() + return Cursive.db.profile.filterhostile + end, + set = function(v) + Cursive.db.profile.filterhostile = v + end, + }, + ["attackable"] = { + type = "toggle", + name = "Attackable", + desc = "Attackable", + order = 3, + get = function() + return Cursive.db.profile.filterattackable + end, + set = function(v) + Cursive.db.profile.filterattackable = v + end, + }, + ["range"] = { + type = "toggle", + name = "Within 28 Range", + desc = "Within 28 Range", + order = 4, + get = function() + return Cursive.db.profile.filterrange + end, + set = function(v) + Cursive.db.profile.filterrange = v + end, + }, +} + Cursive.cmdtable = { type = "group", handler = Cursive, @@ -40,56 +231,73 @@ Cursive.cmdtable = { end end, }, - ["barwidth"] = { - type = "range", - name = "Health Bar Width", - desc = "Health Bar Width", - order = 1, - min = 30, - max = 150, - step = 5, + ["clickthrough"] = { + type = "toggle", + name = "Allow clickthrough", + desc = "This will allow you to click through the frame to target mobs behind it, but prevents dragging the frame.", + order = 2, get = function() - return Cursive.db.profile.width + return Cursive.db.profile.clickthrough end, set = function(v) - Cursive.db.profile.width = v + Cursive.db.profile.clickthrough = v + Cursive.UpdateFramesFromConfig() end, }, - ["barheight"] = { - type = "range", - name = "Health Bar Height", - desc = "Health Bar Height", + ["showbackdrop"] = { + type = "toggle", + name = "Show Frame Background", + desc = "Toggle the frame background to help with positioning", order = 1, - min = 10, - max = 30, - step = 2, get = function() - return Cursive.db.profile.height + return Cursive.db.profile.showbackdrop end, set = function(v) - Cursive.db.profile.height = v + Cursive.db.profile.showbackdrop = v + Cursive.UpdateFramesFromConfig() end, }, - ["spacing"] = { - type = "range", - name = "Spacing", - desc = "Spacing", - order = 1, - min = 0, - max = 10, - step = 1, - get = function() - return Cursive.db.profile.spacing - end, - set = function(v) - Cursive.db.profile.spacing = v + ["resetframe"] = { + type = "execute", + name = "Reset Frame", + desc = "Move the frame back to the default position", + order = 2, + func = function() + Cursive.db.profile.anchor = "CENTER" + Cursive.db.profile.x = -100 + Cursive.db.profile.y = -100 + Cursive.UpdateFramesFromConfig() end, }, + ["spacer"] = { + type = "header", + name = " ", + order = 3, + }, + ["bardisplay"] = { + type = "group", + name = "Bar Display Settings", + desc = "Bar Display Settings", + order = 10, + args = barOptions + }, + ["filters"] = { + type = "group", + name = "Mob filters", + desc = "Target and Raid Marks always shown", + order = 20, + args = mobFilters + }, + ["spacer2"] = { + type = "header", + name = " ", + order = 21, + }, ["maxrow"] = { type = "range", name = "Max Rows", desc = "Max Rows", - order = 1, + order = 30, min = 1, max = 20, step = 1, @@ -97,22 +305,28 @@ Cursive.cmdtable = { return Cursive.db.profile.maxrow end, set = function(v) - Cursive.db.profile.maxrow = v + if v ~= Cursive.db.profile.maxrow then + Cursive.db.profile.maxrow = v + Cursive.UpdateFramesFromConfig() + end end, }, - ["scale"] = { + ["maxcol"] = { type = "range", - name = "Scale", - desc = "Scale", - order = 1, - min = 0.5, - max = 2, - step = 0.1, + name = "Max Columns", + desc = "Max Columns", + order = 40, + min = 1, + max = 20, + step = 1, get = function() - return Cursive.db.profile.scale + return Cursive.db.profile.maxcol end, set = function(v) - Cursive.db.profile.scale = v + if v ~= Cursive.db.profile.maxcol then + Cursive.db.profile.maxcol = v + Cursive.UpdateFramesFromConfig() + end end, }, } diff --git a/sounds/refresh.mp3 b/sounds/refresh.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..554cd0ae78f9761619634ec3b0a4518cfaffc590 GIT binary patch literal 5318 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 RK!SKCMD}0k_kY#J-vH8Ed}{yz literal 0 HcmV?d00001 diff --git a/sounds/resist.mp3 b/sounds/resist.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..01e123a6dd4629febf6cc0184322c02c739e6e79 GIT binary patch literal 42363 zcmeFYXH-*B)Gc~a2@oJuLp4;X5_%CZRH+IAN)ZUXiV7+n5_(lS0TfUHsY+FtN-qK;LLPqi-8;Vf?!E8bG2Z+6_K$P+KKo?kjAV|v)|_h{JuMk1@Ne*&nVM>! zof!ZCVrc)+MNaXetn@`Gtki$({+9z~Z{a_!{?DnNx67Tg>DlK1V*n_+3c#t63`|UH z>|E#1^9hQGi%Uw&DJrU5*3j10HMn;Dy19k5t*yPYo2RGuz5D+DL7~LR$e4sjDJkh$ zIeB@{3SX9$RaVu#ecRMZ?&#?09~v1MoA@$2yRf+Y^XJC)-oe4qU&_C)K6^;Vvxii~ z{#*RlApmy%FVmu{B(*BH|9biVKmULH3!EXr3E<15DFMAw0eH7t-9T1&fbrRIu{%G> z3E{+_^735wgb(MlI*)e7%+D{c7I6Ol<(O&N^W%bCXil)abCG>5N$1gd`nW_xlqL>` zAd?9wUITt47U49L3`tIGlqDX%fp`b{6<$*gSbNZdQ8dsjzxw4 zjzvt#iho7GwUey|Bz3obIlD{<`G&N!MV}bQyUPO{=z{XYg8(LTM}Z2D!{fsMX36<2 zmLU;Jk;u<$ep~bN42QZIj@L>S=kM}(aJ1&r9E6M+&)4=8Ql&_r*q#p0Z{~3xZq0dY zZC!aRyX(5XSH&BTDC^es_`S`Xn6w=Jtd+slOO`%Xug)ByXsVU`4JCcic5@p?4Il7`tQ4SGo>B~Cu8i_P%5#o#WOfC*6jzY3vd~ZgI zu6?hcV1^+0mMd5zyg`Vy80>IK1D707eiF0IWr?dQWZ^H$uLBjD!9~@v3Z;PnXmt$O7_>u3 zh7!Yn&`O101ndcA03-1s4K+~~%u57-XOW_+Q-6-o&xlo**o(fa1`wWjY0|TR9AQ*;e_6U>P+IkY(}Bp!5SJ1Xi7^bI8l(eV;{y+(kcQ9AlLirYhu<$V zMJ|$A7+ua|xxjvNXnZ~8Y>0n)WY<*;A}HTBa%mjo0K$$a!<6io%`?8A5~m)hl^b3# z&-!5j`gbdZa{Okyb;{=5&CjFe#G*~ggK1VCY9o$;1i$wu|FQqK`N(

$N%SW0S-n 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 ZI$fgmM}h2El!5hs(!;+s4F40J{|gpCEL8vi literal 0 HcmV?d00001 diff --git a/ui.lua b/ui.lua index 1fdc1b7..4f99d40 100644 --- a/ui.lua +++ b/ui.lua @@ -19,13 +19,49 @@ ui.background = { insets = { left = 0, right = 0, top = 0, bottom = 0 } } -ui.frames = {} +ui.rootBarFrame = nil +ui.targetIndicatorSize = 8 +ui.padding = 2 -ui.CreateRoot = function(parent, caption) - local frame = CreateFrame("Frame", "Cursive" .. caption, parent) - frame.id = caption +local function GetBarWidth() + local config = Cursive.db.profile + return ui.targetIndicatorSize + + config.raidiconsize + + ui.padding + + config.healthwidth + + config.maxcurses * (config.curseiconsize + ui.padding) +end + +local function UpdateRootBarFrame() + local config = Cursive.db.profile + + if config.showbackdrop then + ui.rootBarFrame:SetBackdrop(ui.background) + else + ui.rootBarFrame:SetBackdrop(nil) + end + + ui.rootBarFrame:EnableMouse(not config.clickthrough) + + ui.rootBarFrame.pos = config.anchor .. config.x .. config.y .. config.scale + ui.rootBarFrame:ClearAllPoints() + ui.rootBarFrame:SetPoint(config.anchor, config.x, config.y) + + ui.rootBarFrame:SetScale(config.scale) + + ui.rootBarFrame.caption:SetFont(STANDARD_TEXT_FONT, Cursive.db.profile.textsize, "THINOUTLINE") + ui.rootBarFrame.caption:SetText(Cursive.db.profile.caption) + + ui.rootBarFrame:SetWidth(config.maxcol * GetBarWidth()) + ui.rootBarFrame:SetHeight(config.maxrow * config.height) +end + +local function CreateRoot() + local frame = CreateFrame("Frame", Cursive.db.profile.caption, UIParent) + ui.rootBarFrame = frame + + frame.id = Cursive.db.profile.caption - frame:EnableMouse(true) frame:RegisterForDrag("LeftButton") frame:SetMovable(true) @@ -35,7 +71,6 @@ ui.CreateRoot = function(parent, caption) end) frame:SetScript("OnDragStop", function() - -- load current window config -- convert to best anchor depending on position local new_anchor = utils.GetBestAnchor(this) local anchor, x, y = utils.ConvertFrameAnchor(this, new_anchor) @@ -49,24 +84,38 @@ ui.CreateRoot = function(parent, caption) -- stop drag this:StopMovingOrSizing() this.lock = false - end) - -- assign/initialize elements - frame.CreateBar = ui.CreateBar - frame.frames = {} + this:ClearAllPoints() + this:SetPoint(anchor, x, y) + end) -- create title text frame.caption = frame:CreateFontString(nil, "HIGH", "GameFontWhite") - frame.caption:SetFont(STANDARD_TEXT_FONT, 9, "THINOUTLINE") frame.caption:SetPoint("TOPLEFT", frame, "TOPLEFT", 10, -2) frame.caption:SetTextColor(1, 1, 1, 1) - frame.caption:SetText(caption) + + UpdateRootBarFrame() + + frame:Show() return frame end +ui.barFrames = {} -- holds all barFrames for all guids + +Cursive.UpdateFramesFromConfig = function() + for guid, frame in pairs(ui.barFrames) do + frame:Hide() + ui.barFrames[guid] = nil + end + + if ui.rootBarFrame then + UpdateRootBarFrame() + end +end + ui.BarEnter = function() - this.border:SetBackdropBorderColor(1, 1, 1, 1) + this.bar.border:SetBackdropBorderColor(1, 1, 1, 1) this.hover = true GameTooltip_SetDefaultAnchor(GameTooltip, this) @@ -80,6 +129,10 @@ ui.BarLeave = function() end ui.BarUpdate = function() + if not this.guid then + return + end + -- update statusbar values this.bar:SetMinMaxValues(0, UnitHealthMax(this.guid)) this.bar:SetValue(UnitHealth(this.guid)) @@ -92,26 +145,28 @@ ui.BarUpdate = function() local name = UnitName(this.guid) local hp = UnitHealth(this.guid) -- convert hp to k if > 1000 - if hp and hp > 1000 then - -- round to 1 decimal - hp = math.floor(hp / 100) / 10 .. "k" + if hp then + if hp >= 1000000 then + hp = math.floor(hp / 100000) / 10 .. "m" + elseif hp >= 1000 then + hp = math.floor(hp / 100) / 10 .. "k" + end end if name then - if hp then - this.text:SetText(name .. " " .. tostring(hp)) - else - this.text:SetText(name) - end + this.nameText:SetText(name) + end + if hp then + this.hpText:SetText(hp) end -- update health bar border if this.hover then - this.border:SetBackdropBorderColor(1, 1, 1, 1) + this.bar.border:SetBackdropBorderColor(1, 1, 1, 1) elseif UnitAffectingCombat(this.guid) then - this.border:SetBackdropBorderColor(.8, .2, .2, 1) + this.bar.border:SetBackdropBorderColor(.8, .2, .2, 1) else - this.border:SetBackdropBorderColor(.2, .2, .2, 1) + this.bar.border:SetBackdropBorderColor(.2, .2, .2, 1) end -- show raid icon if existing @@ -134,49 +189,88 @@ ui.BarClick = function() TargetUnit(this.guid) end -ui.CreateBar = function(parent, guid) - local frame = CreateFrame("Button", nil, parent) - frame.guid = guid +local function CreateBar(guid) + local barFrame = CreateFrame("Button", nil, ui.rootBarFrame) + barFrame.guid = guid - frame:SetScript("OnClick", ui.BarClick) - frame:SetScript("OnEnter", ui.BarEnter) - frame:SetScript("OnLeave", ui.BarLeave) - frame:SetScript("OnUpdate", ui.BarUpdate) + barFrame:SetScript("OnClick", ui.BarClick) + barFrame:SetScript("OnEnter", ui.BarEnter) + barFrame:SetScript("OnLeave", ui.BarLeave) + barFrame:SetScript("OnUpdate", ui.BarUpdate) + + local config = Cursive.db.profile + local width = GetBarWidth() + barFrame:SetWidth(width) + barFrame:SetHeight(config.height) + + -- create target indicator + local targetLeft = barFrame:CreateTexture(nil, "OVERLAY") + targetLeft:SetWidth(ui.targetIndicatorSize) + targetLeft:SetHeight(8) + targetLeft:SetPoint("LEFT", barFrame, "LEFT", 0, 0) + targetLeft:SetTexture("Interface\\AddOns\\Cursive\\img\\target-left") + targetLeft:Hide() + barFrame.target_left = targetLeft + + -- create raid icon textures + local icon = barFrame:CreateTexture(nil, "OVERLAY") + icon:SetWidth(config.raidiconsize) + icon:SetHeight(config.raidiconsize) + icon:SetPoint("LEFT", targetLeft, "RIGHT", 0, 0) + icon:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons") + icon:Hide() + barFrame.icon = icon -- create health bar - local bar = CreateFrame("StatusBar", nil, frame) + local bar = CreateFrame("StatusBar", nil, barFrame) bar:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar") bar:SetStatusBarColor(1, .8, .2, 1) bar:SetMinMaxValues(0, 100) bar:SetValue(20) - bar:SetAllPoints() - frame.bar = bar + bar:SetPoint("LEFT", icon, "RIGHT", ui.padding, 0) + bar:SetWidth(config.healthwidth) + bar:SetHeight(config.height) + barFrame.bar = bar - -- create caption text - local text = frame.bar:CreateFontString(nil, "HIGH", "GameFontWhite") - text:SetPoint("TOPLEFT", bar, "TOPLEFT", 2, -2) - text:SetPoint("BOTTOMRIGHT", bar, "BOTTOMRIGHT", -2, 2) - text:SetFont(STANDARD_TEXT_FONT, 9, "THINOUTLINE") - text:SetJustifyH("LEFT") - frame.text = text + local hp = bar:CreateFontString(nil, "HIGH", "GameFontWhite") + hp:SetPoint("TOPRIGHT", bar, "TOPRIGHT", -2, -2) + hp:SetWidth(30) + hp:SetHeight(config.height - 4) + hp:SetFont(STANDARD_TEXT_FONT, config.textsize, "THINOUTLINE") + hp:SetJustifyH("RIGHT") + barFrame.hpText = hp - -- create raid icon textures - local icon = bar:CreateTexture(nil, "OVERLAY") - icon:SetWidth(16) - icon:SetHeight(16) - icon:SetPoint("RIGHT", frame, "RIGHT", -2, 0) - icon:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons") - icon:Hide() - frame.icon = icon + local name = bar:CreateFontString(nil, "HIGH", "GameFontWhite") + name:SetPoint("TOPLEFT", bar, "TOPLEFT", 2, -2) + name:SetPoint("BOTTOMRIGHT", hp, "BOTTOMLEFT", 2, 0) + name:SetFont(STANDARD_TEXT_FONT, config.textsize, "THINOUTLINE") + name:SetJustifyH("LEFT") + barFrame.nameText = name + + -- create health bar backdrops + if pfUI and pfUI.uf then + pfUI.api.CreateBackdrop(bar) + bar.border = bar.backdrop + else + bar:SetBackdrop(ui.background) + bar:SetBackdropColor(0, 0, 0, 1) + + local border = CreateFrame("Frame", nil, bar.bar) + border:SetBackdrop(ui.border) + border:SetBackdropColor(.2, .2, .2, 1) + border:SetPoint("TOPLEFT", bar.bar, "TOPLEFT", -2, 2) + border:SetPoint("BOTTOMRIGHT", bar.bar, "BOTTOMRIGHT", 2, -2) + bar.border = border + end -- display up to 3 curses for i = 1, 3 do - local curse = bar:CreateTexture(nil, "OVERLAY") - curse:SetWidth(20) - curse:SetHeight(20) - curse:SetPoint("LEFT", frame, "RIGHT", 4 + ((i - 1) * 20), 0) + local curse = barFrame:CreateTexture(nil, "OVERLAY") + curse:SetWidth(config.curseiconsize) + curse:SetHeight(config.curseiconsize) + curse:SetPoint("LEFT", bar, "RIGHT", i * ui.padding + ((i - 1) * config.curseiconsize), 0) - curse.timer = bar:CreateFontString(nil, "OVERLAY", "GameFontNormal") + curse.timer = barFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal") curse.timer:SetFontObject(GameFontHighlight) curse.timer:SetFont(STANDARD_TEXT_FONT, 11, "OUTLINE") curse.timer:SetTextColor(1, 1, 1) @@ -184,153 +278,115 @@ ui.CreateBar = function(parent, guid) curse.timer:Hide() curse:Hide() - frame["curse" .. i] = curse + barFrame["curse" .. i] = curse end - -- create target indicator - local target_left = bar:CreateTexture(nil, "OVERLAY") - target_left:SetWidth(8) - target_left:SetHeight(8) - target_left:SetPoint("LEFT", frame, "LEFT", -4, 0) - target_left:SetTexture("Interface\\AddOns\\Cursive\\img\\target-left") - target_left:Hide() - frame.target_left = target_left + ui.barFrames[guid] = barFrame + return barFrame +end - -- create frame backdrops - if pfUI and pfUI.uf then - pfUI.api.CreateBackdrop(frame) - frame.border = frame.backdrop - else - frame:SetBackdrop(ui.background) - frame:SetBackdropColor(0, 0, 0, 1) +local function GetBarCords(row, col) + local config = Cursive.db.profile + local x = (col - 1) * GetBarWidth() + local y = row * (config.height + config.spacing) -- don't subtract 1 to account for header + return x, y +end - local border = CreateFrame("Frame", nil, frame.bar) - border:SetBackdrop(ui.border) - border:SetBackdropColor(.2, .2, .2, 1) - border:SetPoint("TOPLEFT", frame.bar, "TOPLEFT", -2, 2) - border:SetPoint("BOTTOMRIGHT", frame.bar, "BOTTOMRIGHT", 2, -2) - frame.border = border +local function DisplayGuid(guid, row, col) + local barFrame = ui.barFrames[guid] or CreateBar(guid) + + local x, y = GetBarCords(row, col) + + -- update position if required + if not barFrame.pos or barFrame.pos ~= x .. -y then + barFrame:ClearAllPoints() + barFrame:SetPoint("TOPLEFT", ui.rootBarFrame, "TOPLEFT", x, -y) + barFrame.pos = x .. -y end - return frame + -- update curses + local curseNumber = 1 + + local guidCurses = Cursive.curses.guids[guid] + if guidCurses then + for curseName, curseData in pairs(guidCurses) do + if curseNumber > 3 then + break + end + + local remaining = Cursive.curses:TimeRemaining(curseData) + local curse = barFrame["curse" .. curseNumber] + if remaining >= 0 then + curse:SetTexture(Cursive.curses.trackedCurseIds[curseData.spellID].texture) + curse.timer:SetText(remaining) + curse.timer:Show() + curse:Show() + else + curse.timer:Hide() + curse:Hide() + end + curseNumber = curseNumber + 1 + end + end + + barFrame:Show() end ui:SetAllPoints() ui:SetScript("OnUpdate", function() - if not Cursive.db.profile.enabled then + local config = Cursive.db.profile + + if not config.enabled then return end if (this.tick or 1) > GetTime() then return else - this.tick = GetTime() + .2 + this.tick = GetTime() + .8 end - local caption = Cursive.db.profile.caption - local config = Cursive.db.profile - - -- create ui frames based on config values - -- create root frame if not existing - ui.frames[caption] = ui.frames[caption] or ui:CreateRoot(caption) - local root = ui.frames[caption] + if not ui.rootBarFrame then + ui.rootBarFrame = CreateRoot() + end -- skip if locked (due to moving) - if root.lock then + if ui.rootBarFrame.lock then return end - -- update position based on config - if not root.pos or root.pos ~= config.anchor .. config.x .. config.y .. config.scale then - root.pos = config.anchor .. config.x .. config.y .. config.scale - root:ClearAllPoints() - root:SetPoint(config.anchor, config.x, config.y) - root:SetScale(config.scale) - end - -- run through all guids and fill with bars local title_size = 12 + config.spacing - local width, height = config.width, config.height + title_size - local x, y, rowCount, colCount = 0, 0, 0, 1 + + local row = 1 + local col = 1 + local maxBarsDisplayed = false for guid, time in pairs(Cursive.core.guids) do -- apply filters local shouldDisplay = Cursive:ShouldDisplayGuid(guid) - - local exists = UnitExists(guid) and Cursive.filter.alive(guid) - -- display element if filters allow it - if exists and shouldDisplay then - rowCount = rowCount + 1 + if shouldDisplay and not maxBarsDisplayed then + -- display guid + DisplayGuid(guid, row, col) - if rowCount > config.maxrow then - if colCount < config.maxcol then - colCount = colCount + 1 - rowCount, x = 1, x + config.width + config.spacing - width = math.max(x + config.width, width) - else - break + -- update row/col + row = row + 1 + if row > config.maxrow then + row = 1 + col = col + 1 + if col > config.maxcol then + maxBarsDisplayed = true end end - - y = (rowCount - 1) * (config.height + config.spacing) + title_size - height = math.max(y + config.height + config.spacing, height) - - root.frames[guid] = root.frames[guid] or root:CreateBar(guid) - - -- update position if required - if not root.frames[guid].pos or root.frames[guid].pos ~= x .. -y then - root.frames[guid]:ClearAllPoints() - root.frames[guid]:SetPoint("TOPLEFT", root, "TOPLEFT", x, -y) - root.frames[guid].pos = x .. -y - end - - -- update sizes if required - if not root.frames[guid].sizes or root.frames[guid].sizes ~= config.width .. config.height then - root.frames[guid]:SetWidth(config.width) - root.frames[guid]:SetHeight(config.height) - root.frames[guid].sizes = config.width .. config.height - end - - for i = 1, 3 do - if not root.frames[guid]["curse" .. i].sizes or root.frames[guid]["curse" .. i].sizes ~= config.width .. config.height then - root.frames[guid]["curse" .. i]:SetWidth(config.height) - root.frames[guid]["curse" .. i]:SetHeight(config.height) - end - end - - -- update curses - local curseNumber = 1 - - local guidCurses = Cursive.curses.guids[guid] - if guidCurses then - for curseName, curseData in pairs(guidCurses) do - if curseNumber > 3 then - break - end - - local remaining = Cursive.curses:TimeRemaining(curseData) - local curse = root.frames[guid]["curse" .. curseNumber] - if remaining >= 0 then - curse:SetTexture(Cursive.curses.trackedCurseIds[curseData.spellID].texture) - curse.timer:SetText(remaining) - curse.timer:Show() - curse:Show() - else - curse.timer:Hide() - curse:Hide() - end - curseNumber = curseNumber + 1 - end - end - - root.frames[guid]:Show() else - if root.frames[guid] then - root.frames[guid]:Hide() - root.frames[guid] = nil + if ui.barFrames[guid] then + ui.barFrames[guid]:Hide() + ui.barFrames[guid] = nil end - if not exists then + + local active = UnitExists(guid) and Cursive.filter.alive(guid) + if not active then -- remove from core Cursive.core.remove(guid) -- remove from curses @@ -338,10 +394,6 @@ ui:SetScript("OnUpdate", function() end end end - - -- update window size - root:SetWidth(width) - root:SetHeight(height) end) Cursive.ui = ui