--[[----------------------------------------------------------------------- oUF: Stardust - a layout for the oUF framework Copyright (c) 2016 Andrew Mordecai <armordecai@protonmail.ch> This code is released under the zlib license; see LICENSE for details. -------------------------------------------------------------------------]] local _, Stardust = ... local config = Stardust.config local colors = oUF.colors local _, class = UnitClass("player") local LibSharedMedia = LibStub("LibSharedMedia-3.0") --------------------------- -- Widget creation --------------------------- local function NewStatusBar(parent, textSize, noBG, noBorder, noShadow) local TEXTURE = LibSharedMedia:Fetch("statusbar", config.barTexture) local bar = CreateFrame("StatusBar", nil, parent) bar:SetStatusBarTexture(TEXTURE) if textSize then bar.value = bar:CreateFontString(nil, "OVERLAY") bar.value:SetFont(LibSharedMedia:Fetch("font", config.numberFont), textSize, "OUTLINE") bar.value:SetShadowOffset(0, 0) bar.value:SetTextColor(1, 1, 1) bar.value:SetPoint("CENTER") end if not noBG then bar.bg = bar:CreateTexture(nil, "BORDER") bar.bg:SetAllPoints() bar.bg:SetTexture(TEXTURE) bar.bg.multiplier = config.bgMultiplier end if not noBorder then bar.backdrop = bar:CreateTexture(nil, "BACKGROUND") bar.backdrop:SetPoint("BOTTOMLEFT", -1, -1) bar.backdrop:SetPoint("TOPRIGHT", 1, 1) bar.backdrop:SetTexture(0, 0, 0) end if not noShadow then Stardust.AddShadow(bar, 3) end return bar end local function NewBarGroup(parent, count, width, height, textSize) local group = { __max = count } for i = 1, count do local bar = NewStatusBar(parent, textSize) bar:SetSize(width, height) bar:SetMinMaxValues(0, 1) bar:SetValue(1) -- ClassIcons expects texture objects bar.SetVertexColor = bar.SetStatusBarColor if i > 1 then bar:SetPoint("LEFT", group[i-1], "RIGHT", 3, 0) end group[i] = bar end return group end local function AddStatusIcon(self, element, size, offsetX, offsetY) local icon = self.Health:CreateTexture(nil, "OVERLAY") icon:SetPoint("LEFT", self.Health, "TOPLEFT", 3, 0) icon:SetSize(size or 16, size or 16) self.StatusIcons = self.StatusIcons or {} tinsert(self.StatusIcons, icon) icon.offsetX = offsetX or 0 icon.offsetY = offsetY or 0 icon.PostUpdate = Stardust.PostUpdateStatusIcon self[element] = icon return icon end --------------------------- -- Frame setup --------------------------- local function ApplyStyle(self, unit, isSingle) unit = unit:gsub("%d+", "") local unitConfig = config.units[unit] local classColor = oUF.colors.class[class] local classR, classG, classB = classColor[1], classColor[2], classColor[3] --------------------------- -- Frame --------------------------- self:SetScript("OnEnter", Stardust.OnEnter) self:SetScript("OnLeave", Stardust.OnLeave) self:RegisterForClicks("AnyUp") if (isSingle) then self:SetSize(config.width * (unitConfig and unitConfig.width or 1), config.height * (unitConfig and unitConfig.height or 1)) end Stardust.AddShadow(self, 6) --------------------------- -- Health bar --------------------------- local Health = NewStatusBar(self, config.numberLarge) Health:SetPoint("BOTTOMLEFT") Health:SetPoint("TOPRIGHT") Health:SetReverseFill(true) Health:SetStatusBarColor(0.3, 0.3, 0.3) Health.bg:SetVertexColor(0.15, 0.15, 0.15) Health.value:ClearAllPoints() Health.value:SetPoint("BOTTOMRIGHT", 0, 3 + config.powerHeight + 2) Health.frequentUpdates = true Health.PostUpdate = Stardust.PostUpdateHealth self:SmoothBar(Health) self.Health = Health --------------------------- -- Name text --------------------------- local Name = self.Health:CreateFontString(nil, "OVERLAY") Name:SetPoint("BOTTOMLEFT", 2, 3 + config.powerHeight + 2) Name:SetPoint("RIGHT", self.Health.value, "LEFT") Name:SetJustifyH("LEFT") Name:SetFont(LibSharedMedia:Fetch("font", config.textFont), config.textSize, "OUTLINE") Name:SetShadowOffset(0, 0) Name:SetTextColor(1, 1, 1) self:Tag(Name, "[unitcolor][name]") self.Name = Name --------------------------- -- Power bar --------------------------- local Power = NewStatusBar(Health, config.numberSmall) Power:SetPoint("BOTTOMLEFT", 3, 3) Power:SetPoint("BOTTOMRIGHT", -3, 3) Power:SetHeight(config.powerHeight) Power.colorClass = true Power.colorDisconnected = true Power.colorReaction = true Power.colorTapping = true Power.frequentUpdates = true Power.PostUpdate = Stardust.PostUpdatePower self:SmoothBar(Power) self.Power = Power Stardust.AddShadow(Power, 3) --------------------------- -- AFK text --------------------------- if unit == "player" or unit == "party" then local AFK = self:CreateFontString(nil, "OVERLAY") AFK:SetPoint("CENTER", self.Power) AFK:SetFont(LibSharedMedia:Fetch("font", config.numberFont), config.numberSmall, "OUTLINE") AFK:SetShadowOffset(0, 0) AFK:SetTextColor(1, 1, 1) AFK.PostUpdate = Stardust.PostUpdateAFK self.AFK = AFK end --------------------------- -- Secondary resources --------------------------- if unit == "player" then --------------------------- -- Runes @ TOPLEFT --------------------------- if class == "DEATHKNIGHT" then local Runes = NewBarGroup(self.Health, 6, 30, config.powerHeight) Runes[1]:SetPoint("TOPLEFT", self.Health, 3, -3) Runes.PostUpdateRune = Stardust.PostUpdateRune Runes.PostUpdateRuneType = Stardust.PostUpdateRuneType self.Runes = Runes end --------------------------- -- Combo Points @ TOPLEFT --------------------------- if class == "DRUID" or class == "ROGUE" then local CPoints = NewBarGroup(self.Health, 5, 30, config.powerHeight) CPoints[1]:SetPoint("TOPLEFT", self.Health, 3, -3) CPoints.PreUpdate = Stardust.PreUpdateCPoints self.CPoints = CPoints for i = 1, #CPoints do local bar = CPoints[i] local mu = bar.bg.multiplier bar:SetStatusBarColor(classR, classG, classB) bar.bg:SetVertexColor(classR * mu, classG * mu, classB * mu) end end --------------------------- -- Totems @ TOPLEFT --------------------------- if class == "SHAMAN" then local Totems = NewBarGroup(self.Health, 4, 30, config.powerHeight, config.numberSmall) Totems[1]:SetPoint("TOPLEFT", self.Health, 3, -3) Totems.PreUpdate = Stardust.PreUpdateTotems Totems.PostUpdate = Stardust.PostUpdateTotem self.Totems = Totems for i = 1, 4 do local bar = Totems[i] bar:EnableMouse(true) bar:SetHitRectInsets(0, 0, -6, -3) bar.__owner = self -- oUF sets it on Totems, but not Totems[i] local color = oUF.colors.totems[i] local r, g, b = color[1], color[2], color[3] local mu = bar.bg.multiplier bar:SetStatusBarColor(r, g, b) bar.bg:SetVertexColor(r * mu, g * mu, b * mu) bar.value:SetPoint("CENTER", 0, 3) end end --------------------------- -- Chi / Holy Power / Shadow Orbs / Soul Shards @ TOPLEFT --------------------------- if class == "MONK" or class == "PALADIN" or class == "PRIEST" or class == "WARLOCK" then local ClassIcons = NewBarGroup(self.Health, 6, 30, config.powerHeight) ClassIcons[1]:SetPoint("TOPLEFT", self.Health, 3, -3) ClassIcons.PostUpdate = Stardust.PostUpdateClassIcons self.ClassIcons = ClassIcons end --------------------------- -- Druid Mana @ TOP / Stagger @ TOPRIGHT / Demonic Fury @ TOP --------------------------- if class == "DRUID" or class == "MONK" or class == "WARLOCK" then local bar = NewStatusBar(Health, config.numberSmall) bar:SetPoint("TOPLEFT", 3, -3) bar:SetPoint("TOPRIGHT", -3, -3) bar:SetHeight(config.powerHeight) self:SmoothBar(bar) if class == "DRUID" then bar.colorPower = true bar.PostUpdate = PostUpdatePower self.DruidMana = bar elseif class == "MONK" then bar:SetPoint("TOPLEFT", self.ClassIcons[4], 3, 0) bar.PostUpdate = PostUpdateStagger self.Stagger = bar elseif class == "WARLOCK" then bar.colorPower = true bar.PostUpdate = PostUpdatePower self.DemonicFury = bar end end --------------------------- -- Maelstrom Weapon @ TOPRIGHT --------------------------- if class == "SHAMAN" then local AuraStack = NewBarGroup(self.Health, 5, config.powerHeight * 2, config.powerHeight) AuraStack[1]:SetPoint("TOPRIGHT", self.Health, -3, -3) AuraStack.PostUpdate = Stardust.PostUpdateCPoints self.AuraStack = AuraStack AuraStack.aura = GetSpellInfo(51530) -- Maelstrom Weapon AuraStack.spec = 2 -- Enhancement for i = 1, #AuraStack do local bar = AuraStack[i] local mu = bar.bg.multiplier bar:SetStatusBarColor(classR, classG, classB) bar.bg:SetVertexColor(classR * mu, classG * mu, classB * mu) if i > 1 then bar:ClearAllPoints() bar:SetPoint("RIGHT", AuraStack[i-1], "LEFT", -3, 0) end end end --------------------------- -- Burning Embers @ TOPLEFT --------------------------- if class == "WARLOCK" then local BurningEmbers = NewBarGroup(self.Health, 4, 30, config.powerHeight) BurningEmbers[1]:SetPoint("TOPLEFT", self.Health, 3, -3) BurningEmbers.PreUpdate = Stardust.PreUpdateCPoints self.BurningEmbers = BurningEmbers for i = 1, #BurningEmbers do local bar = BurningEmbers[i] local mu = bar.bg.multiplier bar:SetStatusBarColor(classR, classG, classB) bar.bg:SetVertexColor(classR * mu, classG * mu, classB * mu) self:SmoothBar(bar) end end end --------------------------- -- Alternate Power Bar -- TODO: layout --------------------------- local AltPowerBar = NewStatusBar(self.Health, config.numberSmall) AltPowerBar:SetPoint("TOPLEFT", self.Power, "BOTTOMLEFT", 0, -3) AltPowerBar:SetPoint("TOPRIGHT", self.Power, "BOTTOMRIGHT", 0, 3) AltPowerBar:SetHeight(config.powerHeight) AltPowerBar:EnableMouse(true) AltPowerBar.colorTexture = true AltPowerBar.PostUpdate = Stardust.PostUpdatePower self:SmoothBar(AltPowerBar) self.AltPowerBar = AltPowerBar Stardust.AddShadow(AltPowerBar, 3) --------------------------- -- TODO --------------------------- -- EclipseBar -- HealPrediction -- Castbar --------------------------- -- Group status icons --------------------------- if not unit:match("pet") and not unit:match(".+target") then AddStatusIcon(self, "LFDRole", 24) AddStatusIcon(self, "RaidRole") -- maintank, mainassist AddStatusIcon(self, "Leader") AddStatusIcon(self, "Assistant") AddStatusIcon(self, "MasterLooter", nil, 0, 1) AddStatusIcon(self, "PvP", 32, 0, -5) -- TODO: move it somewhere else? end --------------------------- -- Combat icon --------------------------- if unit == "player" then local Combat = self.Health:CreateTexture(nil, "OVERLAY") Combat:SetSize(32, 32) Combat:SetPoint("RIGHT", self.Health, "TOPRIGHT", -3, 0) Combat.PostUpdate = Stardust.PostUpdateCombat self.Combat = Combat local Resting = self.Health:CreateTexture(nil, "OVERLAY") Resting:SetSize(32, 32) Resting:SetPoint("RIGHT", self.Health, "TOPRIGHT", -3, 0) Resting.PostUpdate = Stardust.PostUpdateResting self.Resting = Resting end --------------------------- -- Phasing icon --------------------------- if not unit:match("pet") and not unit:match(".+target") then local PhaseIcon = self.Health:CreateTexture(nil, "OVERLAY") PhaseIcon:SetPoint("TOP") PhaseIcon:SetPoint("BOTTOM") PhaseIcon:SetWidth(config.height * 2.5) PhaseIcon:SetTexture("Interface\\Icons\\Spell_Frost_Stun") PhaseIcon:SetTexCoord(0.05, 0.95, 0.5 - 0.25 * 0.9, 0.5 + 0.25 * 0.9) PhaseIcon:SetAlpha(0.5) PhaseIcon:SetBlendMode("ADD") PhaseIcon:SetDesaturated(true) PhaseIcon:SetVertexColor(0.4, 0.8, 1) self.PhaseIcon = PhaseIcon end --------------------------- -- Quest mob icon --------------------------- if unit == "target" then local QuestIcon = self.Health:CreateTexture(nil, "OVERLAY") QuestIcon:SetSize(32, 32) QuestIcon:SetPoint("CENTER", self.Health, "LEFT", -3, 0) self.QuestIcon = QuestIcon end --------------------------- -- Raid target icon --------------------------- if unit == "player" or unit == "target" or unit == "party" then local RaidIcon = self.Health:CreateTexture(nil, "OVERLAY") RaidIcon:SetSize(24, 24) RaidIcon:SetPoint("CENTER", self.Health, "TOP", 0, 6) -- TODO self.RaidIcon = RaidIcon end --------------------------- -- Ready Check icon --------------------------- if unit == "player" or unit == "target" or unit == "party" then local ReadyCheck = self.Health:CreateTexture(nil, "OVERLAY") ReadyCheck:SetSize(24, 24) ReadyCheck:SetPoint("CENTER", 0, 3) -- TODO self.ReadyCheck = ReadyCheck end --------------------------- -- Resurrection icon --------------------------- if not unit:match("pet") and not unit:match(".+target") then local ResurrectIcon = self.Health:CreateTexture(nil, "OVERLAY") ResurrectIcon:SetSize(24, 24) ResurrectIcon:SetPoint("CENTER", 0, 3) -- TODO self.ResurrectIcon = ResurrectIcon end --------------------------- -- Threat level icon -- TODO: colorize and enlarge frame shadow for aggro --------------------------- if unit == "target" or unit == "focus" then local Threat = self.Health:CreateTexture(nil, "OVERLAY") Threat:SetSize(16, 16) Threat:SetPoint("CENTER", 0, 3) -- TODO self.Threat = Threat end --------------------------- -- DispelIcon (redirected to frame glow) --------------------------- if not unit:match(".+target$") then local DispelIcon = setmetatable({}, { __index = Stardust.DispelIconStub }) DispelIcon.PostUpdate = Stardust.PostUpdateDispelIcon self.DispelIcon = DispelIcon end --------------------------- -- Auras --------------------------- if unit == "player" or unit == "target" then local Auras = CreateFrame("Frame", nil, self) Auras:SetPoint("BOTTOMLEFT", self, "TOPLEFT", 0, 9) Auras:SetSize(config.width, 16) Auras.gap = true Auras['growth-x'] = "LEFT" Auras['growth-y'] = "UP" Auras.initialAnchor = "BOTTOMRIGHT" Auras.showDebuffType = true Auras.showStealableBuffs = true Auras.size = 24 Auras.spacing = 6 Auras.CustomFilter = Stardust.AuraFilter Auras.PostCreateIcon = Stardust.PostCreateAuraIcon Auras.PostUpdateIcon = Stardust.PostUpdateAuraIcon self.Auras = Auras end --------------------------- -- Range --------------------------- self.Range = { insideAlpha = 1, outsideAlpha = 0.5 } end oUF:Factory(function(self) self:RegisterStyle("Stardust", ApplyStyle) self:SetActiveStyle("Stardust") local player = self:Spawn("player") player:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOM", -175, 235) local pet = self:Spawn("pet") pet:SetPoint("TOPRIGHT", player, "BOTTOMRIGHT", 0, -6) local target = self:Spawn("target") target:SetPoint("BOTTOMLEFT", UIParent, "BOTTOM", 175, 235) local targettarget = self:Spawn("targettarget") targettarget:SetPoint("TOPLEFT", target, "BOTTOMLEFT", 0, -6) end)