Quantcast
local mod = StarTip:NewModule("Bars")
mod.name = "Bars"
mod.toggled = true
--mod.childGroup = true
local _G = _G
local StarTip = _G.StarTip
local GameTooltip = _G.GameTooltip
local GameTooltipStatusBar = _G.GameTooltipStatusBar
local UnitIsPlayer = _G.UnitIsPlayer
local RAID_CLASS_COLORS = _G.RAID_CLASS_COLORS
local UnitSelectionColor = _G.UnitSelectionColor
local UnitClass = _G.UnitClass
local self = mod
local LSM = LibStub("LibSharedMedia-3.0")
local WidgetBar = LibStub("LibScriptableWidgetBar-1.0")
local Utils = LibStub("LibScriptablePluginUtils-1.0")
local LibTimer = LibStub("LibScriptableUtilsTimer-1.0")
local L = StarTip.L

local environment = {}

local anchors = {
	"TOP",
	"TOPRIGHT",
	"TOPLEFT",
	"BOTTOM",
	"BOTTOMRIGHT",
	"BOTTOMLEFT",
	"RIGHT",
	"LEFT",
	"CENTER"
}

local anchorsDict = {}

for i, v in ipairs(anchors) do
	anchorsDict[v] = i
end

local createBars
local widgets = {}

local function copy(tbl)
	if type(tbl) ~= "table" then return tbl end
	local newTbl = {}
	for k, v in pairs(tbl) do
		newTbl[k] = copy(v)
	end
	return newTbl
end

local defaultWidgets = {
	[1] = {
		name = "Health Bar",
		type = "bar",
		expression = [[
if not UnitExists(unit) then return self.lastHealthBar end
self.lastHealthBar = UnitHealth(unit)
return self.lastHealthBar
]],
		min = "return 0",
		max = [[
if not UnitExists(unit) then return self.lastHealthBarMax end
self.lastHealthBarMax = UnitHealthMax(unit)
return self.lastHealthBarMax
]],
		color1 = [[
if not UnitExists(unit) then return self.lastR, self.lastG, self.lastB end
local r, g, b
if UnitIsPlayer(unit) then
    r, g, b = ClassColor(unit)
else
    if UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) then
        r, g, b = .5, .5, .5
	else
        r, g, b = UnitSelectionColor(unit)
	end
end
self.lastR, self.lastG, self.lastB = r, g, b
return r, g, b
]],
		height = 6,
		length = 0,
		points = {{"BOTTOM", "StarTipTooltipMain", "TOP", 0, 0}, {"LEFT", "StarTipTooltipMain", "LEFT", 5, 0}, {"RIGHT", "StarTipTooltipMain", "RIGHT", -5, 0}},
		texture1 = LSM:GetDefault("statusbar"),
		enabled = true,
		layer = 1,
		level = 100,
		parent = "StarTipTooltipMain"
	},
	[2] = {
		name = "Mana Bar",
		type = "bar",
		expression = [[
if not UnitExists(unit) then return self.lastManaBar end
self.lastManaBar = UnitPower(unit)
return self.lastManaBar
]],
		min = "return 0",
		max = [[
if not UnitExists(unit) then return self.lastManaMax end
self.lastManaMax = UnitManaMax('mouseover')
return self.lastManaMax
]],
		color1 = [[
if not UnitExists(unit) then return self.lastR, self.lastG, self.lastB end
self.lastR, self.lastG, self.lastB = PowerColor(nil, unit)
return self.lastR, self.lastG, self.lastB
]],
		height = 6,
		length = 0,
		points = {{"TOP", "StarTipTooltipMain", "BOTTOM", 0, 0}, {"LEFT", "StarTipTooltipMain", "LEFT", 5, 0}, {"RIGHT", "StarTipTooltipMain", "RIGHT", -5, 0}},
		texture1 = LSM:GetDefault("statusbar"),
		enabled = true,
		layer = 1,
		level = 100,
		parent = "StarTipTooltipMain"
	},
	[3] = {
		name = "Threat Bar",
		type = "bar",
		expression = [[
if not UnitExists(unit) then return self.lastthreatpct end
local _,_,threatpct = UnitDetailedThreatSituation(unit, "target")
self.lastthreatpct = threatpct or 0
return self.lastthreatpct
]],
		color1 = [[
if not UnitExists(unit) then return self.lastStatus end
local _, status = UnitDetailedThreatSituation(unit, "target")
self.lastStatus = status
return status
]],
		length = 6,
		height = 0,
		points = {{"LEFT", "StarTipTooltipMain", "RIGHT", 0, 0}, {"TOP", "StarTipTooltipMain", "TOP", 0, -5}, {"BOTTOM", "StarTipTooltipMain", "BOTTOM", 0, 5}},
		texture = LSM:GetDefault("statusbar"),
		min = "return 0",
		max = "return 100",
		enabled = true,
		layer = 1,
		level = 100,
		parent = "StarTipTooltipMain",
		orientation = WidgetBar.ORIENTATION_VERTICAL
	}

}

local defaults = {
	profile = {
		classColors = true,
		bars = {}
	}
}

mod.defaults = defaults

local options = {}
local optionsDefaults = {
	add = {
		name = L["Add Bar"],
		desc = L["Add a bar"],
		type = "input",
		set = function(info, v)
			local widget = {
				name = v,
				type = "bar",
				min = "return 0",
				max = "return 100",
				length = 12,
				height = 0,
				points = {{"RIGHT", "StarTipTooltipMain", "LEFT", 0, 0}, {"TOP", "StarTipTooltipMain", "TOP", 0, -5}, {"BOTTOM", "StarTipTooltipMain", "BOTTOM", 0, 5}},
				level = 100,
				layer = 1,
				texture = LSM:GetDefault("statusbar"),
				expression = "return random() * 100",
				color1 = "return .5, 1, .8",
				orientation = WidgetBar.ORIENTATION_VERTICAL,
				custom = true,
				enabled = true,
				parent = "StarTipTooltipMain"
			}
			tinsert(mod.db.profile.bars, widget)
			StarTip:RebuildOpts()
			mod:ClearBars()
		end,
		order = 5
	},
	defaults = {
		name = L["Restore Defaults"],
		desc = L["Restore Defaults"],
		type = "execute",
		func = function()
			mod.db.profile.bars = copy(defaultWidgets);
			StarTip:RebuildOpts()
		end,
		order = 6
	},
}

local intersectTimer
local intersectUpdate = function()
	for i, w in ipairs(widgets) do
		--w:IntersectUpdate()
	end
end


function updateBar(widget, bar)
	assert(widget and bar)

	bar:SetValue(widget.val1 * 100)

	local r, g, b = 0, 0, 1

	if widget.color1 and widget.bar1 then
		r, g, b = widget.color1.ret1, widget.color1.ret2, widget.color1.ret3
	elseif widget.color2 and widget.color2.is_valid then
		r, g, b = widget.color2.ret1, widget.color2.ret2, widget.color2.ret3
	end

	if type(r) == "number" then
		bar:SetStatusBarColor(r, g, b)
	else
		--bar:Hide()
	end

end

local textureDict = {}

local new, del
do
	local pool = {}
	function new(parent)
		local bar = next(pool)
		if type(parent) == "string" then
			parent = _G[parent]
		end
		if type(parent) ~= "table" then
			parent = _G["StarTipTooltipMain"]
		end
		if bar then
			pool[bar] = nil
			bar:SetParent(parent)
		else
			bar = CreateFrame("StatusBar", nil, parent)
		end

		return bar
	end
	function del(bar)
		pool[bar] = true
	end
end

local defaultPoint = {"BOTTOMLEFT", "StarTipTooltipMain", "TOPLEFT"}

local strataNameList = {
	"TOOLTIP", "FULLSCREEN_DIALOG", "FULLSCREEN", "DIALOG", "HIGH", "MEDIUM", "LOW", "BACKGROUND"
}

local strataLocaleList = {
	"Tooltip", "Fullscreen Dialog", "Fullscreen", "Dialog", "High", "Medium", "Low", "Background"
}

local function clearBar(obj)
	if not obj then return end
	obj.bar:ClearAllPoints()
	obj.bar:Hide()
	del(obj.bar)
	obj:Del()
	if obj.secondBar then
		obj.secondBar.bar:Hide()
		del(obj.secondBar.bar)
		obj.secondBar:Del()
	end
end

function mod:ClearBars()
	for k, v in pairs(mod.bars or {}) do
		clearBar(v)
	end
	wipe(mod.bars or {})
end

local function createBars()
	if type(mod.bars) ~= "table" then mod.bars = {} end

	for k, v in pairs(self.db.profile.bars) do
		if v.enabled and not v.deleted then
			local widget = mod.bars[v]
			if not widget then
				local bar = new(v.parent)
				widget = WidgetBar:New(StarTip.core, v.name, copy(v), v.row or 0, v.col or 0, v.layer or 1, StarTip.db.profile.errorLevel, updateBar, bar)
				tinsert(widgets, widget)
				bar:SetStatusBarTexture(LSM:Fetch("statusbar", v.texture1))
				bar:ClearAllPoints()
				if widget.orientation == WidgetBar.ORIENTATION_VERTICAL then
					bar:SetOrientation("VERTICAL")
				else
					bar:SetOrientation("HORIZONTAL")
				end
				for j, point in ipairs(v.points) do
					local arg1, arg2, arg3, arg4, arg5 = unpack(point)
					arg4 = (arg4 or 0)
					arg5 = (arg5 or 0)
					bar:SetPoint(arg1, arg2, arg3, arg4, arg5)
				end
				bar:SetWidth(v.length or 10)
				bar:SetHeight(v.height or 10)
				bar:SetMinMaxValues(0, 100)
				bar:Show()
				bar:SetFrameStrata(strataNameList[v.layer or 1])
				bar:SetFrameLevel(v.level)
				widget.bar1 = true
				widget.bar = bar
				mod.bars[v] = widget
				v.bar = bar

				if v.expression2 then
					bar = new(v.parent)
					widget = WidgetBar:New(StarTip.core, v.name, v, v.row or 0, v.col or 0, v.layer or 0, StarTip.db.profile.errorLevel, updateBar, bar)
					bar:SetStatusBarTexture(LSM:Fetch("statusbar", v.texture2 or v.texutre1 or "Blizzard"))
					bar:ClearAllPoints()
					for i, point in ipairs(v.points) do
						local arg1, arg2, arg3, arg4, arg5 = unpack(point)
						arg4 = (arg4 or 0)
						if v.top then
							arg5 = (arg5 or 0) - (v.height or 12)
						else
							arg5 = (arg5 or 0) + (v.height or 12)
						end
						bar:SetPoint(arg1, arg2, arg3, arg4, arg5)
					end
					bar:SetWidth(v.length or 10)
					bar:SetHeight(v.height)
					bar:SetMinMaxValues(0, 100)
					bar:Show()
					bar:SetFrameStrata(strataNameList[widget.layer or 1])
					bar:SetFrameLevel(v.level)
					mod.bars[v].secondBar = widget
				end
			end
		end
	end
end

function mod:CreateBars()
	createBars()
end

function mod:ReInit()
	if not self.db.profile.bars then
		self.db.profile.bars = {}
	end

	for k in pairs(self.db.profile.bars) do
		if type(k) == "string" then
			wipe(self.db.profile.bars)
			break
		end
	end

	for k, v in pairs(defaultWidgets) do
		for j, vv in ipairs(self.db.profile.bars) do
			if v.name == vv.name and not vv.custom then
				for k, val in pairs(v) do
					if v[k] ~= vv[k] and not vv[k.."Dirty"] then
						vv[k] = v[k]
					end
				end
				v.tagged = true
				v.deleted = vv.deleted
			end
		end
	end

	for k, v in pairs(defaultWidgets) do
		if not v.tagged and not v.deleted then
			self.db.profile.bars[k] = copy(v)
		end
	end

end

function mod:OnInitialize()
	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)

	self:ReInit()

	StarTip:SetOptionsDisabled(options, true)

	self.bars = {}
end

function mod:OnEnable()
	StarTip:SetOptionsDisabled(options, false)
	intersectTimer = intersectTimer or LibTimer:New("Bars.intersectTimer", 100, true, intersectUpdate)
	self:ClearBars()
	for k, bar in pairs(self.bars or {}) do
		if bar.config.alwaysShown then
			bar:Start()
			bar.bar:Show()
			if bar.secondBar then
				bar.secondBar:Start()
				bar.secondBar:Show()
			end
		end
	end
end

function mod:OnDisable()
	self:ClearBars()
	StarTip:SetOptionsDisabled(options, true)
	if type(intersectTimer) == "table" then intersectTimer:Stop() end
end

--[[function mod:RebuildOpts()
	for k, v in ipairs(self.db.profile.bars) do
		options.bars.args[k] = WidgetBar:GetOptions(v)
	end
end]]

function mod:GetOptions()
	return options
end

function mod:SetUnit()
	GameTooltipStatusBar:Hide()
	createBars()
	for i, bar in pairs(self.bars or {}) do
		bar:Start()
		bar.bar:Show()
		if bar.secondBar then
			bar.secondBar:Start()
			bar.secondBar.bar:Show()
		end
	end
	intersectTimer:Start()
end

function mod:SetItem()
	for i, bar in pairs(self.bars or {}) do
		if not bar.config.alwaysShown then
			bar:Stop()
			bar.bar:Hide()
			if bar.secondBar then
				bar.secondBar:Stop()
				bar.secondBar.bar:Hide()
			end
		end
	end
	intersectTimer:Start()
end

function mod:SetSpell()
	for i, bar in pairs(self.bars or {}) do
		if not bar.config.alwaysShown then
			bar:Stop()
			bar.bar:Hide()
			if bar.secondBar then
				bar.secondBar:Stop()
				bar.secondBar.bar:Hide()
			end
		end
	end
	intersectTimer:Start()
end

function mod:OnHide()
	for i, bar in pairs(self.bars or {}) do
		if not bar.config.alwaysShown then
			bar:Stop()
			bar.bar:Hide()
			if bar.secondBar then
				bar.secondBar:Stop()
				bar.secondBar.bar:Hide()
			end
		end
	end
	intersectTimer:Stop()
end

local function colorGradient(perc)
    if perc <= 0.5 then
        return 1, perc*2, 0
    else
        return 2 - perc*2, 1, 0
    end
end

function mod:RebuildOpts()
	local defaults = WidgetBar.defaults
	self:ClearBars()
	wipe(options)
	for k, v in pairs(optionsDefaults) do
		options[k] = v
	end

	for i, db in ipairs(self.db.profile.bars) do
		options[db.name:gsub(" ", "_")] = {
			name = db.name,
			type="group",
			order = i,
			args = WidgetBar:GetOptions(db, StarTip.RebuildOpts, StarTip),
		}
		options[db.name:gsub(" ", "_")].args.delete = {
			name = L["Delete"],
			type = "execute",
			func = function()
				local delete = true
				for i, v in ipairs(defaultWidgets) do
					if db.name == v.name then
						db.deleted = true
						delete = false
					end
				end
				if delete then
					tremove(self.db.profile.bars, i)
				end
				self:ClearBars()
				StarTip:RebuildOpts()
			end,
			order = 100
		}
		options[db.name:gsub(" ", "_")].args.enabled = {
			name = L["Enabled"],
			desc = L["Whether the bar is enabled or not"],
			type = "toggle",
			get = function() return db.enabled end,
			set = function(info, v)
				db.enabled = v;
				db["enabledDirty"] = true
				self:ClearBars()
			end,
			order = 1
		}
		options[db.name:gsub(" ", "_")].args.texture1 = {
			name = L["Texture #1"],
			desc = L["This bar's texture"],
			type = "select",
			values = LSM:List("statusbar"),
			get = function() return StarTip:GetLSMIndexByName("statusbar", db.texture1 or LSM:GetDefault("statusbar"))  end,
			set = function(info, v)
				db.texture1 = LSM:List("statusbar")[v]
				db.texture1Dirty = true
				self:ClearBars()
			end,
			order = 5,
		}
		options[db.name:gsub(" ", "_")].args.texture2 = {
			name = L["Texture #2"],
			desc = L["This bar's texture"],
			type = "select",
			values = LSM:List("statusbar"),
			get = function() return StarTip:GetLSMIndexByName("statusbar", db.texture2 or db.texture1 or LSM:GetDefault("statusbar"))  end,
			set = function(info, v)
				db.texture2 = LSM:List("statusbar")[v]
				db.texture2Dirty = true
				self:ClearBars()
			end,
			order = 6,
		}
		options[db.name:gsub(" ", "_")].args.direction = nil
		options[db.name:gsub(" ", "_")].args.style = nil
	end
end