local EMPTY_TABLE = {}; local TIMEX_BAR = "TimexBar"; local DEFAULT_SCALE = 0.8; local DEFAULT_RES = 0.1; local strformat = string.format; local function ARG_ID(t) return t.timexBar.id; end; local function ARG_ELAPSED(t) return t.timexBar.elapsed; end; local function ARG_REMAINING(t) return t.timexBar.v; end; local timexDebug = nil; --<< ================================================= >>-- -- Section I: Initialize the AddOn Object. -- --<< ================================================= >>-- TimexBar = AceModule:new({ -- name = TimexLocals.TimexBar_Title, -- author = "Rowne/facboy", -- aceCompatible = "100", ARG_ID = ARG_ID, ARG_ELAPSED = ARG_ELAPSED, ARG_REMAINING = ARG_REMAINING, }) function TimexBar:Enable() self.barDB = {}; self.barMap = setmetatable({}, Timex.weakV_mt); table.setn(self.barDB, 20); for id = 1,20,1 do getglobal(TIMEX_BAR..id):SetScale(DEFAULT_SCALE); end --for id = 1,20,1 do getglobal(TIMEX_BAR..id):SetFrameStrata("TOOLTIP"); end end --<< ================================================= >>-- -- Section II: Private utility functions. -- --<< ================================================= >>-- -------------------- -- argument stuff -------------------- local args_switch = {}; args_switch[ARG_ID] = ARG_ID; args_switch[ARG_ELAPSED] = ARG_ELAPSED; args_switch[ARG_REMAINING] = ARG_REMAINING; local function buildArgs(args, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) local sub = args.sub; local f = args_switch[a20]; args[20], sub[20] = not f and a20 or nil, f; f = args_switch[a19]; args[19], sub[19] = not f and a19 or nil, f; f = args_switch[a18]; args[18], sub[18] = not f and a18 or nil, f; f = args_switch[a17]; args[17], sub[17] = not f and a17 or nil, f; f = args_switch[a16]; args[16], sub[16] = not f and a16 or nil, f; f = args_switch[a15]; args[15], sub[15] = not f and a15 or nil, f; f = args_switch[a14]; args[14], sub[14] = not f and a14 or nil, f; f = args_switch[a13]; args[13], sub[13] = not f and a13 or nil, f; f = args_switch[a12]; args[12], sub[12] = not f and a12 or nil, f; f = args_switch[a11]; args[11], sub[11] = not f and a11 or nil, f; f = args_switch[a10]; args[10], sub[10] = not f and a10 or nil, f; f = args_switch[a9]; args[9], sub[9] = not f and a9 or nil, f; f = args_switch[a8]; args[8], sub[8] = not f and a8 or nil, f; f = args_switch[a7]; args[7], sub[7] = not f and a7 or nil, f; f = args_switch[a6]; args[6], sub[6] = not f and a6 or nil, f; f = args_switch[a5]; args[5], sub[5] = not f and a5 or nil, f; f = args_switch[a4]; args[4], sub[4] = not f and a4 or nil, f; f = args_switch[a3]; args[3], sub[3] = not f and a3 or nil, f; f = args_switch[a2]; args[2], sub[2] = not f and a2 or nil, f; f = args_switch[a1]; args[1], sub[1] = not f and a1 or nil, f; end local args_mt = { __index = function(t, k) local f = t.sub[k]; if f then return f(t); end end, } local function newArgs(timexBar) local args = { timexBar = timexBar, sub = {} }; setmetatable(args, args_mt); return args; end --<< ================================================= >>-- -- Section III: The Time-Event Handler. -- --<< ================================================= >>-- local function timexHandler(self, timexBar, elapsed) --self.cmd:msg("timexHandler: timexBar.n = %s", tostring(timexBar.n)); local v = timexBar.v; if v then v = v - elapsed; if v <= 0 then if timexBar.f then timexBar.elapsed = elapsed; local a = timexBar.a; local status, err = pcall(timexBar.f, a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], a[16], a[17], a[18], a[19], a[20]); if (not status) then Timex.cmd:msg("TimexBar function '%s' failed with error: %s", tostring(timexBar.id), tostring(err)); end end self:Stop(timexBar.id); return; elseif timexBar.uf then timexBar.elapsed = elapsed; local a = timexBar.ua; local status, err = pcall(timexBar.uf, a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], a[16], a[17], a[18], a[19], a[20]); if (not status) then Timex.cmd:msg("TimexBar update function '%s' failed with error: %s", tostring(timexBar.id), tostring(err)); end end -- Update bar local settext = ceil(v); settext = settext > 60 and (format("%d", settext / 60)..":"..format("%02d", mod(settext, 60))) or settext; timexBar.ttxt:SetText(settext); timexBar.sbar:SetValue(v); timexBar.v = v; end end --<< ================================================= >>-- -- Section IV: The TimexBarClass 'inner' class -- --<< ================================================= >>-- -- class definition local TimexBarClass = { bR = 0.1, bB = 0.2, bG = 0.8, bA = 1.0, tR = 1.0, tB = 1.0, tG = 1.0, tA = 1.0, aP = "CENTER", aF = "UIParent", aRP = "CENTER", xO = 0, yO = 0, }; local TimexBarClass_mt = { __index = TimexBarClass }; do local bar = getglobal(TIMEX_BAR.."1"); TimexBarClass.s, TimexBarClass.bW, TimexBarClass.bH = DEFAULT_SCALE, bar:GetWidth(), bar:GetHeight(); local ttxt = getglobal(TIMEX_BAR.."1TimerText"); TimexBarClass.tW = ttxt:GetWidth(); end -- private constructor local function newTimexBar(timexBar, b) local n = TIMEX_BAR..b; local newInst = { n = n, bar = getglobal(n), sbar = getglobal(n.."StatusBar"), txt = getglobal(n.."Text"), ttxt = getglobal(n.."TimerText"), btn = getglobal(n.."Button"), btnTex = getglobal(n.."ButtonTexture") }; setmetatable(newInst, TimexBarClass_mt); return newInst; end -- private reset function (only resets the 'functional' attributes, not the formatting ones) local function resetTimexBar(timexBar) -- reset all values to nil timexBar.id, timexBar.f, timexBar.uf, timexBar.elapsed, timexBar.v, timexBar.res = nil, nil, nil, nil, nil, nil; -- clear arg tables local args = timexBar.a; if args then args[1], args[2], args[3], args[4], args[5] = nil, nil, nil, nil, nil; args[6], args[7], args[8], args[9], args[10] = nil, nil, nil, nil, nil; args[11], args[12], args[13], args[14], args[15] = nil, nil, nil, nil, nil; args[16], args[17], args[18], args[19], args[20] = nil, nil, nil, nil, nil; end args = timexBar.ua; if args then args[1], args[2], args[3], args[4], args[5] = nil, nil, nil, nil, nil; args[6], args[7], args[8], args[9], args[10] = nil, nil, nil, nil, nil; args[11], args[12], args[13], args[14], args[15] = nil, nil, nil, nil, nil; args[16], args[17], args[18], args[19], args[20] = nil, nil, nil, nil, nil; end if timexBar.cf then timexBar.cf = nil; args = timexBar.ca; if args then args[1], args[2], args[3], args[4], args[5] = nil, nil, nil, nil, nil; args[6], args[7], args[8], args[9], args[10] = nil, nil, nil, nil, nil; args[11], args[12], args[13], args[14], args[15] = nil, nil, nil, nil, nil; args[16], args[17], args[18], args[19], args[20] = nil, nil, nil, nil, nil; end end end -- private formatting function local function resetTimexBarFormat(timexBar) local bar, txt, ttxt = timexBar.bar, timexBar.txt, timexBar.ttxt; if not timexBar.sColor and timexBar.rColor then timexBar.bR, timexBar.bB, timexBar.bG, timexBar.bA = nil, nil, nil, nil; timexBar.sbar:SetStatusBarColor(timexBar.bR, timexBar.bB, timexBar.bG, timexBar.bA); timexBar.rColor = nil; end if not timexBar.sTextColor and timexBar.rTextColor then timexBar.tR, timexBar.tB, timexBar.tG, timexBar.tA = nil, nil, nil, nil; txt:SetTextColor(timexBar.tR, timexBar.tB, timexBar.tG, timexBar.tA); ttxt:SetTextColor(timexBar.tR, timexBar.tB, timexBar.tG, timexBar.tA); timexBar.rTextColor = nil; end if not timexBar.sPoint and timexBar.rPoint then timexBar.aP, timexBar.aF, timexBar.aRP, timexBar.xO, timexBar.yO = nil, nil, nil, nil, nil; bar:ClearAllPoints(); bar:SetPoint(timexBar.aP, timexBar.aF, timexBar.aRP, timexBar.xO, timexBar.yO); timexBar.rPoint = nil; end if not timexBar.sWidth and timexBar.rWidth then timexBar.bW = nil; bar:SetWidth(timexBar.bW); timexBar.rWidth = nil; end if not timexBar.sHeight and timexBar.rHeight then timexBar.bH = nil; bar:SetHeight(timexBar.bH); timexBar.rHeight = nil; end if not timexBar.sScale and timexBar.rScale then timexBar.s = nil; bar:SetScale(timexBar.s); timexBar.rScale = nil; end if not timexBar.sTimeWidth and timexBar.rTimeWidth then timexBar.tW = nil; ttxt:SetWidth(timexBar.tW); txt:SetPoint("TOPLEFT", bar, "LEFT", timexBar.tW, 13); timexBar.rTimeWidth = nil; end if not timexBar.sText and timexBar.rText then timexBar.text = nil; if timexBar.text then timexBar.txt:SetText("| "..timexBar.text); else timexBar.txt:SetText(""); end timexBar.rText = nil; end if not timexBar.sTexture and timexBar.rTexture then timexBar.tex = nil; if timexBar.tex then timexBar.btnTex:SetTexture(timexBar.tex); timexBar.btn:Show(); else timexBar.btn:Hide(); end timexBar.rTexture = nil; end end local function clearSetFlags(timexBar) timexBar.sColor, timexBar.sTextColor, timexBar.sPoint, timexBar.sWidth = nil, nil, nil, nil; timexBar.sHeight, timexBar.sScale, timexBar.sTimeWidth, timexBar.sText, timexBar.sTexture = nil, nil, nil, nil, nil; end --<< ================================================= >>-- -- Section V: The Start and Stop Bar Functions. -- --<< ================================================= >>-- -- Assigns a bar to id function TimexBar:Get(id) if id and id ~= "" then local timexBar = self.barMap[id]; -- if not found if not timexBar then -- find first available local b = 1; timexBar = self.barDB[b]; while (timexBar) do if (not timexBar.v) then break; end b = b + 1; timexBar = self.barDB[b]; end if timexBar then clearSetFlags(timexBar); elseif (b <= 20) then timexBar = newTimexBar(self, b); self.barDB[b] = timexBar; else error("No more bars available!"); end -- assign id timexBar.id, self.barMap[id] = id, timexBar; end return timexBar.n; end end function TimexBar:Start(id, time, res) if (time) then local timexBar = self.barMap[id]; if timexBar then res = res or DEFAULT_RES; timexBar.v = time; timexBar.res = res; -- reset bar format and show resetTimexBarFormat(timexBar); local settext = ceil(timexBar.v); settext = settext > 60 and format("%d:%02d", settext/60, mod(settext, 60)) or settext; timexBar.ttxt:SetText(settext); local sbar = timexBar.sbar; sbar:SetMinMaxValues(0, time); sbar:SetValue(timexBar.v); if timexBar.cf then timexBar.btn:EnableMouse(1); timexBar.btn:SetScript("OnClick", timexBar.onClick); end timexBar.bar:Show(); Timex:AddSchedule(timexBar, res, true, nil, timexHandler, self, timexBar, Timex.ARG_ELAPSED); return timexBar.n; else error(strformat("TimexBar '%s' not found.", tostring(id))); end end end function TimexBar:Stop(id) local timexBar = self.barMap[id]; if timexBar then Timex:DeleteSchedule(timexBar); if timexBar.cf then timexBar.btn:EnableMouse(0); timexBar.btn:SetScript("OnClick", nil); end timexBar.bar:Hide(); resetTimexBar(timexBar); self.barMap[id] = nil; end end function TimexBar:Pause(id) local timexBar = self.barMap[id]; if timexBar then Timex:DeleteSchedule(timexBar); end end function TimexBar:Resume(id) local timexBar = self.barMap[id]; if timexBar then if timexBar.res then Timex:AddSchedule(timexBar, timexBar.res, true, nil, timexHandler, self, timexBar, Timex.ARG_ELAPSED); else error(strformat("TimexBar '%s' has not been started yet.", tostring(id))); end end end function TimexBar:Check(id, r) local timexBar = self.barMap[id]; if timexBar then return (r and timexBar.n) or TRUE; end end function TimexBar:ChangeDuration(id, t) local timexBar = self.barMap[id]; if timexBar then if timexBar.v then timexBar.v = t; end end end function TimexBar:Debug(debug) timexDebug = debug; end --<< ================================================= >>-- -- Section VI: The Bar Formatting Functions -- --<< ================================================= >>-- function TimexBar:SetColor(id, red, blue, green, alpha) local timexBar = self.barMap[id]; if timexBar then if timexBar.bR ~= red or timexBar.bB ~= blue or timexBar.bG ~= green or timexBar.bA ~= alpha then timexBar.bR, timexBar.bB, timexBar.bG, timexBar.bA = red, blue, green, alpha; timexBar.sbar:SetStatusBarColor(timexBar.bR, timexBar.bB, timexBar.bG, timexBar.bA); timexBar.rColor = true; end timexBar.sColor = true; else error(strformat("TimexBar '%s' not found.", tostring(id))); end end function TimexBar:SetTextColor(id, red, blue, green, alpha) local timexBar = self.barMap[id]; if timexBar then if timexBar.tR ~= red or timexBar.tB ~= blue or timexBar.tG ~= green or timexBar.tA ~= alpha then timexBar.tR, timexBar.tB, timexBar.tG, timexBar.tA = red, blue, green, alpha; timexBar.txt:SetTextColor(timexBar.tR, timexBar.tB, timexBar.tG, timexBar.tA); timexBar.ttxt:SetTextColor(timexBar.tR, timexBar.tB, timexBar.tG, timexBar.tA); timexBar.rTextColor = true; end timexBar.sTextColor = true; else error(strformat("TimexBar '%s' not found.", tostring(id))); end end function TimexBar:SetPoint(id, point, relativeFrame, relativePoint, xOffset, yOffset) local timexBar = self.barMap[id]; if timexBar then if timexBar.aP ~= point or timexBar.aF ~= relativeFrame or timexBar.aRP ~= relativePoint or timexBar.xO ~= xOffset or timexBar.yO ~= yOffset then timexBar.aP, timexBar.aF, timexBar.aRP, timexBar.xO, timexBar.yO = point, relativeFrame, relativePoint, xOffset, yOffset; local bar = timexBar.bar; bar:ClearAllPoints(); bar:SetPoint(timexBar.aP, timexBar.aF, timexBar.aRP, timexBar.xO, timexBar.yO); timexBar.rPoint = true; end timexBar.sPoint = true; else error(strformat("TimexBar '%s' not found.", tostring(id))); end end function TimexBar:SetWidth(id, width) local timexBar = self.barMap[id]; if timexBar then if timexBar.bW ~= width then timexBar.bW = width; timexBar.bar:SetWidth(timexBar.bW); timexBar.rWidth = true; end timexBar.sWidth = true; else error(strformat("TimexBar '%s' not found.", tostring(id))); end end function TimexBar:SetHeight(id, height) local timexBar = self.barMap[id]; if timexBar then if timexBar.bH ~= height then timexBar.bH = height; timexBar.bar:SetHeight(timexBar.bH); timexBar.rHeight = true; end timexBar.sHeight = true; else error(strformat("TimexBar '%s' not found.", tostring(id))); end end function TimexBar:SetScale(id, scale) local timexBar = self.barMap[id]; if timexBar then if timexBar.s ~= scale then timexBar.s = scale; timexBar.bar:SetScale(timexBar.s); timexBar.rScale = true; end timexBar.sScale = true; else error(strformat("TimexBar '%s' not found.", tostring(id))); end end function TimexBar:SetTimeWidth(id, width) local timexBar = self.barMap[id]; if timexBar then if timexBar.tW ~= width then timexBar.tW = width; timexBar.ttxt:SetWidth(timexBar.tW); timexBar.txt:SetPoint("TOPLEFT", timexBar.bar, "LEFT", timexBar.tW, 13); timexBar.rTimeWidth = true; end timexBar.sTimeWidth = true; else error(strformat("TimexBar '%s' not found.", tostring(id))); end end function TimexBar:SetText(id, text) local timexBar = self.barMap[id]; if timexBar then if timexBar.text ~= text then timexBar.text = text; if timexBar.text then timexBar.txt:SetText("| "..timexBar.text); else timexBar.txt:SetText(""); end timexBar.rText = true; end timexBar.sText = true; else error(strformat("TimexBar '%s' not found.", tostring(id))); end end function TimexBar:SetTexture(id, texturePath) local timexBar = self.barMap[id]; if timexBar then if timexBar.tex ~= texturePath then timexBar.tex = texturePath; if timexBar.tex then timexBar.btnTex:SetTexture(timexBar.tex); timexBar.btn:Show(); else timexBar.btn:Hide(); end timexBar.rTexture = true; end timexBar.sTexture = true; else error(strformat("TimexBar '%s' not found.", tostring(id))); end end function TimexBar:SetFunction(id, f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) local timexBar = self.barMap[id]; if timexBar then timexBar.f = f; if not timexBar.a then timexBar.a = newArgs(timexBar); end buildArgs(timexBar.a, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); else error(strformat("TimexBar '%s' not found.", tostring(id))); end end function TimexBar:SetUpdateFunction(id, f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) local timexBar = self.barMap[id]; if timexBar then timexBar.uf = f; if not timexBar.ua then timexBar.ua = newArgs(timexBar); end buildArgs(timexBar.ua, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); else error(strformat("TimexBar '%s' not found.", tostring(id))); end end function TimexBar:SetClickFunction(id, f, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) local timexBar = self.barMap[id]; if timexBar then -- create the onClick function for this bar. if not timexBar.onClick then timexBar.onClick = function() local a = timexBar.ca; local status, err = pcall(timexBar.cf, a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], a[16], a[17], a[18], a[19], a[20]); if not status then Timex.cmd:msg("TimexBar click function '%s' failed with error: %s", tostring(timexBar.id), tostring(err)); end end end timexBar.cf = f; if not timexBar.ca then timexBar.ca = newArgs(timexBar); end buildArgs(timexBar.ca, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); else error(strformat("TimexBar '%s' not found.", tostring(id))); end end --<< ================================================= >>-- -- Section Omega: Register the AddOn Object. -- --<< ================================================= >>-- --TimexBar:RegisterForLoad()