Quantcast
--[[-----------------------------------------------------------------------
	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 = Stardust.colors

local _, class = UnitClass("player")
local LibSharedMedia = LibStub("LibSharedMedia-3.0")

---------------------------
-- Widget creation
---------------------------

local function NewStatusBar(parent, textFont, textSize, noBG, noBackdrop)
	local TEXTURE = LibSharedMedia:Fetch("statusbar", config.barTexture)

	local bar = CreateFrame("StatusBar", nil, parent)
	bar:SetStatusBarTexture(TEXTURE)

	if textFont and textSize then
		bar.value = bar:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
		bar.value:SetFont(LibSharedMedia:Fetch("font", textSize))
		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 noBackdrop then
		bar.backdrop = Health:CreateTexture(nil, "BACKDROP")
		bar.backdrop:SetPoint("BOTTOMLEFT", -1, -1)
		bar.backdrop:SetPoint("TOPRIGHT", 1, 1)
		bar.backdrop:SetTexture(0, 0, 0)
	end

	return bar
end

local function NewBarGroup(parent, count, width, height)
	local group = { __max = count }

	local color = Stardust.colors.class[class]
	local r, g, b = color[1], color[2], color[3]

	for i = 1, count do
		local bar = NewStatusBar(parent)
		bar:SetSize(width, height)
		bar:SetMinMaxValues(0, 1)
		bar:SetValue(1)

		if not noColor then
			local mu = bar.bg.multiplier
			bar:SetStatusBarColor(r, g, b)
			bar.bg:SetVertexColor(r * mu, g * mu, b * mu)
		end

		-- 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)
	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.PostUpdate = Stardust.PostUpdateStatusIcon
	self[element] = icon
	return icon
end

---------------------------
-- Frame setup
---------------------------

local function ApplyStyle(self, unit, isSingle)
	unit = unit:gsub("%d+", "")

	local uconfig = config.units[unit]

	---------------------------
	-- Frame
	---------------------------

	self:SetScript("OnEnter", UnitFrame_OnEnter)
	self:SetScript("OnLeave", UnitFrame_OnLeave)

	self:RegisterForClicks("AnyUp")

	if (isSingle) then
		self:SetSize(config.width * (uconfig and uconfig.width or 1), config.height * (uconfig and uconfig.height or 1))
	end

	---------------------------
	-- Outer glow
	---------------------------

	self.Glow = CreateGlow(self)

	---------------------------
	-- Health bar
	---------------------------

	local Health = NewStatusBar(self, config.numberFont, 25)
	Health:SetPoint("BOTTOMLEFT")
	Health:SetPoint("TOPRIGHT")
	Health:SetReverseFill(true)

	Health.value:ClearAllPoints()
	Health.value:SetPoint("RIGHT", Health, "TOPRIGHT", 0, 3)

	Health.colorClass = true
	Health.colorDisconnected = true
	Health.colorReaction = true
	Health.colorTapping = true
	Health.frequentUpdates = true
	Health.PostUpdate = Stardust.PostUpdateHealth
	self.Health = Health

	---------------------------
	-- Power bar
	---------------------------

	local Power = NewStatusBar(Health, config.numberFont, 15)
	Power:SetPoint("BOTTOMLEFT", 3, 3)
	Power:SetPoint("BOTTOMRIGHT", -3, 3)
	Power:SetHeight(config.powerHeight)

	Power.colorDisconnected = true
	Power.colorPower = true
	Power.PostUpdate = Stardust.PostUpdatePower
	self.Power = Power

	---------------------------
	-- Secondary resources
	---------------------------

	if 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

	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.PostUpdate = Stardust.PostUpdateCPoints
		self.CPoints = CPoints
	end

	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

	if class == "DRUID" or class == "SHAMAN" then
	    -- TODO: This can also show death knight ghouls.
	    -- How do these work? Are they important?
	    -- How to show them at the same time as runes?
		local Totems = NewBarGroup(self.Health, 4, 30, config.powerHeight)
		Totems[1]:SetPoint("TOPLEFT", self.Health, 3, -3)
		if class == "SHAMAN" then
			local mu = config.bgMultiplier
			for i = 1, 4 do
				local totem = Totems[i]
				totem:EnableMouse(true)

				local color = Stardust.colors.totems[i]
				local r, g, b = color[1], color[2], color[3]
				totem:SetStatusBarColor(r, g, b)
				totem.bg:SetVertexColor(r * mu, b * mu, g * mu)

				local value = totem:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
				value:SetFont(LibSharedMedia:Fetch("font", config.numberFont), 15)
				value:SetPoint("CENTER")
			end
		end
		Totems.PreUpdate = Stardust.PreUpdateTotems
		self.Totems = Totems
	end

	-- TODO: burning embers

	---------------------------
	-- Druid mana
	-- Warlock demonic fury
	---------------------------

	if class == "DRUID" or class == "WARLOCK" then
		local bar = NewStatusBar(Health)
		bar:SetPoint("TOPLEFT", 3, -3)
		bar:SetPoint("TOPRIGHT", -3, -3)
		bar:SetHeight(config.powerHeight)
		if class == "DRUID" then
			bar:SetPoint("TOPLEFT", self.Totems[4], 3, 0)
			bar.colorPower = true
			bar.PostUpdate = PostUpdatePower
			self.DruidMana = bar
		else
			bar.colorPower = true
			bar.PostUpdate = PostUpdatePower
			self.DemonicFury = bar
		end
	end

	---------------------------
	-- TODO
	---------------------------

	-- AltPowerBar
	-- EclipseBar
	-- HealPrediction
	-- Stagger

	-- Castbar

	-- Auras

	---------------------------
	-- Name text
	---------------------------

	local Name = self:CreateFontString(nil, "OVERLAY", "GameFontNormal")
	Name:SetPoint("BOTTOMLEFT", Power, "TOPLEFT", 0, 3)
	Name:SetFont(LibSharedMedia:Fetch("font", config.valueFont), 14)
	self:Tag(Name, "[unitcolor][name]")
	self.Name = Name

	---------------------------
	-- Group status icons
	---------------------------

	AddStatusIcon("LFDRole")
	AddStatusIcon("RaidRole") -- maintank, mainassist
	AddStatusIcon("Leader")
	AddStatusIcon("Assistant")
	AddStatusIcon("MasterLooter")
	AddStatusIcon("PvP")

	---------------------------
	-- Combat icon
	---------------------------

	if unit == "player" then
		local Combat = self.Health:CreateTexture(nil, "OVERLAY")
		Combat:SetSize(16, 16)
		Combat:SetPoint("RIGHT", self.Health, "TOPRIGHT", -3, 0)
		Combat.PostUpdate = Stardust.PostUpdateCombat
		self.Combat = Combat

		local Resting = self.Health:CreateTexture(nil, "OVERLAY")
		Resting:SetSize(16, 16)
		Resting:SetPoint("RIGHT", self.Health, "TOPRIGHT", -3, 0)
		Resting.PostUpdate = Stardust.PostUpdateResting
		self.Resting = Resting
	end

	---------------------------
	-- Phasing icon
	---------------------------

	if not unit:match(".+target$") and not unit:match(".+pet") 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(16, 16)
		QuestIcon:SetPoint("RIGHT", self.Health, "TOPRIGHT", -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", 0, 3) -- 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(".+target$") and not unit:match("pet") 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
	---------------------------

	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

	---------------------------
	-- 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)