diff --git a/Quartz/CastBarTemplate.lua b/Quartz/CastBarTemplate.lua new file mode 100644 index 0000000..3581954 --- /dev/null +++ b/Quartz/CastBarTemplate.lua @@ -0,0 +1,1077 @@ +--[[ + Copyright (C) 2006-2007 Nymbia + Copyright (C) 2010 Hendrik "Nevcairiel" Leppkes < h.leppkes@gmail.com > + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +]] +local Quartz3 = LibStub("AceAddon-3.0"):GetAddon("Quartz3") +local L = LibStub("AceLocale-3.0"):GetLocale("Quartz3") + +local media = LibStub("LibSharedMedia-3.0") +local lsmlist = AceGUIWidgetLSMlists + +---------------------------- +-- Upvalues +local min, type, format, unpack, setmetatable = math.min, type, string.format, unpack, setmetatable +local CreateFrame, GetTime, UIParent = CreateFrame, GetTime, UIParent +local UnitName, UnitCastingInfo, UnitChannelInfo = UnitName, UnitCastingInfo, UnitChannelInfo + +local CastBarTemplate = CreateFrame("Frame") +local CastBarTemplate_MT = {__index = CastBarTemplate} + +local TimeFmt, RomanFmt = Quartz3.Util.TimeFormat, Quartz3.Util.ConvertRankToRomanNumeral + +local playerName = UnitName("player") + +local function call(obj, method, ...) + if type(obj.parent[method]) == "function" then + return obj.parent[method](obj.parent, obj, ...) + end +end + +---------------------------- +-- Frame Scripts + +-- OnShow and OnHide are not used by the template +-- But forward the call to the embeding module, they might use it. +local function OnShow(self) + call(self, "OnShow") +end + +local function OnHide(self) + call(self, "OnHide") +end + +-- OnUpdate handles the bar movement and the text updates +local function OnUpdate(self) + local currentTime = GetTime() + local startTime, endTime, delay = self.startTime, self.endTime, self.delay + local db = self.config + if self.channeling or self.casting then + local perc, remainingTime, delayFormat, delayFormatTime + if self.casting then + local showTime = min(currentTime, endTime) + remainingTime = endTime - showTime + perc = (showTime - startTime) / (endTime - startTime) + + delayFormat, delayFormatTime = "|cffff0000+%.1f|cffffffff %s", "|cffff0000+%.1f|cffffffff %s / %s" + elseif self.channeling then + remainingTime = endTime - currentTime + perc = remainingTime / (endTime - startTime) + + delayFormat, delayFormatTime = "|cffff0000-%.1f|cffffffff %s", "|cffff0000-%.1f|cffffffff %s / %s" + end + + self.Bar:SetValue(perc) + self.Spark:ClearAllPoints() + self.Spark:SetPoint("CENTER", self.Bar, "LEFT", perc * db.w, 0) + + if delay and delay ~= 0 then + if db.hidecasttime then + self.TimeText:SetFormattedText("|cffff0000+%.1f|cffffffff %s", delay, format(TimeFmt(remainingTime))) + else + self.TimeText:SetFormattedText("|cffff0000+%.1f|cffffffff %s / %s", delay, format(TimeFmt(remainingTime)), format(TimeFmt(endTime - startTime, true))) + end + else + if db.hidecasttime then + self.TimeText:SetFormattedText(TimeFmt(remainingTime)) + else + self.TimeText:SetFormattedText("%s / %s", format(TimeFmt(remainingTime)), format(TimeFmt(endTime - startTime, true))) + end + end + + if currentTime > endTime then + self.casting, self.channeling = nil, nil + self.fadeOut = true + self.stopTime = currentTime + end + elseif self.fadeOut then + self.Spark:Hide() + local alpha + local stopTime = self.stopTime + if stopTime then + alpha = stopTime - currentTime + 1 + else + alpha = 0 + end + if alpha >= 1 then + alpha = 1 + end + if alpha <= 0 then + self.stopTime = nil + self:Hide() + else + self:SetAlpha(alpha*db.alpha) + end + else + self:Hide() + end +end +CastBarTemplate.OnUpdate = OnUpdate + +local function OnEvent(self, event, ...) + if self[event] then + self[event](self, event, ...) + end +end + +---------------------------- +-- Template Methods + +local function SetNameText(self, name, rank) + local mask, arg = nil, nil + if self.config.spellrank and rank then + mask, arg = RomanFmt(rank, self.config.spellrankstyle) + end + + if self.config.targetname and self.targetName and self.targetName ~= "" then + if mask then + mask = mask .. " -> " .. self.targetName + else + name = name .. " -> " .. self.targetName + end + end + if mask then + self.Text:SetFormattedText(mask, name, arg) + else + self.Text:SetText(name) + end +end +CastBarTemplate.SetNameText = SetNameText + +local function ToggleCastNotInterruptible(self, notInterruptible, init) + if self.unit == "player" and not init then return end + local db = self.config + + if notInterruptible and db.noInterruptChangeColor then + self.Bar:SetStatusBarColor(unpack(db.noInterruptColor)) + end + + local r, g, b, a + if notInterruptible and db.noInterruptChangeBorder then + self.backdrop.edgeFile = media:Fetch("border", db.noInterruptBorder) + r,g,b = unpack(db.noInterruptBorderColor) + a = db.noInterruptBorderAlpha + else + self.backdrop.edgeFile = media:Fetch("border", db.border) + r,g,b = unpack(Quartz3.db.profile.bordercolor) + a = Quartz3.db.profile.borderalpha + end + self:SetBackdrop(self.backdrop) + self:SetBackdropBorderColor(r, g, b, a) + + r, g, b = unpack(Quartz3.db.profile.backgroundcolor) + self:SetBackdropColor(r, g, b, Quartz3.db.profile.backgroundalpha) + + if self.Shield then + if notInterruptible and db.noInterruptShield and not db.hideicon then + self.Shield:Show() + else + self.Shield:Hide() + end + end + + self.lastNotInterruptible = notInterruptible +end +CastBarTemplate.ToggleCastNotInterruptible = ToggleCastNotInterruptible + +---------------------------- +-- Event Handlers + +function CastBarTemplate:UNIT_SPELLCAST_SENT(event, unit, spell, rank, target) + if unit ~= self.unit and not (self.unit == "player" and unit == "vehicle") then + return + end + if target then + self.targetName = target + else + -- auto selfcast? is this needed, even? + self.targetName = playerName + end + + call(self, "UNIT_SPELLCAST_SENT", unit, spell, rank, target) +end + +function CastBarTemplate:UNIT_SPELLCAST_START(event, unit) + if (unit ~= self.unit and not (self.unit == "player" and unit == "vehicle")) or call(self, "PreShowCondition", unit) then + return + end + local db = self.config + if event == "UNIT_SPELLCAST_START" then + self.casting, self.channeling = true, nil + else + self.casting, self.channeling = nil, true + end + + local spell, rank, displayName, icon, startTime, endTime, isTradeSkill, castID, notInterruptible + if self.casting then + spell, rank, displayName, icon, startTime, endTime, isTradeSkill, castID, notInterruptible = UnitCastingInfo(unit) + else -- self.channeling + spell, rank, displayName, icon, startTime, endTime, isTradeSkill, notInterruptible = UnitChannelInfo(unit) + -- channeling spells sometimes just display "Channeling" - this is not wanted + displayName = spell + end + -- in case this returned nothing + if not startTime then return end + + startTime = startTime / 1000 + endTime = endTime / 1000 + self.startTime = startTime + self.endTime = endTime + self.delay = 0 + self.fadeOut = nil + + self.Bar:SetStatusBarColor(unpack(self.casting and Quartz3.db.profile.castingcolor or Quartz3.db.profile.channelingcolor)) + + self.Bar:SetValue(self.casting and 0 or 1) + self:Show() + self:SetAlpha(db.alpha) + + SetNameText(self, displayName, rank) + + self.Spark:Show() + + if icon == "Interface\\Icons\\Temp" and Quartz3.db.profile.hidesamwise then + icon = nil + end + self.Icon:SetTexture(icon) + + local position = db.timetextposition + if position == "caststart" or position == "castend" then + if (position == "caststart" and self.casting) or (position == "castend" and self.channeling) then + self.TimeText:SetPoint("LEFT", self.Bar, "LEFT", db.timetextx, db.timetexty) + self.TimeText:SetJustifyH("LEFT") + else + self.TimeText:SetPoint("RIGHT", self.Bar, "RIGHT", -1 * db.timetextx, db.timetexty) + self.TimeText:SetJustifyH("RIGHT") + end + end + + ToggleCastNotInterruptible(self, notInterruptible) + + call(self, "UNIT_SPELLCAST_START", unit) +end +CastBarTemplate.UNIT_SPELLCAST_CHANNEL_START = CastBarTemplate.UNIT_SPELLCAST_START + +function CastBarTemplate:UNIT_SPELLCAST_STOP(event, unit) + if not (self.channeling or self.casting) or (unit ~= self.unit and not (self.unit == "player" and unit == "vehicle")) then + return + end + + self.Bar:SetValue(self.casting and 1.0 or 0) + self.Bar:SetStatusBarColor(unpack(Quartz3.db.profile.completecolor)) + + self.casting, self.channeling = nil, nil + self.fadeOut = true + self.stopTime = GetTime() + + self.TimeText:SetText("") + + call(self, "UNIT_SPELLCAST_STOP", unit) +end +CastBarTemplate.UNIT_SPELLCAST_CHANNEL_STOP = CastBarTemplate.UNIT_SPELLCAST_STOP + +function CastBarTemplate:UNIT_SPELLCAST_FAILED(event, unit) + if self.channeling or self.casting or (unit ~= self.unit and not (self.unit == "player" and unit == "vehicle")) then + return + end + self.fadeOut = true + if not self.stopTime then + self.stopTime = GetTime() + end + self.Bar:SetValue(1.0) + self.Bar:SetStatusBarColor(unpack(Quartz3.db.profile.failcolor)) + + self.TimeText:SetText("") + + call(self, "UNIT_SPELLCAST_FAILED", unit) +end + +function CastBarTemplate:UNIT_SPELLCAST_INTERRUPTED(event, unit) + if unit ~= self.unit and not (self.unit == "player" and unit == "vehicle") then + return + end + self.casting, self.channeling = nil, nil + self.fadeOut = true + if not self.stopTime then + self.stopTime = GetTime() + end + self.Bar:SetValue(1.0) + self.Bar:SetStatusBarColor(unpack(Quartz3.db.profile.failcolor)) + + self.TimeText:SetText("") + + call(self, "UNIT_SPELLCAST_INTERRUPTED", unit) +end +CastBarTemplate.UNIT_SPELLCAST_CHANNEL_INTERRUPTED = CastBarTemplate.UNIT_SPELLCAST_INTERRUPTED + +function CastBarTemplate:UNIT_SPELLCAST_DELAYED(event, unit) + if unit ~= self.unit and not (self.unit == "player" and unit == "vehicle") or call(self, "PreShowCondition", unit) then + return + end + local oldStart = self.startTime + local spell, rank, displayName, icon, startTime, endTime + if self.casting then + spell, rank, displayName, icon, startTime, endTime = UnitCastingInfo(unit) + else + spell, rank, displayName, icon, startTime, endTime = UnitChannelInfo(unit) + end + + if not startTime then + return self:Hide() + end + + startTime = startTime / 1000 + endTime = endTime / 1000 + self.startTime = startTime + self.endTime = endTime + + if self.casting then + self.delay = (self.delay or 0) + (startTime - (oldStart or startTime)) + else + self.delay = (self.delay or 0) + ((oldStart or startTime) - startTime) + end + + call(self, "UNIT_SPELLCAST_DELAYED", unit) +end +CastBarTemplate.UNIT_SPELLCAST_CHANNEL_UPDATE = CastBarTemplate.UNIT_SPELLCAST_DELAYED + + +function CastBarTemplate:UNIT_SPELLCAST_INTERRUPTIBLE(event, unit) + if unit ~= self.unit then + return + end + ToggleCastNotInterruptible(self, false) +end + +function CastBarTemplate:UNIT_SPELLCAST_NOT_INTERRUPTIBLE(event, unit) + if unit ~= self.unit then + return + end + ToggleCastNotInterruptible(self, true) +end + +function CastBarTemplate:UpdateUnit() + if UnitCastingInfo(self.unit) then + self:UNIT_SPELLCAST_START("UNIT_SPELLCAST_START", self.unit) + elseif UnitChannelInfo(self.unit) then + self:UNIT_SPELLCAST_START("UNIT_SPELLCAST_CHANNEL_START", self.unit) + else + self:Hide() + end +end + +function CastBarTemplate:SetConfig(config) + self.config = config +end + +function CastBarTemplate:ApplySettings() + local db = self.config + + self:ClearAllPoints() + if not db.x then + db.x = (UIParent:GetWidth() / 2 - (db.w * db.scale) / 2) / db.scale + end + self:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", db.x, db.y) + self:SetWidth(db.w + 10) + self:SetHeight(db.h + 10) + self:SetAlpha(db.alpha) + self:SetScale(db.scale) + + ToggleCastNotInterruptible(self, self.lastNotInterruptible, true) + + self.Bar:ClearAllPoints() + self.Bar:SetPoint("CENTER",self,"CENTER") + self.Bar:SetWidth(db.w) + self.Bar:SetHeight(db.h) + self.Bar:SetStatusBarTexture(media:Fetch("statusbar", db.texture)) + self.Bar:GetStatusBarTexture():SetHorizTile(false) + self.Bar:GetStatusBarTexture():SetVertTile(false) + self.Bar:SetMinMaxValues(0, 1) + + if db.hidetimetext then + self.TimeText:Hide() + else + self.TimeText:Show() + self.TimeText:ClearAllPoints() + self.TimeText:SetWidth(db.w) + local position = db.timetextposition + if position == "left" then + self.TimeText:SetPoint("LEFT", self.Bar, "LEFT", db.timetextx, db.timetexty) + self.TimeText:SetJustifyH("LEFT") + elseif position == "center" then + self.TimeText:SetPoint("CENTER", self.Bar, "CENTER", db.timetextx, db.timetexty) + self.TimeText:SetJustifyH("CENTER") + elseif position == "right" then + self.TimeText:SetPoint("RIGHT", self.Bar, "RIGHT", -1 * db.timetextx, db.timetexty) + self.TimeText:SetJustifyH("RIGHT") + end -- L["Cast Start Side"], L["Cast End Side"] -- handled at runtime + end + self.TimeText:SetFont(media:Fetch("font", db.font), db.timefontsize) + self.TimeText:SetShadowColor( 0, 0, 0, 1) + self.TimeText:SetShadowOffset( 0.8, -0.8 ) + self.TimeText:SetTextColor(unpack(Quartz3.db.profile.timetextcolor)) + self.TimeText:SetNonSpaceWrap(false) + self.TimeText:SetHeight(db.h) + + local temptext = self.TimeText:GetText() + if db.hidecasttime then + self.TimeText:SetFormattedText(TimeFmt(10)) + else + self.TimeText:SetFormattedText("%s / %s", format(TimeFmt(10)), format(TimeFmt(10, true))) + end + local normaltimewidth = self.TimeText:GetStringWidth() + self.TimeText:SetText(temptext) + + if db.hidenametext then + self.Text:Hide() + else + self.Text:Show() + self.Text:ClearAllPoints() + local position = db.nametextposition + if position == "left" then + self.Text:SetPoint("LEFT", self.Bar, "LEFT", db.nametextx, db.nametexty) + self.Text:SetJustifyH("LEFT") + if db.hidetimetext or db.timetextposition ~= "right" then + self.Text:SetWidth(db.w) + else + self.Text:SetWidth(db.w - normaltimewidth - 5) + end + elseif position == "center" then + self.Text:SetPoint("CENTER", self.Bar, "CENTER", db.nametextx, db.nametexty) + self.Text:SetJustifyH("CENTER") + else -- L["Right"] + self.Text:SetPoint("RIGHT", self.Bar, "RIGHT", -1 * db.nametextx, db.nametexty) + self.Text:SetJustifyH("RIGHT") + if db.hidetimetext or db.timetextposition ~= "left" then + self.Text:SetWidth(db.w) + else + self.Text:SetWidth(db.w - normaltimewidth - 5) + end + end + end + self.Text:SetFont(media:Fetch("font", db.font), db.fontsize) + self.Text:SetShadowColor( 0, 0, 0, 1) + self.Text:SetShadowOffset( 0.8, -0.8 ) + self.Text:SetTextColor(unpack(Quartz3.db.profile.spelltextcolor)) + self.Text:SetNonSpaceWrap(false) + self.Text:SetHeight(db.h) + + if db.hideicon then + self.Icon:Hide() + else + self.Icon:Show() + self.Icon:ClearAllPoints() + if db.iconposition == "left" then + self.Icon:SetPoint("RIGHT", self.Bar, "LEFT", -1 * db.icongap, 0) + else --L["Right"] + self.Icon:SetPoint("LEFT", self.Bar, "RIGHT", db.icongap, 0) + end + self.Icon:SetWidth(db.h) + self.Icon:SetHeight(db.h) + self.Icon:SetTexCoord(0.07, 0.93, 0.07, 0.93) + self.Icon:SetAlpha(db.iconalpha) + end + + self.Spark:SetTexture("Interface\\CastingBar\\UI-CastingBar-Spark") + self.Spark:SetVertexColor(unpack(Quartz3.db.profile.sparkcolor)) + self.Spark:SetBlendMode("ADD") + self.Spark:SetWidth(20) + self.Spark:SetHeight(db.h*2.2) +end + +function CastBarTemplate:RegisterEvents() + if self.unit == "player" then + self:RegisterEvent("UNIT_SPELLCAST_SENT") + end + self:RegisterEvent("UNIT_SPELLCAST_START") + self:RegisterEvent("UNIT_SPELLCAST_STOP") + self:RegisterEvent("UNIT_SPELLCAST_FAILED") + self:RegisterEvent("UNIT_SPELLCAST_DELAYED") + self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED") + self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START") + self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE") + self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP") + self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_INTERRUPTED") + if self.unit ~= "player" then + self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE") + self:RegisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE") + end + + media.RegisterCallback(self, "LibSharedMedia_SetGlobal", function(mtype, override) + if mtype == "statusbar" then + self.Bar:SetStatusBarTexture(media:Fetch("statusbar", override)) + end + end) + + media.RegisterCallback(self, "LibSharedMedia_Registered", function(mtype, key) + if mtype == "statusbar" and key == self.config.texture then + self.Bar:SetStatusBarTexture(media:Fetch("statusbar", self.config.texture)) + end + end) +end + +function CastBarTemplate:UnregisterEvents() + self:UnregisterAllEvents() + media.UnregisterCallback(self, "LibSharedMedia_SetGlobal") + media.UnregisterCallback(self, "LibSharedMedia_Registered") +end + +do + local function dragstart(self) + self:StartMoving() + end + + local function dragstop(self) + self.config.x = self:GetLeft() + self.config.y = self:GetBottom() + self:StopMovingOrSizing() + end + + local function nothing(self) + self:SetAlpha(self.config.alpha) + end + + function CastBarTemplate:Unlock() + self:Show() + self:EnableMouse(true) + self:SetScript("OnDragStart", dragstart) + self:SetScript("OnDragStop", dragstop) + self:SetAlpha(1) + self.Hide = nothing + self.Icon:SetTexture("Interface\\Icons\\Temp") + self.Text:SetText(self.unit) + end + + function CastBarTemplate:Lock() + self.Hide = nil + self:EnableMouse(false) + self:SetScript("OnDragStart", nil) + self:SetScript("OnDragStop", nil) + if not (self.channeling or self.casting) then + self:Hide() + end + end +end + + +---------------------------- +-- Options + +do + local function getBar(info) + return Quartz3.CastBarTemplate.bars[info[1]] + end + + local function hideiconoptions(info) + local db = getBar(info).config + return db.hideicon + end + + local function hidetimetextoptions(info) + local db = getBar(info).config + return db.hidetimetext + end + + local function hidecasttimeprecision(info) + local db = getBar(info).config + return db.hidetimetext or db.hidecasttime + end + + local function hidenametextoptions(info) + local db = getBar(info).config + return db.hidenametext + end + + local function hidespellrankstyle(info) + local db = getBar(info).config + return db.hidenametext or not db.spellrank + end + + local function noInterruptChangeBorder(info) + local db = getBar(info).config + return not db.noInterruptChangeBorder + end + + local function noInterruptChangeColor(info) + local db = getBar(info).config + return not db.noInterruptChangeColor + end + + local function icondisabled(info) + local db = getBar(info).config + return db.hideicon + end + + local function snapToCenter(info, v) + local bar = getBar(info) + local scale = bar.config.scale + if v == "horizontal" then + bar.config.x = (UIParent:GetWidth() / 2 - (bar.config.w * scale) / 2) / scale + else -- L["Vertical"] + bar.config.y = (UIParent:GetHeight() / 2 - (bar.config.h * scale) / 2) / scale + end + bar:ApplySettings() + end + + local function copySettings(info, v) + local bar = getBar(info) + local from = Quartz3:GetModule(v) + Quartz3:CopySettings(from.db.profile, bar.config) + bar:ApplySettings() + end + + local function getEnabled(info) + local bar = getBar(info) + return Quartz3:GetModuleEnabled(bar.modName) + end + + local function setEnabled(info, v) + local bar = getBar(info) + return Quartz3:SetModuleEnabled(bar.modName, v) + end + + local function getOpt(info) + local db = getBar(info).config + return db[info[#info]] + end + + local function setOpt(info, value) + local bar = getBar(info) + bar.config[info[#info]] = value + bar:ApplySettings() + end + + local function getColor(info) + return unpack(getOpt(info)) + end + + local function setColor(info, ...) + setOpt(info, {...}) + end + + function CastBarTemplate:CreateOptions() + local options = { + type = "group", + name = self.localizedName, + get = getOpt, + set = setOpt, + args = { + toggle = { + type = "toggle", + name = L["Enable"], + desc = L["Enable"], + get = getEnabled, + set = setEnabled, + order = 99, + width = "full", + }, + h = { + type = "range", + name = L["Height"], + desc = L["Height"], + min = 10, max = 50, step = 1, + order = 200, + }, + w = { + type = "range", + name = L["Width"], + desc = L["Width"], + min = 50, max = 1500, bigStep = 5, + order = 200, + }, + x = { + type = "range", + name = L["X"], + desc = L["Set an exact X value for this bar's position."], + min = -2560, max = 2560, bigStep = 1, + order = 200, + }, + y = { + type = "range", + name = L["Y"], + desc = L["Set an exact Y value for this bar's position."], + min = -1600, max = 1600, bigStep = 1, + order = 200, + }, + scale = { + type = "range", + name = L["Scale"], + desc = L["Scale"], + min = 0.2, max = 1, bigStep = 0.025, + order = 201, + }, + alpha = { + type = "range", + name = L["Alpha"], + desc = L["Alpha"], + isPercent = true, + min = 0.1, max = 1, bigStep = 0.025, + order = 202, + }, + icon = { + type = "header", + name = L["Icon"], + order = 300, + }, + hideicon = { + type = "toggle", + name = L["Hide Icon"], + desc = L["Hide Spell Cast Icon"], + order = 301, + }, + iconposition = { + type = "select", + name = L["Icon Position"], + desc = L["Set where the Spell Cast icon appears"], + disabled = hideiconoptions, + values = {["left"] = L["Left"], ["right"] = L["Right"]}, + order = 301, + }, + iconalpha = { + type = "range", + name = L["Icon Alpha"], + desc = L["Set the Spell Cast icon alpha"], + isPercent = true, + min = 0.1, max = 1, bigStep = 0.025, + order = 302, + disabled = hideiconoptions, + }, + icongap = { + type = "range", + name = L["Icon Gap"], + desc = L["Space between the cast bar and the icon."], + min = -35, max = 35, bigStep = 1, + order = 302, + disabled = hideiconoptions, + }, + fonthead = { + type = "header", + name = L["Font and Text"], + order = 398, + }, + font = { + type = "select", + dialogControl = "LSM30_Font", + name = L["Font"], + desc = L["Set the font used in the Name and Time texts"], + values = lsmlist.font, + order = 399, + }, + nlfont = { + type = "description", + name = "", + order = 400, + }, + hidenametext = { + type = "toggle", + name = L["Hide Spell Name"], + desc = L["Disable the text that displays the spell name/rank"], + order = 401, + }, + nlname = { + type = "description", + name = "", + order = 403, + }, + nametextposition = { + type = "select", + name = L["Spell Name Position"], + desc = L["Set the alignment of the spell name text"], + values = {["left"] = L["Left"], ["right"] = L["Right"], ["center"] = L["Center"]}, + disabled = hidenametextoptions, + order = 404, + }, + fontsize = { + type = "range", + name = L["Spell Name Font Size"], + desc = L["Set the size of the spell name text"], + min = 7, max = 20, step = 1, + order = 405, + disabled = hidenametextoptions, + }, + nametextx = { + type = "range", + name = L["Spell Name X Offset"], + desc = L["Adjust the X position of the spell name text"], + min = -35, max = 35, step = 1, + disabled = hidenametextoptions, + order = 406, + }, + nametexty = { + type = "range", + name = L["Spell Name Y Offset"], + desc = L["Adjust the Y position of the name text"], + min = -35, max = 35, step = 1, + disabled = hidenametextoptions, + order = 407, + }, + spellrank = { + type = "toggle", + name = L["Spell Rank"], + desc = L["Display the rank of spellcasts alongside their name"], + disabled = hidenametextoptions, + order = 408, + }, + spellrankstyle = { + type = "select", + name = L["Spell Rank Style"], + desc = L["Set the display style of the spell rank"], + disabled = hidespellrankstyle, + values = {["number"] = L["Number"], ["roman"] = L["Roman"], ["full"] = L["Full Text"], ["romanfull"] = L["Roman Full Text"]}, + order = 409, + }, + hidetimetext = { + type = "toggle", + name = L["Hide Time Text"], + desc = L["Disable the text that displays the time remaining on your cast"], + order = 411, + }, + hidecasttime = { + type = "toggle", + name = L["Hide Cast Time"], + desc = L["Disable the text that displays the total cast time"], + disabled = hidetimetextoptions, + order = 412, + }, + timefontsize = { + type = "range", + name = L["Time Font Size"], + desc = L["Set the size of the time text"], + min = 7, max = 20, step = 1, + order = 414, + disabled = hidetimetextoptions, + }, + timetextposition = { + type = "select", + name = L["Time Text Position"], + desc = L["Set the alignment of the time text"], + values = {["left"] = L["Left"], ["right"] = L["Right"], ["center"] = L["Center"], ["caststart"] = L["Cast Start Side"], ["castend"] = L["Cast End Side"]}, + disabled = hidetimetextoptions, + order = 415, + }, + timetextx = { + type = "range", + name = L["Time Text X Offset"], + desc = L["Adjust the X position of the time text"], + min = -35, max = 35, step = 1, + disabled = hidetimetextoptions, + order = 416, + }, + timetexty = { + type = "range", + name = L["Time Text Y Offset"], + desc = L["Adjust the Y position of the time text"], + min = -35, max = 35, step = 1, + disabled = hidetimetextoptions, + order = 417, + }, + textureheader = { + type = "header", + name = L["Texture and Border"], + order = 450, + }, + texture = { + type = "select", + dialogControl = "LSM30_Statusbar", + name = L["Texture"], + desc = L["Set the Cast Bar Texture"], + values = lsmlist.statusbar, + order = 451, + }, + border = { + type = "select", + dialogControl = "LSM30_Border", + name = L["Border"], + desc = L["Set the border style"], + values = lsmlist.border, + order = 452, + }, + noInterruptGroup = { + type = "group", + name = L["No interrupt cast bars"], + dialogInline = true, + order = 455, + args = { + noInterruptChangeBorder = { + type = "toggle", + name = L["Change Border Style"], + desc = L["Adjust the Border Style for non-interruptible Cast Bars"], + order = 1, + }, + noInterruptBorder = { + type = "select", + name = L["Border"], + desc = L["Set the border style for no interrupt casting bars"], + dialogControl = "LSM30_Border", + values = lsmlist.border, + order = 2, + disabled = noInterruptChangeBorder, + }, + noInterruptBorderColor = { + type = "color", + name = L["Border Color"], + desc = L["Set the color of the no interrupt casting bar border"], + get = getColor, + set = setColor, + order = 3, + disabled = noInterruptChangeBorder, + }, + noInterruptBorderAlpha = { + type = "range", + name = L["Border Alpha"], + desc = L["Set the alpha of the no interrupt casting bar border"], + isPercent = true, + min = 0, max = 1, bigStep = 0.025, + order = 4, + disabled = noInterruptChangeBorder, + }, + noInterruptChangeColor = { + type = "toggle", + name = L["Change Color"], + desc = L["Change the color of non-interruptible Cast Bars"], + order = 10, + }, + noInterruptColor = { + type = "color", + name = L["Cast Bar Color"], + desc = L["Configure the color of the cast bar."], + disabled = noInterruptChangeColor, + set = setColor, + get = getColor, + order = 11, + }, + noInterruptShield = { + type = "toggle", + name = L["Show Shield Icon"], + desc = L["Show the Shield Icon on non-interruptible Cast Bars"], + disabled = icondisabled, + }, + }, + }, + toolheader = { + type = "header", + name = L["Tools"], + order = 500, + }, + snaptocenter = { + type = "select", + name = L["Snap to Center"], + desc = L["Move the CastBar to center of the screen along the specified axis"], + get = false, + set = snapToCenter, + values = {["horizontal"] = L["Horizontal"], ["vertical"] = L["Vertical"]}, + order = 503, + }, + copysettings = { + type = "select", + name = L["Copy Settings From"], + desc = L["Select a bar from which to copy settings"], + get = false, + set = copySettings, + values = {["Target"] = L["Target"], ["Focus"] = L["Focus"], ["Pet"] = L["Pet"], ["Player"] = L["Player"]}, + order = 504 + } + } + } + return options + end +end + +Quartz3.CastBarTemplate = {} +Quartz3.CastBarTemplate.defaults = { + --x = -- applied automatically in applySettings() + y = 180, + h = 25, + w = 250, + scale = 1, + texture = "Blizzard", + hideicon = false, + alpha = 1, + iconalpha = 0.9, + iconposition = "left", + icongap = 4, + hidenametext = false, + nametextposition = "left", + timetextposition = "right", + font = "Friz Quadrata TT", + fontsize = 14, + hidetimetext = false, + hidecasttime = false, + timefontsize = 12, + targetname = false, + spellrank = false, + spellrankstyle = "roman", + border = "Blizzard Tooltip", + nametextx = 3, + nametexty = 0, + timetextx = 3, + timetexty = 0, + + noInterruptBorderChange = false, + noInterruptBorder = "Tooltip enlarged", + noInterruptBorderColor = {0.71, 0.73, 0.71}, -- Default color chosen by playing around with settings, rounded to 2 significant digits + noInterruptBorderAlpha = 1, + noInterruptColorChange = false, + noInterruptColor = {1.0, 0.49, 0}, + noInterruptShield = true, +} +Quartz3.CastBarTemplate.template = CastBarTemplate +Quartz3.CastBarTemplate.bars = {} +function Quartz3.CastBarTemplate:new(parent, unit, name, localizedName, config) + local frameName = "Quartz3CastBar" .. name + local bar = setmetatable(CreateFrame("Frame", frameName, UIParent), CastBarTemplate_MT) + bar.unit = unit + bar.parent = parent + bar.config = config + bar.modName = name + bar.localizedName = localizedName + bar.locked = true + + Quartz3.CastBarTemplate.bars[name] = bar + + bar:SetFrameStrata("MEDIUM") + bar:SetScript("OnShow", OnShow) + bar:SetScript("OnHide", OnHide) + bar:SetScript("OnUpdate", OnUpdate) + bar:SetScript("OnEvent", OnEvent) + bar:SetMovable(true) + bar:RegisterForDrag("LeftButton") + bar:SetClampedToScreen(true) + + bar.Bar = CreateFrame("StatusBar", nil, bar) + bar.Text = bar.Bar:CreateFontString(nil, "OVERLAY") + bar.TimeText = bar.Bar:CreateFontString(nil, "OVERLAY") + bar.Icon = bar.Bar:CreateTexture(nil, "DIALOG") + bar.Spark = bar.Bar:CreateTexture(nil, "OVERLAY") + if unit ~= "player" then + bar.Shield = bar.Bar:CreateTexture(nil, "ARTWORK") + bar.Shield:SetTexture("Interface\\CastingBar\\UI-CastingBar-Small-Shield") + bar.Shield:SetTexCoord(0, 36/256, 0, 1) + bar.Shield:SetWidth(36) + bar.Shield:SetHeight(64) + bar.Shield:SetPoint("CENTER", bar.Icon, "CENTER", -2, -1) + bar.Shield:Hide() + end + + bar.lastNotInterruptible = false + + bar.backdrop = { bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", + tile = true, tileSize = 16, edgeSize = 16, --edgeFile = "", -- set by ApplySettings + insets = {left = 4, right = 4, top = 4, bottom = 4} } + bar:Hide() + + return bar +end diff --git a/Quartz/Changelog-Quartz-3.0.3.1.txt b/Quartz/Changelog-Quartz-3.0.3.1.txt new file mode 100644 index 0000000..c6315a3 --- /dev/null +++ b/Quartz/Changelog-Quartz-3.0.3.1.txt @@ -0,0 +1,12 @@ +tag 3.0.3.1 +efd06041a5297a4c7f2a6e648ce15d2d81d25d92 +Hendrik Leppkes +2010-07-26 21:40:13 +0200 + +Tag as 3.0.3.1 for lib upgrades. + + +-------------------- + +Hendrik Leppkes: + - Use "tag: latest" for SMW and LSM diff --git a/Quartz/Config.lua b/Quartz/Config.lua new file mode 100644 index 0000000..3b07a68 --- /dev/null +++ b/Quartz/Config.lua @@ -0,0 +1,215 @@ +--[[ + Copyright (C) 2006-2007 Nymbia + Copyright (C) 2010 Hendrik "Nevcairiel" Leppkes < h.leppkes@gmail.com > + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +]] +local Quartz3 = LibStub("AceAddon-3.0"):GetAddon("Quartz3") +local L = LibStub("AceLocale-3.0"):GetLocale("Quartz3") +local media = LibStub("LibSharedMedia-3.0") + +---------------------------- +-- Upvalues +-- GLOBALS: LibStub, InterfaceOptionsFrame_OpenToCategory +local pairs, unpack, type = pairs, unpack, type + +local getOpt, setOpt, getColor, setColor +do + function getOpt(info) + local key = info[#info] + return Quartz3.db.profile[key] + end + + function setOpt(info, value) + local key = info[#info] + Quartz3.db.profile[key] = value + Quartz3:ApplySettings() + end + + function getColor(info) + return unpack(getOpt(info)) + end + + function setColor(info, r, g, b, a) + setOpt(info, {r, g, b, a}) + end +end + +local options, moduleOptions = nil, {} +local function getOptions() + if not options then + options = { + type = "group", + args = { + general = { + type = "group", + inline = true, + name = "", + args = { + unlock = { + type = "execute", + name = L["Toggle Bar Lock"], + desc = L["Unlock the Bars to be able to move them around."], + func = function() + Quartz3:ToggleLock(true) + end, + order = 50, + }, + nllock = { + type = "description", + name = "", + order = 51, + }, + hidesamwise = { + type = "toggle", + name = L["Hide Samwise Icon"], + desc = L["Hide the icon for spells with no icon"], + order = 101, + get = getOpt, + set = setOpt, + }, + casttimeprecision = { + type = "range", + name = L["Cast Time Precision"], + desc = L["Number of decimals to show for the Cast Time"], + min = 0, max = 3, step = 1, + get = getOpt, + set = setOpt, + order = 102, + }, + colors = { + type = "group", + name = L["Colors"], + desc = L["Colors"], + guiInline = true, + order = 450, + get = getColor, + set = setColor, + args = { + spelltextcolor = { + type = "color", + name = L["Spell Text"], + desc = L["Set the color of the %s"]:format(L["Spell Text"]), + order = 98, + }, + timetextcolor = { + type = "color", + name = L["Time Text"], + desc = L["Set the color of the %s"]:format(L["Time Text"]), + order = 98, + }, + header = { + type = "header", + name = "", + order = 99, + }, + castingcolor = { + type = "color", + name = L["Casting"], + desc = L["Set the color of the cast bar when %s"]:format(L["Casting"]), + }, + channelingcolor = { + type = "color", + name = L["Channeling"], + desc = L["Set the color of the cast bar when %s"]:format(L["Channeling"]), + }, + completecolor = { + type = "color", + name = L["Complete"], + desc = L["Set the color of the cast bar when %s"]:format(L["Complete"]), + }, + failcolor = { + type = "color", + name = L["Failed"], + desc = L["Set the color of the cast bar when %s"]:format(L["Failed"]), + }, + sparkcolor = { + type = "color", + name = L["Spark Color"], + desc = L["Set the color of the casting bar spark"], + hasAlpha = true, + }, + nl1 = { + type = "description", + name = "", + order = 101, + }, + backgroundcolor = { + type = "color", + name = L["Background"], + desc = L["Set the color of the casting bar background"], + order = 102, + }, + backgroundalpha = { + type = "range", + name = L["Background Alpha"], + desc = L["Set the alpha of the casting bar background"], + isPercent = true, + min = 0, max = 1, bigStep = 0.025, + get = getOpt, + set = setOpt, + order = 103, + }, + bordercolor = { + type = "color", + name = L["Border"], + desc = L["Set the color of the casting bar border"], + order = 104, + }, + borderalpha = { + type = "range", + name = L["Border Alpha"], + desc = L["Set the alpha of the casting bar border"], + isPercent = true, + min = 0, max = 1, bigStep = 0.025, + get = getOpt, + set = setOpt, + order = 105, + }, + }, + }, + }, + }, + }, + } + for k,v in pairs(moduleOptions) do + options.args[k] = (type(v) == "function") and v() or v + end + end + return options +end + +function Quartz3:ChatCommand(input) + if not input or input:trim() == "" then + InterfaceOptionsFrame_OpenToCategory(Quartz3.optFrames.Profiles) + InterfaceOptionsFrame_OpenToCategory(Quartz3.optFrames.Quartz3) + else + LibStub("AceConfigCmd-3.0").HandleCommand(Quartz3, "quartz", "Quartz3", input) + end +end + +function Quartz3:SetupOptions() + self.optFrames = {} + LibStub("AceConfigRegistry-3.0"):RegisterOptionsTable("Quartz3", getOptions) + self.optFrames.Quartz3 = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("Quartz3", "Quartz 3", nil, "general") + self:RegisterModuleOptions("Profiles", LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db), "Profiles") + self:RegisterChatCommand("quartz", "ChatCommand") + self:RegisterChatCommand("q3", "ChatCommand") +end + +function Quartz3:RegisterModuleOptions(name, optTable, displayName) + moduleOptions[name] = optTable + self.optFrames[name] = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("Quartz3", displayName or name, "Quartz 3", name) +end diff --git a/Quartz/GPLv2.txt b/Quartz/GPLv2.txt new file mode 100644 index 0000000..e37680c --- /dev/null +++ b/Quartz/GPLv2.txt @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/Quartz/Quartz.lua b/Quartz/Quartz.lua new file mode 100644 index 0000000..63df85b --- /dev/null +++ b/Quartz/Quartz.lua @@ -0,0 +1,271 @@ +--[[ + Copyright (C) 2006-2007 Nymbia + Copyright (C) 2010 Hendrik "Nevcairiel" Leppkes < h.leppkes@gmail.com > + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +]] +local Quartz3 = LibStub("AceAddon-3.0"):NewAddon("Quartz3", "AceConsole-3.0") +local L = LibStub("AceLocale-3.0"):GetLocale("Quartz3") +local media = LibStub("LibSharedMedia-3.0") +local db + +---------------------------- +-- Upvalues +-- GLOBALS: LibStub, QuartzDB +local type, pairs, tonumber = type, pairs, tonumber + +local defaults = { + profile = { + modules = { ["*"] = true }, + hidesamwise = true, + sparkcolor = {1, 1, 1, 0.5}, + spelltextcolor = {1, 1, 1}, + timetextcolor = {1, 1, 1}, + castingcolor = {1.0, 0.49, 0}, + channelingcolor = {0.32, 0.3, 1}, + completecolor = {0.12, 0.86, 0.15}, + failcolor = {1.0, 0.09, 0}, + backgroundcolor = {0, 0, 0}, + bordercolor = {0, 0, 0}, + backgroundalpha = 1, + borderalpha = 1, + casttimeprecision = 1, + }, +} + +media:Register("statusbar", "BantoBar", "Interface\\Addons\\Quartz\\textures\\BantoBar") +media:Register("statusbar", "Frost", "Interface\\AddOns\\Quartz\\textures\\Frost") +media:Register("statusbar", "Healbot", "Interface\\AddOns\\Quartz\\textures\\Healbot") +media:Register("statusbar", "LiteStep", "Interface\\AddOns\\Quartz\\textures\\LiteStep") +media:Register("statusbar", "Rocks", "Interface\\AddOns\\Quartz\\textures\\Rocks") +media:Register("statusbar", "Runes", "Interface\\AddOns\\Quartz\\textures\\Runes") +media:Register("statusbar", "Xeon", "Interface\\AddOns\\Quartz\\textures\\Xeon") +media:Register("border", "Tooltip enlarged", "Interface\\AddOns\\Quartz\\textures\\Tooltip-BigBorder") + +function Quartz3:OnInitialize() + self.db = LibStub("AceDB-3.0"):New("Quartz3DB", defaults, true) + db = self.db.profile + + self:SetupOptions() +end + +function Quartz3:OnEnable() + if QuartzDB then + QuartzDB = nil + LibStub("AceTimer-3.0").ScheduleTimer(self, function() + self:Print(L["Congratulations! You've just upgraded Quartz from the old Ace2-based version to the new Ace3 version!"]) + self:Print(L["Sadly, this also means your configuration was lost. You'll have to reconfigure Quartz using the new options integrated into the Interface Options Panel, quickly accessible with /quartz"]) + self:Print(L["Sorry for the inconvenience, and thanks for using Quartz!"]) + end, 1) + end + self.db.RegisterCallback(self, "OnProfileChanged", "ApplySettings") + self.db.RegisterCallback(self, "OnProfileCopied", "ApplySettings") + self.db.RegisterCallback(self, "OnProfileReset", "ApplySettings") + + media.RegisterCallback(self, "LibSharedMedia_Registered", "ApplySettings") + media.RegisterCallback(self, "LibSharedMedia_SetGlobal", "ApplySettings") + + CONFIGMODE_CALLBACKS = CONFIGMODE_CALLBACKS or {} + CONFIGMODE_CALLBACKS["Quartz3"] = function(action) + if action == "ON" then + self:Unlock(false) + elseif action == "OFF" then + self:Lock() + end + end + + self:ApplySettings() +end + +function Quartz3:ApplySettings() + db = self.db.profile + + for k,v in self:IterateModules() do + if self:GetModuleEnabled(k) and not v:IsEnabled() then + self:EnableModule(k) + elseif not self:GetModuleEnabled(k) and v:IsEnabled() then + self:DisableModule(k) + end + if type(v.ApplySettings) == "function" then + v:ApplySettings() + end + end +end + +function Quartz3:ToggleLock(showUI) + local func = self.unlock and "Lock" or "Unlock" + self[func](self, showUI) +end + +function Quartz3:Unlock(showUI) + self.unlock = true + for k,v in self:IterateModules() do + if v:IsEnabled() and type(v.Unlock) == "function" then + v:Unlock() + end + end + if showUI then + self:ShowUnlockDialog() + end +end + +function Quartz3:Lock() + self.unlock = nil + for k,v in self:IterateModules() do + if v:IsEnabled() and type(v.Lock) == "function" then + v:Lock() + end + end + if self.unlock_dialog then self.unlock_dialog:Hide() end +end + +function Quartz3:ShowUnlockDialog() + if not self.unlock_dialog then + local f = CreateFrame("Frame", "Quartz3UnlockDialog", UIParent) + f:SetFrameStrata("DIALOG") + f:SetToplevel(true) + f:EnableMouse(true) + f:SetClampedToScreen(true) + f:SetWidth(360) + f:SetHeight(110) + f:SetBackdrop{ + bgFile="Interface\\DialogFrame\\UI-DialogBox-Background" , + edgeFile="Interface\\DialogFrame\\UI-DialogBox-Border", + tile = true, + insets = {left = 11, right = 12, top = 12, bottom = 11}, + tileSize = 32, + edgeSize = 32, + } + f:SetPoint("TOP", 0, -50) + f:Hide() + f:SetScript("OnShow", function() PlaySound("igMainMenuOption") end) + f:SetScript("OnHide", function() PlaySound("gsTitleOptionExit") end) + + local tr = f:CreateTitleRegion() + tr:SetAllPoints(f) + + local header = f:CreateTexture(nil, "ARTWORK") + header:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header") + header:SetWidth(256); header:SetHeight(64) + header:SetPoint("TOP", 0, 12) + + local title = f:CreateFontString("ARTWORK") + title:SetFontObject("GameFontNormal") + title:SetPoint("TOP", header, "TOP", 0, -14) + title:SetText(L["Quartz3"]) + + local desc = f:CreateFontString("ARTWORK") + desc:SetFontObject("GameFontHighlight") + desc:SetJustifyV("TOP") + desc:SetJustifyH("LEFT") + desc:SetPoint("TOPLEFT", 18, -32) + desc:SetPoint("BOTTOMRIGHT", -18, 48) + desc:SetText(L["Bars unlocked. Move them now and click Lock when you are done."]) + + local lockBars = CreateFrame("CheckButton", "Quartz3UnlockDialogLock", f, "OptionsButtonTemplate") + getglobal(lockBars:GetName() .. "Text"):SetText(L["Lock"]) + + lockBars:SetScript("OnClick", function(self) + Quartz3:Lock() + LibStub("AceConfigRegistry-3.0"):NotifyChange("Quartz3") + end) + + --position buttons + lockBars:SetPoint("BOTTOMRIGHT", -14, 14) + + self.unlock_dialog = f + end + self.unlock_dialog:Show() +end + +local copyExclude = { + x = true, + y = true, +} + +function Quartz3:CopySettings(from, to) + for k,v in pairs(from) do + if to[k] and not copyExclude[k] and type(v) ~= "table" then + to[k] = v + end + end +end + +function Quartz3:GetModuleEnabled(module) + return db.modules[module] +end + +function Quartz3:SetModuleEnabled(module, value) + local old = db.modules[module] + db.modules[module] = value + if old ~= value then + if value then + self:EnableModule(module) + else + self:DisableModule(module) + end + end +end + +function Quartz3:Merge(source, target) + if type(target) ~= "table" then target = {} end + for k,v in pairs(source) do + if type(v) == "table" then + target[k] = self:Merge(v, target[k]) + elseif not target[k] then + target[k] = v + end + end + return target +end + +Quartz3.Util = {} +function Quartz3.Util.TimeFormat(num, isCastTime) + if num <= 10 or (isCastTime and num <= 60) then + return ("%%.%df"):format(db.casttimeprecision), num + elseif num <= 60 then + return "%d", num + elseif num <= 3600 then + return "%d:%02d", num / 60, num % 60 + else + return "%d:%02d", num / 3600, (num % 3600) / 60 + end +end + +do + local numerals = { -- 25"s enough for now, I think? + "I", "II", "III", "IV", "V", + "VI", "VII", "VIII", "IX", "X", + "XI", "XII", "XIII", "XIV", "XV", + "XVI", "XVII", "XVIII", "XIX", "XX", + "XXI", "XXII", "XXIII", "XXIV", "XXV", + } + function Quartz3.Util.ConvertRankToRomanNumeral(rank, style) + local mask, arg = nil, nil + local number = tonumber(rank:match(L["Rank (%d+)"])) + if number and number > 0 then + if style == "number" then + mask, arg = "%s %d", number + elseif style == "full" then + mask, arg = "%s (%s)", rank + elseif style == "roman" then + mask, arg = "%s %s", numerals[number] + else -- full roman + mask, arg = "%s (%s)", L["Rank %s"]:format(numerals[number]) + end + end + return mask, arg + end +end diff --git a/Quartz/Quartz.toc b/Quartz/Quartz.toc new file mode 100644 index 0000000..f2a7801 --- /dev/null +++ b/Quartz/Quartz.toc @@ -0,0 +1,61 @@ +## Title: Quartz +## Interface: 30300 +## Notes: Modular casting bar. +## Author: Nevcairiel, Nymbia +## Version: 3.0.3.1 +## X-License: GPL v2 +## X-Credits: Ammo (some code based on PitBull_CastBar), kergoth (Tradeskill Merge module idea), Roartindon (Lag Embed mode for Latency module) +## X-Curse-Packaged-Version: 3.0.3.1 +## X-Curse-Project-Name: Quartz +## X-Curse-Project-ID: quartz +## X-Curse-Repository-ID: wow/quartz/mainline + +## Title-ruRU: Кварц +## Notes-ruRU: Модульная полоса применений. +## Notes-frFR: Barres d'incantation modulaires. +## Notes-zhCN: 模块化施法条。 +## Notes-zhTW: 模組化施法條。 + +## SavedVariables: Quartz3DB +## OptionalDeps: Ace3, LibSharedMedia-3.0, AceGUI-3.0-SharedMediaWidgets, SharedMedia, FlightMap + +#@no-lib-strip@ +libs\LibStub\LibStub.lua +libs\CallbackHandler-1.0\CallbackHandler-1.0.xml +libs\AceAddon-3.0\AceAddon-3.0.xml +libs\AceGUI-3.0\AceGUI-3.0.xml +libs\AceConfig-3.0\AceConfig-3.0.xml +libs\AceConsole-3.0\AceConsole-3.0.xml +libs\AceDB-3.0\AceDB-3.0.xml +libs\AceDBOptions-3.0\AceDBOptions-3.0.xml +libs\AceEvent-3.0\AceEvent-3.0.xml +libs\AceTimer-3.0\AceTimer-3.0.xml +libs\AceBucket-3.0\AceBucket-3.0.xml +libs\AceLocale-3.0\AceLocale-3.0.xml +libs\AceHook-3.0\AceHook-3.0.xml + +libs\LibSharedMedia-3.0\lib.xml +libs\AceGUI-3.0-SharedMediaWidgets\widget.xml +#@end-no-lib-strip@ + +locale\locale.xml + +Quartz.lua +Config.lua + +CastBarTemplate.lua + +modules\Player.lua +modules\Target.lua +modules\Focus.lua +modules\Pet.lua +modules\Latency.lua +modules\Tradeskill.lua +modules\GCD.lua +modules\Buff.lua +modules\Mirror.lua +modules\Timer.lua +modules\Swing.lua +modules\Interrupt.lua +modules\Range.lua +modules\Flight.lua diff --git a/Quartz/libs/AceAddon-3.0/AceAddon-3.0.lua b/Quartz/libs/AceAddon-3.0/AceAddon-3.0.lua new file mode 100644 index 0000000..6c89654 --- /dev/null +++ b/Quartz/libs/AceAddon-3.0/AceAddon-3.0.lua @@ -0,0 +1,642 @@ +--- **AceAddon-3.0** provides a template for creating addon objects. +-- It'll provide you with a set of callback functions that allow you to simplify the loading +-- process of your addon.\\ +-- Callbacks provided are:\\ +-- * **OnInitialize**, which is called directly after the addon is fully loaded. +-- * **OnEnable** which gets called during the PLAYER_LOGIN event, when most of the data provided by the game is already present. +-- * **OnDisable**, which is only called when your addon is manually being disabled. +-- @usage +-- -- A small (but complete) addon, that doesn't do anything, +-- -- but shows usage of the callbacks. +-- local MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon") +-- +-- function MyAddon:OnInitialize() +-- -- do init tasks here, like loading the Saved Variables, +-- -- or setting up slash commands. +-- end +-- +-- function MyAddon:OnEnable() +-- -- Do more initialization here, that really enables the use of your addon. +-- -- Register Events, Hook functions, Create Frames, Get information from +-- -- the game that wasn't available in OnInitialize +-- end +-- +-- function MyAddon:OnDisable() +-- -- Unhook, Unregister Events, Hide frames that you created. +-- -- You would probably only use an OnDisable if you want to +-- -- build a "standby" mode, or be able to toggle modules on/off. +-- end +-- @class file +-- @name AceAddon-3.0.lua +-- @release $Id: AceAddon-3.0.lua 895 2009-12-06 16:28:55Z nevcairiel $ + +local MAJOR, MINOR = "AceAddon-3.0", 5 +local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR) + +if not AceAddon then return end -- No Upgrade needed. + +AceAddon.frame = AceAddon.frame or CreateFrame("Frame", "AceAddon30Frame") -- Our very own frame +AceAddon.addons = AceAddon.addons or {} -- addons in general +AceAddon.statuses = AceAddon.statuses or {} -- statuses of addon. +AceAddon.initializequeue = AceAddon.initializequeue or {} -- addons that are new and not initialized +AceAddon.enablequeue = AceAddon.enablequeue or {} -- addons that are initialized and waiting to be enabled +AceAddon.embeds = AceAddon.embeds or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end }) -- contains a list of libraries embedded in an addon + +-- Lua APIs +local tinsert, tconcat, tremove = table.insert, table.concat, table.remove +local fmt, tostring = string.format, tostring +local select, pairs, next, type, unpack = select, pairs, next, type, unpack +local loadstring, assert, error = loadstring, assert, error +local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget + +-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded +-- List them here for Mikk's FindGlobals script +-- GLOBALS: LibStub, IsLoggedIn, geterrorhandler + +--[[ + xpcall safecall implementation +]] +local xpcall = xpcall + +local function errorhandler(err) + return geterrorhandler()(err) +end + +local function CreateDispatcher(argCount) + local code = [[ + local xpcall, eh = ... + local method, ARGS + local function call() return method(ARGS) end + + local function dispatch(func, ...) + method = func + if not method then return end + ARGS = ... + return xpcall(call, eh) + end + + return dispatch + ]] + + local ARGS = {} + for i = 1, argCount do ARGS[i] = "arg"..i end + code = code:gsub("ARGS", tconcat(ARGS, ", ")) + return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler) +end + +local Dispatchers = setmetatable({}, {__index=function(self, argCount) + local dispatcher = CreateDispatcher(argCount) + rawset(self, argCount, dispatcher) + return dispatcher +end}) +Dispatchers[0] = function(func) + return xpcall(func, errorhandler) +end + +local function safecall(func, ...) + -- we check to see if the func is passed is actually a function here and don't error when it isn't + -- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not + -- present execution should continue without hinderance + if type(func) == "function" then + return Dispatchers[select('#', ...)](func, ...) + end +end + +-- local functions that will be implemented further down +local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype + +-- used in the addon metatable +local function addontostring( self ) return self.name end + +--- Create a new AceAddon-3.0 addon. +-- Any libraries you specified will be embeded, and the addon will be scheduled for +-- its OnInitialize and OnEnable callbacks. +-- The final addon object, with all libraries embeded, will be returned. +-- @paramsig [object ,]name[, lib, ...] +-- @param object Table to use as a base for the addon (optional) +-- @param name Name of the addon object to create +-- @param lib List of libraries to embed into the addon +-- @usage +-- -- Create a simple addon object +-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceEvent-3.0") +-- +-- -- Create a Addon object based on the table of a frame +-- local MyFrame = CreateFrame("Frame") +-- MyAddon = LibStub("AceAddon-3.0"):NewAddon(MyFrame, "MyAddon", "AceEvent-3.0") +function AceAddon:NewAddon(objectorname, ...) + local object,name + local i=1 + if type(objectorname)=="table" then + object=objectorname + name=... + i=2 + else + name=objectorname + end + if type(name)~="string" then + error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) + end + if self.addons[name] then + error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2) + end + + object = object or {} + object.name = name + + local addonmeta = {} + local oldmeta = getmetatable(object) + if oldmeta then + for k, v in pairs(oldmeta) do addonmeta[k] = v end + end + addonmeta.__tostring = addontostring + + setmetatable( object, addonmeta ) + self.addons[name] = object + object.modules = {} + object.defaultModuleLibraries = {} + Embed( object ) -- embed NewModule, GetModule methods + self:EmbedLibraries(object, select(i,...)) + + -- add to queue of addons to be initialized upon ADDON_LOADED + tinsert(self.initializequeue, object) + return object +end + + +--- Get the addon object by its name from the internal AceAddon registry. +-- Throws an error if the addon object cannot be found (except if silent is set). +-- @param name unique name of the addon object +-- @param silent if true, the addon is optional, silently return nil if its not found +-- @usage +-- -- Get the Addon +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +function AceAddon:GetAddon(name, silent) + if not silent and not self.addons[name] then + error(("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'."):format(tostring(name)), 2) + end + return self.addons[name] +end + +-- - Embed a list of libraries into the specified addon. +-- This function will try to embed all of the listed libraries into the addon +-- and error if a single one fails. +-- +-- **Note:** This function is for internal use by :NewAddon/:NewModule +-- @paramsig addon, [lib, ...] +-- @param addon addon object to embed the libs in +-- @param lib List of libraries to embed into the addon +function AceAddon:EmbedLibraries(addon, ...) + for i=1,select("#", ... ) do + local libname = select(i, ...) + self:EmbedLibrary(addon, libname, false, 4) + end +end + +-- - Embed a library into the addon object. +-- This function will check if the specified library is registered with LibStub +-- and if it has a :Embed function to call. It'll error if any of those conditions +-- fails. +-- +-- **Note:** This function is for internal use by :EmbedLibraries +-- @paramsig addon, libname[, silent[, offset]] +-- @param addon addon object to embed the library in +-- @param libname name of the library to embed +-- @param silent marks an embed to fail silently if the library doesn't exist (optional) +-- @param offset will push the error messages back to said offset, defaults to 2 (optional) +function AceAddon:EmbedLibrary(addon, libname, silent, offset) + local lib = LibStub:GetLibrary(libname, true) + if not lib and not silent then + error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q."):format(tostring(libname)), offset or 2) + elseif lib and type(lib.Embed) == "function" then + lib:Embed(addon) + tinsert(self.embeds[addon], libname) + return true + elseif lib then + error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable"):format(libname), offset or 2) + end +end + +--- Return the specified module from an addon object. +-- Throws an error if the addon object cannot be found (except if silent is set) +-- @name //addon//:GetModule +-- @paramsig name[, silent] +-- @param name unique name of the module +-- @param silent if true, the module is optional, silently return nil if its not found (optional) +-- @usage +-- -- Get the Addon +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- -- Get the Module +-- MyModule = MyAddon:GetModule("MyModule") +function GetModule(self, name, silent) + if not self.modules[name] and not silent then + error(("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'."):format(tostring(name)), 2) + end + return self.modules[name] +end + +local function IsModuleTrue(self) return true end + +--- Create a new module for the addon. +-- The new module can have its own embeded libraries and/or use a module prototype to be mixed into the module.\\ +-- A module has the same functionality as a real addon, it can have modules of its own, and has the same API as +-- an addon object. +-- @name //addon//:NewModule +-- @paramsig name[, prototype|lib[, lib, ...]] +-- @param name unique name of the module +-- @param prototype object to derive this module from, methods and values from this table will be mixed into the module (optional) +-- @param lib List of libraries to embed into the addon +-- @usage +-- -- Create a module with some embeded libraries +-- MyModule = MyAddon:NewModule("MyModule", "AceEvent-3.0", "AceHook-3.0") +-- +-- -- Create a module with a prototype +-- local prototype = { OnEnable = function(self) print("OnEnable called!") end } +-- MyModule = MyAddon:NewModule("MyModule", prototype, "AceEvent-3.0", "AceHook-3.0") +function NewModule(self, name, prototype, ...) + if type(name) ~= "string" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end + if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'."):format(type(prototype)), 2) end + + if self.modules[name] then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists."):format(name), 2) end + + -- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well. + -- NewModule can only be called after the parent addon is present thus the modules will be initialized after their parent is. + local module = AceAddon:NewAddon(fmt("%s_%s", self.name or tostring(self), name)) + + module.IsModule = IsModuleTrue + module:SetEnabledState(self.defaultModuleState) + module.moduleName = name + + if type(prototype) == "string" then + AceAddon:EmbedLibraries(module, prototype, ...) + else + AceAddon:EmbedLibraries(module, ...) + end + AceAddon:EmbedLibraries(module, unpack(self.defaultModuleLibraries)) + + if not prototype or type(prototype) == "string" then + prototype = self.defaultModulePrototype or nil + end + + if type(prototype) == "table" then + local mt = getmetatable(module) + mt.__index = prototype + setmetatable(module, mt) -- More of a Base class type feel. + end + + safecall(self.OnModuleCreated, self, module) -- Was in Ace2 and I think it could be a cool thing to have handy. + self.modules[name] = module + + return module +end + +--- Returns the real name of the addon or module, without any prefix. +-- @name //addon//:GetName +-- @paramsig +-- @usage +-- print(MyAddon:GetName()) +-- -- prints "MyAddon" +function GetName(self) + return self.moduleName or self.name +end + +--- Enables the Addon, if possible, return true or false depending on success. +-- This internally calls AceAddon:EnableAddon(), thus dispatching a OnEnable callback +-- and enabling all modules of the addon (unless explicitly disabled).\\ +-- :Enable() also sets the internal `enableState` variable to true +-- @name //addon//:Enable +-- @paramsig +-- @usage +-- -- Enable MyModule +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- MyModule = MyAddon:GetModule("MyModule") +-- MyModule:Enable() +function Enable(self) + self:SetEnabledState(true) + return AceAddon:EnableAddon(self) +end + +--- Disables the Addon, if possible, return true or false depending on success. +-- This internally calls AceAddon:DisableAddon(), thus dispatching a OnDisable callback +-- and disabling all modules of the addon.\\ +-- :Disable() also sets the internal `enableState` variable to false +-- @name //addon//:Disable +-- @paramsig +-- @usage +-- -- Disable MyAddon +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- MyAddon:Disable() +function Disable(self) + self:SetEnabledState(false) + return AceAddon:DisableAddon(self) +end + +--- Enables the Module, if possible, return true or false depending on success. +-- Short-hand function that retrieves the module via `:GetModule` and calls `:Enable` on the module object. +-- @name //addon//:EnableModule +-- @paramsig name +-- @usage +-- -- Enable MyModule using :GetModule +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- MyModule = MyAddon:GetModule("MyModule") +-- MyModule:Enable() +-- +-- -- Enable MyModule using the short-hand +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- MyAddon:EnableModule("MyModule") +function EnableModule(self, name) + local module = self:GetModule( name ) + return module:Enable() +end + +--- Disables the Module, if possible, return true or false depending on success. +-- Short-hand function that retrieves the module via `:GetModule` and calls `:Disable` on the module object. +-- @name //addon//:DisableModule +-- @paramsig name +-- @usage +-- -- Disable MyModule using :GetModule +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- MyModule = MyAddon:GetModule("MyModule") +-- MyModule:Disable() +-- +-- -- Disable MyModule using the short-hand +-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") +-- MyAddon:DisableModule("MyModule") +function DisableModule(self, name) + local module = self:GetModule( name ) + return module:Disable() +end + +--- Set the default libraries to be mixed into all modules created by this object. +-- Note that you can only change the default module libraries before any module is created. +-- @name //addon//:SetDefaultModuleLibraries +-- @paramsig lib[, lib, ...] +-- @param lib List of libraries to embed into the addon +-- @usage +-- -- Create the addon object +-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon") +-- -- Configure default libraries for modules (all modules need AceEvent-3.0) +-- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0") +-- -- Create a module +-- MyModule = MyAddon:NewModule("MyModule") +function SetDefaultModuleLibraries(self, ...) + if next(self.modules) then + error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2) + end + self.defaultModuleLibraries = {...} +end + +--- Set the default state in which new modules are being created. +-- Note that you can only change the default state before any module is created. +-- @name //addon//:SetDefaultModuleState +-- @paramsig state +-- @param state Default state for new modules, true for enabled, false for disabled +-- @usage +-- -- Create the addon object +-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon") +-- -- Set the default state to "disabled" +-- MyAddon:SetDefaultModuleState(false) +-- -- Create a module and explicilty enable it +-- MyModule = MyAddon:NewModule("MyModule") +-- MyModule:Enable() +function SetDefaultModuleState(self, state) + if next(self.modules) then + error("Usage: SetDefaultModuleState(state): cannot change the module defaults after a module has been registered.", 2) + end + self.defaultModuleState = state +end + +--- Set the default prototype to use for new modules on creation. +-- Note that you can only change the default prototype before any module is created. +-- @name //addon//:SetDefaultModulePrototype +-- @paramsig prototype +-- @param prototype Default prototype for the new modules (table) +-- @usage +-- -- Define a prototype +-- local prototype = { OnEnable = function(self) print("OnEnable called!") end } +-- -- Set the default prototype +-- MyAddon:SetDefaultModulePrototype(prototype) +-- -- Create a module and explicitly Enable it +-- MyModule = MyAddon:NewModule("MyModule") +-- MyModule:Enable() +-- -- should print "OnEnable called!" now +-- @see NewModule +function SetDefaultModulePrototype(self, prototype) + if next(self.modules) then + error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2) + end + if type(prototype) ~= "table" then + error(("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'."):format(type(prototype)), 2) + end + self.defaultModulePrototype = prototype +end + +--- Set the state of an addon or module +-- This should only be called before any enabling actually happend, e.g. in/before OnInitialize. +-- @name //addon//:SetEnabledState +-- @paramsig state +-- @param state the state of an addon or module (enabled=true, disabled=false) +function SetEnabledState(self, state) + self.enabledState = state +end + + +--- Return an iterator of all modules associated to the addon. +-- @name //addon//:IterateModules +-- @paramsig +-- @usage +-- -- Enable all modules +-- for name, module in MyAddon:IterateModules() do +-- module:Enable() +-- end +local function IterateModules(self) return pairs(self.modules) end + +-- Returns an iterator of all embeds in the addon +-- @name //addon//:IterateEmbeds +-- @paramsig +local function IterateEmbeds(self) return pairs(AceAddon.embeds[self]) end + +--- Query the enabledState of an addon. +-- @name //addon//:IsEnabled +-- @paramsig +-- @usage +-- if MyAddon:IsEnabled() then +-- MyAddon:Disable() +-- end +local function IsEnabled(self) return self.enabledState end +local mixins = { + NewModule = NewModule, + GetModule = GetModule, + Enable = Enable, + Disable = Disable, + EnableModule = EnableModule, + DisableModule = DisableModule, + IsEnabled = IsEnabled, + SetDefaultModuleLibraries = SetDefaultModuleLibraries, + SetDefaultModuleState = SetDefaultModuleState, + SetDefaultModulePrototype = SetDefaultModulePrototype, + SetEnabledState = SetEnabledState, + IterateModules = IterateModules, + IterateEmbeds = IterateEmbeds, + GetName = GetName, +} +local function IsModule(self) return false end +local pmixins = { + defaultModuleState = true, + enabledState = true, + IsModule = IsModule, +} +-- Embed( target ) +-- target (object) - target object to embed aceaddon in +-- +-- this is a local function specifically since it's meant to be only called internally +function Embed(target) + for k, v in pairs(mixins) do + target[k] = v + end + for k, v in pairs(pmixins) do + target[k] = target[k] or v + end +end + + +-- - Initialize the addon after creation. +-- This function is only used internally during the ADDON_LOADED event +-- It will call the **OnInitialize** function on the addon object (if present), +-- and the **OnEmbedInitialize** function on all embeded libraries. +-- +-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing. +-- @param addon addon object to intialize +function AceAddon:InitializeAddon(addon) + safecall(addon.OnInitialize, addon) + + local embeds = self.embeds[addon] + for i = 1, #embeds do + local lib = LibStub:GetLibrary(embeds[i], true) + if lib then safecall(lib.OnEmbedInitialize, lib, addon) end + end + + -- we don't call InitializeAddon on modules specifically, this is handled + -- from the event handler and only done _once_ +end + +-- - Enable the addon after creation. +-- Note: This function is only used internally during the PLAYER_LOGIN event, or during ADDON_LOADED, +-- if IsLoggedIn() already returns true at that point, e.g. for LoD Addons. +-- It will call the **OnEnable** function on the addon object (if present), +-- and the **OnEmbedEnable** function on all embeded libraries.\\ +-- This function does not toggle the enable state of the addon itself, and will return early if the addon is disabled. +-- +-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing. +-- Use :Enable on the addon itself instead. +-- @param addon addon object to enable +function AceAddon:EnableAddon(addon) + if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end + if self.statuses[addon.name] or not addon.enabledState then return false end + + -- set the statuses first, before calling the OnEnable. this allows for Disabling of the addon in OnEnable. + self.statuses[addon.name] = true + + safecall(addon.OnEnable, addon) + + -- make sure we're still enabled before continueing + if self.statuses[addon.name] then + local embeds = self.embeds[addon] + for i = 1, #embeds do + local lib = LibStub:GetLibrary(embeds[i], true) + if lib then safecall(lib.OnEmbedEnable, lib, addon) end + end + + -- enable possible modules. + for name, module in pairs(addon.modules) do + self:EnableAddon(module) + end + end + return self.statuses[addon.name] -- return true if we're disabled +end + +-- - Disable the addon +-- Note: This function is only used internally. +-- It will call the **OnDisable** function on the addon object (if present), +-- and the **OnEmbedDisable** function on all embeded libraries.\\ +-- This function does not toggle the enable state of the addon itself, and will return early if the addon is still enabled. +-- +-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing. +-- Use :Disable on the addon itself instead. +-- @param addon addon object to enable +function AceAddon:DisableAddon(addon) + if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end + if not self.statuses[addon.name] then return false end + + -- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable. + self.statuses[addon.name] = false + + safecall( addon.OnDisable, addon ) + + -- make sure we're still disabling... + if not self.statuses[addon.name] then + local embeds = self.embeds[addon] + for i = 1, #embeds do + local lib = LibStub:GetLibrary(embeds[i], true) + if lib then safecall(lib.OnEmbedDisable, lib, addon) end + end + -- disable possible modules. + for name, module in pairs(addon.modules) do + self:DisableAddon(module) + end + end + + return not self.statuses[addon.name] -- return true if we're disabled +end + +--- Get an iterator over all registered addons. +-- @usage +-- -- Print a list of all installed AceAddon's +-- for name, addon in AceAddon:IterateAddons() do +-- print("Addon: " .. name) +-- end +function AceAddon:IterateAddons() return pairs(self.addons) end + +--- Get an iterator over the internal status registry. +-- @usage +-- -- Print a list of all enabled addons +-- for name, status in AceAddon:IterateAddonStatus() do +-- if status then +-- print("EnabledAddon: " .. name) +-- end +-- end +function AceAddon:IterateAddonStatus() return pairs(self.statuses) end + +-- Following Iterators are deprecated, and their addon specific versions should be used +-- e.g. addon:IterateEmbeds() instead of :IterateEmbedsOnAddon(addon) +function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end +function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end + +-- Event Handling +local function onEvent(this, event, arg1) + if event == "ADDON_LOADED" or event == "PLAYER_LOGIN" then + -- if a addon loads another addon, recursion could happen here, so we need to validate the table on every iteration + while(#AceAddon.initializequeue > 0) do + local addon = tremove(AceAddon.initializequeue, 1) + -- this might be an issue with recursion - TODO: validate + if event == "ADDON_LOADED" then addon.baseName = arg1 end + AceAddon:InitializeAddon(addon) + tinsert(AceAddon.enablequeue, addon) + end + + if IsLoggedIn() then + while(#AceAddon.enablequeue > 0) do + local addon = tremove(AceAddon.enablequeue, 1) + AceAddon:EnableAddon(addon) + end + end + end +end + +AceAddon.frame:RegisterEvent("ADDON_LOADED") +AceAddon.frame:RegisterEvent("PLAYER_LOGIN") +AceAddon.frame:SetScript("OnEvent", onEvent) + +-- upgrade embeded +for name, addon in pairs(AceAddon.addons) do + Embed(addon) +end diff --git a/Quartz/libs/AceAddon-3.0/AceAddon-3.0.xml b/Quartz/libs/AceAddon-3.0/AceAddon-3.0.xml new file mode 100644 index 0000000..e6ad639 --- /dev/null +++ b/Quartz/libs/AceAddon-3.0/AceAddon-3.0.xml @@ -0,0 +1,4 @@ + +