annotate Fog.lua @ 4:8ace773d6bfc

suppress castbar latency logic on non-player units
author Nenue
date Tue, 15 Dec 2015 10:09:20 -0500
parents 62f9b057c91b
children
rev   line source
Nenue@1 1 -- User: Krakyn
Nenue@1 2 -- Created: 12/4/2015 11:13 PM
Nenue@1 3 --[[
Nenue@1 4 -- Core tools, mostly frame handling business. It's an interface script after all.
Nenue@1 5 -- Types:
Nenue@1 6 -- StatusFrame
Nenue@1 7 -- Primary container for status data, carries primary value information by default
Nenue@1 8 -- FIELDS
Nenue@1 9 -- value = exact primary value represented by frame
Nenue@1 10 -- min = exact minimum for primary value
Nenue@1 11 -- max = exact maximum for primary value
Nenue@1 12 -- percent = value / max
Nenue@1 13 -- alpha = base frame alpha level, set when a fade animation has completed
Nenue@1 14 -- fadeTo = when set, the frame will begin fading to this level
Nenue@1 15 -- fadeDuration = set with fadeTo when the transition needs to be time-adjusted for unpredictable alpha states
Nenue@1 16 -- fadeTime = set with fadeTo when the transition has an explicit desired timing
Nenue@1 17 -- throttle_rate = animation frame delay
Nenue@1 18 --
Nenue@1 19 -- METHODS
Nenue@1 20 -- Update() = Runs the frame's Update script, and calls UpdateText()
Nenue@1 21 -- UpdateText() = Iterates over frame children and calls Update() if it is a StatusText frame
Nenue@1 22 --
Nenue@1 23 -- StatusText
Nenue@1 24 -- Sub-container for individual text elements, carries string output values, controlled by from Update(). By default
Nenue@1 25 -- these are derived from the parent's primary value data, but is mostly overridden in module code.
Nenue@1 26 -- FIELDS
Nenue@1 27 -- text = WoW FontString object housing text data
Nenue@1 28 -- format = a format string for expressing complex data (timer bars, etc.)
Nenue@1 29 -- METHODS
Nenue@1 30 -- SetText() = shortcut for text:SetText(...)
Nenue@1 31 -- SetJustifyH() = shortcut for text:SetJustifyH(...)
Nenue@1 32 -- Implements:
Nenue@1 33 -- frame = CreateBar(name, config root)
Nenue@1 34 -- Creates and displays a generic bar frame with progress textures and default updater, based on the variables from
Nenue@1 35 -- the smart config table. Seeded with methods Update() and UpdateText().
Nenue@1 36 -- Update() will refresh the entire frame and tail call UpdateText()
Nenue@1 37 -- UpdateText() will iterate over the contents of frame:GetChildren() and call Update()
Nenue@1 38 -- NEVER CREATE A CHILD FRAME WITHOUT Update() DEFINED
Nenue@1 39 -- NEVER INVOKE METHODS FROM A GetParent() RETURN
Nenue@1 40 --
Nenue@1 41 -- Bar_SetUpdateHandler(frame, function)
Nenue@1 42 -- Takes the desired OnUpdate script and wraps it inside frame throttling logic, then does SetScript
Nenue@1 43 --
Nenue@1 44 -- frame = AddLabel(frame, config root, name)
Nenue@1 45 -- Constructs a text display and adds it to the frame's list of internal text objects. Contains method Update(), which
Nenue@1 46 -- refreshed text.
Nenue@1 47 --
Nenue@1 48 -- HANDLERS
Nenue@1 49 -- Bar_Update([value, min/duration, max/end])
Nenue@1 50 -- Default handler for any non-timed bar (where isTimer = false in config vars. Invoked by frame:Update()
Nenue@1 51 ]]
Nenue@1 52 local T = LibStub("AceAddon-3.0"):GetAddon("Turok")
Nenue@1 53 local LSM = LibStub("LibSharedMedia-3.0")
Nenue@1 54 local TL = 'Fog'
Nenue@1 55 local print = function(...)
Nenue@1 56 _G.print(TL, ...)
Nenue@1 57 end
Nenue@1 58 --setprinthandler(function (...) T:debug('Fog', nil, ...) end)
Nenue@1 59 local FADE_OUT_TIME = 1 -- duration per 1-0 alpha transition
Nenue@1 60 local FADE_IN_TIME = 0.4 -- duration per 0-1 alpha transition
Nenue@1 61
Nenue@1 62 local inset_factor = {
Nenue@1 63 ['TOPLEFT'] = {-1, 1},
Nenue@1 64 ['TOP'] = {0, 1},
Nenue@1 65 ['TOPRIGHT'] = {1, 1},
Nenue@1 66 ['RIGHT'] = {1, 0},
Nenue@1 67 ['BOTTOMRIGHT'] = {1, -1},
Nenue@1 68 ['BOTTOM'] = {0, -1},
Nenue@1 69 ['BOTTOMLEFT'] = {-1,-1},
Nenue@1 70 ['LEFT'] = {-1, 0}
Nenue@1 71 }
Nenue@1 72
Nenue@1 73 T.anchor_inverse = { ['LEFT'] = 'RIGHT', ['RIGHT'] = 'LEFT', ['UP'] = 'DOWN', ['DOWN'] = 'UP' } -- directional inverse
Nenue@1 74 T.direction_coord = { ['LEFT'] = {1, 0}, ['RIGHT'] = {-1,0}, ['UP'] = {0, -1}, ['DOWN'] = {0, 1 } } -- directional derivatives
Nenue@1 75 T.anchor_direction = { ['LEFT'] = 'RIGHT', ['RIGHT'] = 'LEFT', ['UP'] = 'BOTTOM', ['DOWN'] = 'TOP'} -- directional anchors
Nenue@1 76
Nenue@1 77 function T:CreateBar(name, config)
Nenue@1 78 local parent = type(config.parent) == 'string' and _G[config.parent] or parent
Nenue@1 79 if not parent then
Nenue@1 80 parent = CreateFrame('Frame', config.parent, UIParent)
Nenue@1 81 print('creating dry frame |cFFDDDDDD' .. config.parent .. '|r for |cFFFFFF00' .. name .. '|r')
Nenue@1 82 end
Nenue@1 83
Nenue@1 84 local f
Nenue@1 85 if _G[name] and _G[name].GetFrameType and _G[name].GetFrameType() == 'Frame' then
Nenue@1 86 f = _G[name]
Nenue@1 87 print('found existing table |cFFFFFF00' .. name .. '|r')
Nenue@1 88 else
Nenue@1 89 print('creating statusbar '.. name, config.anchor, parent:GetName(), config.anchorTo, config.posX, config.posY)
Nenue@1 90 end
Nenue@1 91
Nenue@1 92
Nenue@1 93 f = CreateFrame('Frame', name, UIParent)
Nenue@1 94 f.db = config
Nenue@1 95
Nenue@1 96 -- state vars
Nenue@1 97 f.combat = InCombatLockdown()
Nenue@1 98 f.min = 0
Nenue@1 99 f.max = 1
Nenue@1 100 f.value = 0
Nenue@1 101 f.percent = 0
Nenue@1 102 f.alpha = f.combat and config.alpha or config.alpha_ooc
Nenue@1 103 f:SetAlpha(f.combat and config.alpha or config.alpha_ooc)
Nenue@1 104 f:SetPoint(config.anchor, config.parent, config.anchorTo, config.posX, config.posY)
Nenue@1 105 f:SetSize(config.width, config.height)
Nenue@1 106 f:SetFrameStrata(config.strata)
Nenue@1 107 self:CreateStatusTextures(f, config)
Nenue@1 108
Nenue@1 109 f.throttle_rate = 0.0166666666 -- ~60fps
Nenue@2 110 f.throttle_point = GetTime()
Nenue@1 111
Nenue@1 112 -- default handler
Nenue@1 113 f.Update = T.Bar_Update
Nenue@1 114 f.UpdateText = T.Bar_UpdateText
Nenue@1 115 T:Bar_SetUpdateHandler(f, T.Bar_Update)
Nenue@1 116
Nenue@1 117 return f
Nenue@1 118 end
Nenue@1 119
Nenue@1 120 function T:CreateStatusTextures(region, c)
Nenue@1 121 c = c and c or region.db
Nenue@1 122 print('STATUSTEX_make', region:GetName(), c.background_texture, c.background_color, c.foreground_texture, c.foreground_color)
Nenue@1 123 region.background = region:CreateTexture('background', 'BACKGROUND')
Nenue@1 124 region.background:SetAllPoints(region)
Nenue@1 125 if c.background_texture then
Nenue@1 126 region.background:SetTexture(LSM:Fetch('statusbar', c.background_texture))
Nenue@1 127 region.background:SetVertexColor(unpack(c.background_color))
Nenue@1 128 else
Nenue@1 129 region.background:SetTexture(unpack(c.background_color))
Nenue@1 130 end
Nenue@1 131 region.background:SetBlendMode(c.background_blend)
Nenue@1 132
Nenue@1 133 region.foreground = region:CreateTexture('foreground', 'ARTWORK')
Nenue@1 134 region.foreground:SetPoint('TOPLEFT', region, 'TOPLEFT', 0-c.foreground_inset, c.foreground_inset)
Nenue@1 135 region.foreground:SetPoint('BOTTOMRIGHT', region, 'BOTTOMRIGHT', c.foreground_inset, 0-c.foreground_inset)
Nenue@1 136 if c.foreground_texture then
Nenue@1 137 region.foreground:SetTexture(LSM:Fetch('statusbar', c.foreground_texture))
Nenue@1 138 region.foreground:SetVertexColor(unpack(c.foreground_color))
Nenue@1 139 else
Nenue@1 140 region.foreground:SetTexture(unpack(c.foreground_color))
Nenue@1 141 end
Nenue@1 142 region.foreground:SetBlendMode(c.foreground_blend)
Nenue@1 143 end
Nenue@1 144
Nenue@1 145 function T:CreateStatusIcon(region, c)
Nenue@1 146 local file = type(c) == 'string' and c or region.icon
Nenue@1 147 if type(c) ~= 'table' then
Nenue@1 148 c = region.db
Nenue@1 149 end
Nenue@1 150 print('STATUSICON', region:GetName(), file, c.icon_show)
Nenue@1 151
Nenue@1 152 end
Nenue@1 153
Nenue@1 154 -- Sets the OnUpdate handler within a timing scheme
Nenue@1 155 function T:Bar_SetUpdateHandler(bar, func)
Nenue@1 156 bar:SetScript('OnUpdate', function(bar)
Nenue@1 157 if GetTime() < bar.throttle_point then
Nenue@1 158 return
Nenue@1 159 end
Nenue@1 160
Nenue@1 161 bar.throttle_point = bar.throttle_point + bar.throttle_rate
Nenue@1 162 if type(func) == 'string' then
Nenue@1 163 if type(bar[func]) ~= 'function' then
Nenue@1 164 error('TurokBar:SetUpdateScript(); string "' ..func.. '" is not a valid method name')
Nenue@1 165 return
Nenue@1 166 end
Nenue@1 167 elseif type(func) ~= 'function' then
Nenue@1 168 error('TurokBar:SetUpdateScript(function or string); got '.. type(func) .. 'instead')
Nenue@1 169 return
Nenue@1 170 end
Nenue@1 171
Nenue@1 172 func(bar)
Nenue@1 173 end)
Nenue@1 174 end
Nenue@1 175
Nenue@1 176 -- Default update loop
Nenue@1 177 function T:Bar_Update (value, min, max)
Nenue@1 178
Nenue@1 179 if value ~= nil then -- could be 0
Nenue@1 180 self.value = value
Nenue@1 181 end
Nenue@1 182 if (min ~= nil and max ~= nil) then
Nenue@1 183 if self.isTimer then
Nenue@1 184 self.duration = min
Nenue@1 185 self.endTime = max
Nenue@1 186 else
Nenue@1 187 self.min = min
Nenue@1 188 self.max = max
Nenue@1 189 self.duration = max
Nenue@1 190 end
Nenue@1 191 end
Nenue@1 192
Nenue@1 193 if self.combat ~= InCombatLockdown() then
Nenue@1 194 self.combat = InCombatLockdown()
Nenue@1 195 if self.combat then
Nenue@1 196 self.fadeTo = self.db.alpha
Nenue@1 197 self.fadeDuration = FADE_IN_TIME
Nenue@1 198 else
Nenue@1 199 self.fadeTo = self.db.alpha_ooc
Nenue@1 200 self.fadeDuration = FADE_OUT_TIME
Nenue@1 201 end
Nenue@1 202 end
Nenue@1 203
Nenue@1 204 -- we need the time for something
Nenue@1 205 if self.isTimer or self.fadeTo ~= nil then
Nenue@1 206 local time = GetTime()
Nenue@1 207
Nenue@1 208 -- start doing fade animation things
Nenue@1 209 if self.fadeTo ~= nil then
Nenue@1 210
Nenue@1 211 if not self.fadeFrom then
Nenue@1 212 self.fadeFrom = self:GetAlpha()
Nenue@1 213 end
Nenue@1 214
Nenue@1 215 -- fadeDuration missing, fill it in
Nenue@1 216 if not self.fadeDuration then
Nenue@1 217 self.fadeDuration = self.fadeFrom > self.fadeTo and FADE_OUT_TIME or FADE_IN_TIME
Nenue@1 218 end
Nenue@1 219
Nenue@1 220 -- fadeTime missing,
Nenue@1 221 if not self.fadeTime then
Nenue@1 222 local fadeRatio = 1
Nenue@1 223 if self.fadeFrom ~= self.alpha then
Nenue@1 224 fadeRatio = (self.fadeTo - self.fadeFrom) / (self.fadeTo - self.alpha) -- target delta
Nenue@1 225 end
Nenue@1 226 --print(fadeRatio, self.fadeDuration)
Nenue@1 227 self.fadeTime = time + fadeRatio * self.fadeDuration -- fixed rate of change
Nenue@1 228 end
Nenue@1 229
Nenue@1 230 -- are we done?
Nenue@1 231 if time >= self.fadeTime then
Nenue@1 232 self:SetAlpha(self.fadeTo)
Nenue@1 233 self.alpha = self.fadeTo
Nenue@1 234 self.fadeTo = nil
Nenue@1 235 self.fadeFrom = nil
Nenue@1 236 self.fadeDuration = nil
Nenue@1 237 self.fadeTime = nil
Nenue@1 238 else --nope
Nenue@1 239 local remaining = (self.fadeTime - time) / self.fadeDuration
Nenue@1 240 local fadeTotal = (self.fadeTo - self.fadeFrom)
Nenue@1 241 --print(self.fadeTo - (fadeTotal * remaining), fadeTotal * remaining)
Nenue@1 242 self:SetAlpha(self.fadeTo - (fadeTotal * remaining))
Nenue@1 243 end
Nenue@1 244 end
Nenue@1 245
Nenue@1 246 -- termination check
Nenue@1 247 if self.isTimer then
Nenue@1 248 if time >= self.endTime and self.fadeTo == nil then
Nenue@1 249 self:Hide()
Nenue@1 250 return
Nenue@1 251 else
Nenue@1 252 self.percent = (self.endTime - time) / self.duration
Nenue@1 253 end
Nenue@1 254 end
Nenue@1 255
Nenue@1 256 else
Nenue@1 257 self.percent = (self.value - self.min) / (self.max - self.min)
Nenue@1 258 end
Nenue@1 259
Nenue@1 260 self:UpdateText()
Nenue@1 261 self.foreground:SetPoint('BOTTOMRIGHT', self, 'BOTTOMLEFT', self.db.width * self.percent + self.db.foreground_inset, 0-self.db.foreground_inset)
Nenue@1 262 end
Nenue@1 263
Nenue@1 264 function T:Bar_UpdateText()
Nenue@1 265 local c = {self:GetChildren()}
Nenue@1 266 for _, rl in ipairs(c) do
Nenue@1 267 if rl.text then
Nenue@1 268 rl.format = self.db.label_string
Nenue@1 269 rl:Update()
Nenue@1 270 end
Nenue@1 271 end
Nenue@1 272 end
Nenue@1 273
Nenue@1 274 -- addon:AddLabel
Nenue@1 275 -- Constructs a text display and adds it to that region
Nenue@1 276 --
Nenue@1 277 function T:AddLabel (region, config, labelname)
Nenue@1 278 assert(region:IsObjectType('Frame'), "T:CreateLabel(table, table [, string])")
Nenue@1 279 labelname = (labelname or string.format('%x', GetTime() % 1000000))
Nenue@1 280 print('assigning frame for text object |cFFFF9922'..labelname..'|r to '..region:GetName())
Nenue@1 281
Nenue@1 282 local lf = CreateFrame('Frame', region:GetName()..'_'..labelname, region)
Nenue@1 283 local ft = lf:CreateFontString(labelname, 'OVERLAY')
Nenue@1 284 local lx, ly, lp = 0,0, config.label_point
Nenue@1 285 if config.label_inset ~= 0 and lp ~= 'CENTER' then
Nenue@1 286 lx = config.label_inset * inset_factor[lp][1]
Nenue@1 287 ly = config.label_inset * inset_factor[lp][2]
Nenue@1 288 end
Nenue@1 289
Nenue@1 290 lf:SetPoint(lp, region, lp, lx, ly)
Nenue@1 291 lf:SetSize(region:GetWidth(), region:GetHeight())
Nenue@1 292 lf:SetFrameStrata(config.label_strata)
Nenue@1 293
Nenue@1 294 ft:SetFont(LSM:Fetch('font', config.label_font), config.label_size, config.label_outline)
Nenue@1 295 ft:SetAllPoints(lf)
Nenue@1 296 ft:SetJustifyH(config.label_justifyH or (config.label_point:find('LEFT') and 'LEFT' or (config.label_point:find('RIGHT') and 'RIGHT' or 'CENTER')))
Nenue@1 297 ft:SetJustifyV(config.label_justifyV or (config.label_point:find('TOP') and 'TOP' or (config.label_point:find('BOTTOM') and 'BOTTOM' or 'MIDDLE')))
Nenue@1 298 ft:SetTextColor(1, 1, 1)
Nenue@1 299 ft:SetText('SET ME!')
Nenue@1 300
Nenue@1 301 lf.Update = region.isTimer and T.Label_UpdateFormat or T.Label_Update
Nenue@1 302 lf.SetJustifyH = function(self, justify) ft:SetJustifyH(justify) end
Nenue@1 303 lf.SetText = function(self, text) ft:SetText(text) end
Nenue@1 304
Nenue@1 305 lf.text = ft
Nenue@1 306 region[labelname] = lf
Nenue@1 307 return lf
Nenue@1 308 end
Nenue@1 309
Nenue@1 310 -- one of two possible assignments for label:Update()
Nenue@1 311 function T:Label_UpdateFormat()
Nenue@1 312 local region = self:GetParent()
Nenue@1 313 if self.format then
Nenue@1 314 self.value = string.gsub(self.format, '%%p', string.format('%.1f', region.value))
Nenue@1 315 self.value = string.gsub(self.value, '%%d', region.duration)
Nenue@1 316 if region.name then
Nenue@1 317 self.value = string.gsub(self.value, '%%n', region.name)
Nenue@1 318 end
Nenue@1 319 end
Nenue@1 320 self.text:SetText(self.value)
Nenue@1 321 end
Nenue@1 322 function T:Label_Update()
Nenue@1 323 self.text:SetText(self:GetParent().value)
Nenue@1 324 end
Nenue@1 325