local mod = StarTip:NewModule("Histograms", "AceTimer-3.0") mod.name = "Histograms" mod.toggled = true --mod.childGroup = true mod.defaultOff = true local _G = _G local StarTip = _G.StarTip local GameTooltip = _G.GameTooltip local LSM = LibStub("LibSharedMedia-3.0") local WidgetHistogram = LibStub("LibScriptableWidgetHistogram-1.0") local LibCore = LibStub("LibScriptableLCDCore-1.0") local LibTimer = LibStub("LibScriptableUtilsTimer-1.0") local L = StarTip.L local unit local environment = {} local createHistograms local widgets = {} 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 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", expression = "return UnitHealth(unit)", min = "return 0", max = "return UnitHealthMax(unit)", enabled = true, width = 10, height = 50, points = {{"TOPLEFT", "StarTipQTipMain", "BOTTOMLEFT", 0, -12}}, color = [[ return HPColor(UnitHealth(unit), UnitHealthMax(unit)) ]], layer = 1, update = 1000, parent = "StarTipQTipMain" }, [2] = { name = "Power", expression = "return UnitMana(unit)", min = "return 0", max = "return UnitManaMax(unit)", enabled = true, width = 10, height = 50, points = {{"TOPRIGHT", "StarTipQTipMain", "BOTTOMRIGHT", -100, -12}}, color = [[ return PowerColor("RAGE", unit) ]], layer = 1, update = 1000, parent = "StarTipQTipMain" }, [3] = { name = "Mem", type = "histogram", expression = [[ local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip") if mem then return memperc end ]], color = [[ local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip") if mem then local num = floor(memperc) if num < 1 then num = 1 end if num > 100 then num = 100 end local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3] return r, g, b end ]], min = "return 0", max = "return 100", enabled = false, reversed = true, char = "0", width = 10, height = 50, points = {{"TOPLEFT", "StarTipQTipMain", "BOTTOMLEFT", 0, -77}}, layer = 1, update = 1000, persistent = true, intersect = true, intersectPad = 1000, parent = "StarTipQTipMain" }, [4] = { name = "CPU", type = "histogram", expression = [[ if not scriptProfile then return 0 end local cpu, percent, cpudiff, totalCPU, totaldiff, cpuperc = GetCPUUsage("StarTip") return cpuperc ]], color = [[ if not scriptProfile then return 0, 1, 0 end local cpu, percent, cpudiff, totalCPU, totaldiff, cpuperc = GetCPUUsage("StarTip") if cpu then local num = floor(cpuperc) if num < 1 then num = 1 end if num > 100 then num = 100 end local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3] return r, g, b end ]], min = "return 0", max = "return 100", enabled = false, reversed = true, char = "0", width = 10, height = 50, points = {{"TOPRIGHT", "StarTipQTipMain", "BOTTOMRIGHT", -100, -77}}, layer = 1, update = 1000, persistent = true, intersect = true, intersectPad = 100 }, } local defaults = { profile = { classColors = true, histograms = {}, intersect = true, intersectRate = 500 } } local options = {} local optionsDefaults = { add = { name = L["Add Histogram"], desc = L["Add a histogram"], type = "input", set = function(info, v) local widget = { name = v, type = "histogram", min = "return 0", max = "return 100", height = WidgetHistogram.defaults.height, width = WidgetHistogram.defaults.width, enabled = true, points = {{"TOPLEFT", "StarTipQTipMain", "BOTTOMLEFT", 0, -50}}, texture = LSM:GetDefault("statusbar"), expression = "return random(100)", color = "return 0, 0, 1", custom = true } tinsert(mod.db.profile.histograms, widget) StarTip:RebuildOpts() end, order = 5 }, defaults = { name = L["Restore Defaults"], desc = L["Restore Defaults"], type = "execute", func = function() mod.db.profile.histograms = copy(defaultWidgets); StarTip:RebuildOpts() end, order = 6 }, } local intersectUpdate = function() for i, w in ipairs(widgets) do w:IntersectUpdate() end end function updateHistogram(widget) for i = 1, #widget.history do local bar = widget.bars[i] local segment = widget.history[i] if not segment then break end if type(segment) == "table" then bar:SetValue((segment[1] or 0) * 100) local r, g, b, a = widget.history[i][2], widget.history[i][3], widget.history[i][4] bar:SetStatusBarColor(r, g, b, a) elseif type(segment) == "number" then bar:SetValue(segment * 100) bar:SetStatusBarColor(0, 0, 1, 1) end if not UnitExists(StarTip.unit) and not widget.config.alwaysShown then bar:Hide() end end end local textureDict = {} local new, del do local pool = {} function new(parent) if type(parent) == "string" then parent = _G[parent] end if type(parent) ~= "table" then parent = _G["StarTipQTipMain"] end local histogram = next(pool) if histogram then pool[histogram] = nil else histogram = CreateFrame("StatusBar", nil, parent) end return histogram end function del(histogram) pool[histogram] = true end end local function clearHistogram(obj) obj = mod.histograms and mod.histograms[obj] if not obj then return end for k, v in pairs(obj.bars) do del(v) v:Hide() end --obj:Del() end function mod:ClearHistograms() for k, v in pairs(mod.histograms) do clearHistogram(v) end wipe(mod.histograms) end local function createHistograms() if type(mod.histograms) ~= "table" then mod.histograms = {} end --[[for k, widget in pairs(mod.histograms) do for i = 1, widget.width or WidgetHistogram.defaults.width do widget.bars[i]:Hide() if widget.bars[i] then del(widget.bars[i]) end end wipe(widget.bars) end]] environment.unit = "mouseover" if UnitInRaid("player") then for i=1, GetNumRaidMembers() do if UnitGUID("mouseover") == UnitGUID("raid" .. i) then environment.unit = "raid" .. i end end end for k, v in pairs(mod.db.profile.histograms) do if v.enabled and not v.deleted then v.width = v.width or WidgetHistogram.defaults.width local widget = mod.histograms[v] local newWidget if not mod.histograms then mod.histograms = {} end if not widget then widget = WidgetHistogram:New(StarTip.core, v.name, v, v.row or 0, v.col or 0, 0, StarTip.db.profile.errorLevel, updateHistogram) tinsert(widgets, widget) widget.persistent = v.persistent newWidget = true for i = 0, v.width - 1 do local bar = new() bar:SetStatusBarTexture(LSM:Fetch("statusbar", v.texture)) bar:ClearAllPoints() for _, point in ipairs(v.points) do local arg1, arg2, arg3, arg4, arg5 = unpack(point) if (v.width > 100) then arg4 = (arg4 or 0) + i * (v.width / 100) else arg4 = (arg4 or 0) + i * v.width end arg5 = (arg5 or 0) bar:SetPoint(arg1, arg2, arg3, arg4, arg5) end if v.width then if (v.width > 100) then bar:SetWidth(v.width / 100) else bar:SetWidth(v.width or 6) end else bar:SetPoint("TOPLEFT", v.parent or _G["StarTipQTipMain"], "TOPLEFT") bar:SetPoint("BOTTOMLEFT", v.parent or _G["StarTipQTipMain"], "BOTTOMLEFT") end bar:SetHeight(v.height) bar:SetMinMaxValues(0, 100) bar:SetOrientation("VERTICAL") bar:SetValue(0) widget.frame = bar bar.widget = widget if not widget.bars then widget.bars = {} end tinsert(widget.bars, bar) end end widget.config.unit = StarTip.unit mod.histograms[v] = widget end end end function mod:CreateHistograms() createHistograms() end function mod:ReInit() if not self.db.profile.histograms then self.db.profile.histograms = {} end for i, v in ipairs(defaultWidgets) do for j, vv in ipairs(self.db.profile.histograms) 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 i, v in ipairs(defaultWidgets) do if not v.tagged and not v.deleted then tinsert(self.db.profile.histograms, copy(v)) end end end function mod:OnInitialize() self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults) self:ReInit() self.offset = 0 StarTip:SetOptionsDisabled(options, true) self.histograms = {} end function mod:OnEnable() StarTip:SetOptionsDisabled(options, false) if StarTip.db.profile.intersectRate > 0 then self.intersectTimer = self.intersectTimer or LibTimer:New("Texts.intersectTimer", self.db.profile.intersectRate or 500, true, intersectUpdate) end self:ClearHistograms() self:CreateHistograms() for k, histogram in pairs(self.histograms) do if histogram.config.alwaysShown then histogram:Start() for _, bar in pairs(histogram.bars) do bar:Show() end end end end function mod:OnDisable() self:ClearHistograms() StarTip:SetOptionsDisabled(options, true) if self.intersectTimer then self.intersectTimer:Stop() end end function mod:GetOptions() return options end local plugin = LibStub("LibScriptablePluginString-1.0") function mod:SetUnit() GameTooltipStatusBar:Hide() self.offset = 0 for k, widget in pairs(self.histograms) do for i = 1, widget.width or WidgetHistogram.defaults.width do widget.bars[i]:Show() end widget:Start() end if self.intersectTimer then self.intersectTimer:Start() end end function mod:SetItem() for k, widget in pairs(self.histograms) do if not widget.config.alwaysShown then for i, bar in pairs(widget.bars) do bar:Hide() end if not widget.persistent then widget:Stop() end end end if self.intersectTimer then self.intersectTimer:Start() end end function mod:SetSpell() for k, widget in pairs(self.histograms) do if not widget.config.alwaysShown then for i, bar in pairs(widget.bars) do bar:Hide() end if not widget.persistent then widget:Stop() end end end if self.intersectTimer then self.intersectTimer:Start() end end function mod:OnHide() for k, widget in pairs(self.histograms) do if not widget.config.alwaysShown then for i, bar in pairs(widget.bars) do bar:Hide() end if not widget.persistent then widget:Stop() end end end if self.intersectTimer then self.intersectTimer:Stop() end 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 = WidgetHistogram.defaults self:ClearHistograms() self:CreateHistograms() wipe(options) for k, v in pairs(optionsDefaults) do options[k] = v end for i, db in ipairs(self.db.profile.histograms) do options[db.name:gsub(" ", "_")] = { name = db.name, type="group", order = i, args=WidgetHistogram:GetOptions(db, StarTip.RebuildOpts, StarTip) } options[db.name:gsub(" ", "_")].args.delete = { name = L["Delete"], desc = L["Delete this widget"], 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 self.db.profile.histograms[i] = nil end self:ClearHistograms() StarTip:RebuildOpts() end, order = 13 } options[db.name:gsub(" ", "_")].args.enabled = { name = L["Enable"], desc = L["Toggle whether this histogram is enabled or not."], type = "toggle", get = function() return db.enabled end, set = function(info, v) db.enabled = v db["enabledDirty"] = true self:ClearHistograms() end, order = 1 } end end -- Colors, snagged from oUF local power = { [0] = { r = 48/255, g = 113/255, b = 191/255}, -- Mana [1] = { r = 226/255, g = 45/255, b = 75/255}, -- Rage [2] = { r = 255/255, g = 178/255, b = 0}, -- Focus [3] = { r = 1, g = 1, b = 34/255}, -- Energy [4] = { r = 0, g = 1, b = 1}, -- Happiness [5] = {}, --Unknown [6] = { r = 0.23, g = 0.12, b = 0.77 } -- Runic Power } local health = { [0] = {r = 49/255, g = 207/255, b = 37/255}, -- Health [1] = {r = .6, g = .6, b = .6} -- Tapped targets } local happiness = { [1] = {r = 1, g = 0, b = 0}, -- need.... | unhappy [2] = {r = 1 ,g = 1, b = 0}, -- new..... | content [3] = {r = 0, g = 1, b = 0}, -- colors.. | happy } --[[ function mod:UpdateHistogram() local unit = "mouseover" if not UnitExists(unit) then return end local min, max = UnitHealth(unit), UnitHealthMax(unit) self.hpHistogram:SetMinMaxValues(0, max) self.hpHistogram:SetValue(min) local color if self.db.profile.useGradient then color = StarTip.new() color.r, color.g, color.b = colorGradient(min/max) elseif(UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) or not UnitIsConnected(unit)) then color = health[1] elseif UnitIsPlayer(unit) then color = RAID_CLASS_COLORS[select(2, UnitClass(unit))] else color = StarTip.new() color.r, color.g, color.b = UnitSelectionColor(unit) end if not color then color = health[0] end self.hpHistogram:SetStatusBarColor(color.r, color.g, color.b) StarTip.del(color) end ]] -- Logic snagged from oUF --[[ function mod:UpdateHealth() local unit = "mouseover" if not UnitExists(unit) then return end local min, max = UnitHealth(unit), UnitHealthMax(unit) self.hpHistogram:SetMinMaxValues(0, max) self.hpHistogram:SetValue(min) local color if self.db.profile.useGradient then color = StarTip.new() color.r, color.g, color.b = colorGradient(min/max) elseif(UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) or not UnitIsConnected(unit)) then color = health[1] elseif UnitIsPlayer(unit) then color = RAID_CLASS_COLORS[select(2, UnitClass(unit))] else color = StarTip.new() color.r, color.g, color.b = UnitSelectionColor(unit) end if not color then color = health[0] end self.hpHistogram:SetStatusBarColor(color.r, color.g, color.b) StarTip.del(color) end function mod:UpdateMana() local unit = "mouseover" if not UnitExists(unit) then return end local min, max = UnitMana(unit), UnitManaMax(unit) self.mpHistogram:SetMinMaxValues(0, max) self.mpHistogram:SetValue(min) local color = power[UnitPowerType(unit)] self.mpHistogram:SetStatusBarColor(color.r, color.g, color.b) end ]]