| Nenue@6 | 1 --- LibFog-1.0 | 
| Nenue@6 | 2 -- In-house solution to processing frame configuration data. | 
| Nenue@6 | 3 --[[ | 
| Nenue@6 | 4 -- | 
| Nenue@6 | 5  Config Table fields: | 
| Nenue@6 | 6 | 
| Nenue@6 | 7  background .. _color, _texture, _blend       properties of the texture referenced by frame.background | 
| Nenue@6 | 8  foregound  .. " " "                          properties of the texture referenced by frame.foreground | 
| Nenue@6 | 9  backdrop                                     arguments for SetBackdrop | 
| Nenue@6 | 10  border_color                                 sets the border color on an existing frame backdrop | 
| Nenue@6 | 11  alpha, alpha_ooc                             uiobject alpha for in and out of combat | 
| Nenue@6 | 12  combat_fade                                  true to change alpha levels based on combat | 
| Nenue@6 | 13  fade_time, fade_in, fade_out                 fade_time = fade_in or fade_out | 
| Nenue@6 | 14 | 
| Nenue@6 | 15  anchor, parent, anchorTo, x, y               args for UIObject:SetPoint() | 
| Nenue@6 | 16  height, width                                args for Region:SetSize() | 
| Nenue@6 | 17  strata, layer, level                         override the strata, draw layer, and draw level where they apply | 
| Nenue@6 | 18 | 
| Nenue@6 | 19  padding                                      space between frame and background edge | 
| Nenue@6 | 20  foreground_inset                             space between background and foreground edge | 
| Nenue@6 | 21  spacing                                      space between segmented foreground elements (e.g. combo points) | 
| Nenue@6 | 22 | 
| Nenue@6 | 23  font, size, outline                          args for FontString:SetFont() respectively | 
| Nenue@6 | 24  justifyV, justifyH                           LEFT/CENTER/RIGHT, TOP/MIDDLE/BOTTOM | 
| Nenue@6 | 25 | 
| Nenue@6 | 26  SetFrameLayout(): | 
| Nenue@6 | 27  Applies: | 
| Nenue@6 | 28   anchor, parent, anchorTo, x, y | 
| Nenue@6 | 29   width, height, | 
| Nenue@6 | 30   padding, spacing, foreground_inset | 
| Nenue@6 | 31   backdrop, border_color, background_color | 
| Nenue@6 | 32   alpha, alpha_ooc | 
| Nenue@6 | 33 | 
| Nenue@6 | 34  SetStatusTextures(): | 
| Nenue@6 | 35  Applies: | 
| Nenue@6 | 36   foreground_texture, foreground_color, foreground_blend | 
| Nenue@6 | 37   background_texture, background_color, background_blend | 
| Nenue@6 | 38 | 
| Nenue@6 | 39  Defines: | 
| Nenue@6 | 40   fill_direction, fill_width, fill_height, fill_inset | 
| Nenue@6 | 41   :TranslateX(progress) | 
| Nenue@6 | 42   :TranslateY(progress) | 
| Nenue@6 | 43   :SetFillPoints() | 
| Nenue@6 | 44 | 
| Nenue@6 | 45  SetFontLayout(): | 
| Nenue@6 | 46  Applies: | 
| Nenue@6 | 47   anchor, parent, anchorTo, x, y | 
| Nenue@6 | 48   width, height | 
| Nenue@6 | 49   font, size, outline | 
| Nenue@6 | 50   justifyH, justifyV | 
| Nenue@6 | 51 | 
| Nenue@6 | 52  - | 
| Nenue@6 | 53  ]] | 
| Nenue@6 | 54 local MAJOR, MINOR = "LibFog-1.0", 1 | 
| Nenue@6 | 55 local F, oldminor = LibStub:NewLibrary(MAJOR, MINOR) | 
| Nenue@6 | 56 if not F then return end | 
| Nenue@6 | 57 | 
| Nenue@6 | 58 local _G, UIParent, type, unpack, pairs, ipairs, min, abs, tostring, print = _G, UIParent, type, unpack, pairs, ipairs, math.min, math.abs, tostring, print | 
| Nenue@6 | 59 local InCombatLockdown, GetTime, PlaySoundKitID, CreateFrame = InCombatLockdown, GetTime, PlaySoundKitID, CreateFrame | 
| Nenue@6 | 60 local tinsert, wipe, concat = table.insert, table.wipe, table.concat | 
| Nenue@6 | 61 local FADE_OUT_TIME, FADE_IN_TIME = 1, 0.4 | 
| Nenue@6 | 62 | 
| Nenue@6 | 63 --@debug@ | 
| Nenue@6 | 64 local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool | 
| Nenue@6 | 65 local ADDON, scriptargs = ... | 
| Nenue@6 | 66 scriptargs.LibFog = F | 
| Nenue@6 | 67 local print = function(...) | 
| Nenue@6 | 68   if _G.Devian and _G.DevianDB.workspace ~= 1 then | 
| Nenue@6 | 69     _G.print('Layout', ...) | 
| Nenue@6 | 70   end | 
| Nenue@6 | 71 end | 
| Nenue@6 | 72 --- debug highlighters | 
| Nenue@6 | 73 local namef  = function(s) return '|cFFFFFF00' ..tostring(s).. '|r' end    -- uiobject targeted function | 
| Nenue@6 | 74 local namet  = function(s) return '|cFFFF4400 '..tostring(s).. '|r' end    --   region targeted function | 
| Nenue@6 | 75 local valuef = function(s) return '|cFF88FF88'..(s ~= nil and ('"'..tostring(s)..'"') or ('nil'))..'|r' end    -- uiobject name | 
| Nenue@6 | 76 local valuet = function(s) return '|cFFAACCAA'..(s ~= nil and ('"'..tostring(s)..'"') or ('nil'))..'|r' end    --   string value | 
| Nenue@6 | 77 local valuen = function(s) return '|cFFAADD77' ..(s ~= nil and ('"'..tostring(s)..'"') or ('nil')).. '|r' end    --   string enumeration | 
| Nenue@6 | 78 local valued = function(s) return '|cFFFFFFFF' ..(s ~= nil and ('"'..tostring(s)..'"') or ('nil')).. '|r' end    --   number | 
| Nenue@6 | 79 --@end-debug@ | 
| Nenue@6 | 80 local GetPrint = function(trace) | 
| Nenue@6 | 81   if trace then | 
| Nenue@6 | 82     return print | 
| Nenue@6 | 83   else | 
| Nenue@6 | 84     return function() end | 
| Nenue@6 | 85   end | 
| Nenue@6 | 86 end | 
| Nenue@6 | 87 | 
| Nenue@6 | 88 --- Layout control metadata | 
| Nenue@6 | 89 local lastdb      -- fallback if a table isn't found mid-operation | 
| Nenue@6 | 90 local ui_meta = { | 
| Nenue@6 | 91   beepkit = 15263, -- something to play when debugging | 
| Nenue@6 | 92 } | 
| Nenue@6 | 93 local ui_embeds = { | 
| Nenue@6 | 94   ['Frame'] = 'SetFrameLayout', | 
| Nenue@6 | 95   ['Texture'] = 'SetTextureLayout', | 
| Nenue@6 | 96   ['Font'] = 'SetFontLayout', | 
| Nenue@6 | 97 } | 
| Nenue@6 | 98 | 
| Nenue@6 | 99 --- Resolve a parent object from varying depths | 
| Nenue@6 | 100 -- @param self target object | 
| Nenue@6 | 101 -- @parent string/number name of global frame or number of GetParent() hops to make | 
| Nenue@6 | 102 -- @childKey index key to retrieve from the resolved parent object | 
| Nenue@6 | 103 local function ParentValue(self, parent, childKey) | 
| Nenue@6 | 104   local print = GetPrint(self.trace) | 
| Nenue@6 | 105 | 
| Nenue@6 | 106   local relativeTo = parent | 
| Nenue@6 | 107   if type(parent) == 'number' then | 
| Nenue@6 | 108     print(cWord('* Parent Trace:'), cNum(parent), cKey(self:GetName())) | 
| Nenue@6 | 109     relativeTo = self:GetParent() | 
| Nenue@6 | 110     for i = 2, parent do | 
| Nenue@6 | 111       if relativeTo.GetParent and relativeTo:GetParent() ~= UIParent then | 
| Nenue@6 | 112         --@debug@ | 
| Nenue@6 | 113         print('  ', 'parent =', relativeTo:GetName()) | 
| Nenue@6 | 114         --@end-debug | 
| Nenue@6 | 115         local next = relativeTo:GetParent() | 
| Nenue@6 | 116         relativeTo = next | 
| Nenue@6 | 117       else | 
| Nenue@6 | 118         --@debug@ | 
| Nenue@6 | 119         print('  ',cWord(self:GetName()), 'parent =', cWord(parent)) | 
| Nenue@6 | 120         --@debug-end@ | 
| Nenue@6 | 121       end | 
| Nenue@6 | 122     end | 
| Nenue@6 | 123   end | 
| Nenue@6 | 124 | 
| Nenue@6 | 125   -- This allows us to call for an immediate sub-frame and still get a usable value if it's not there | 
| Nenue@6 | 126   if childKey and relativeTo[childKey] then | 
| Nenue@6 | 127     return relativeTo[childKey] | 
| Nenue@6 | 128   end | 
| Nenue@6 | 129   return relativeTo | 
| Nenue@6 | 130 end | 
| Nenue@6 | 131 | 
| Nenue@6 | 132 --- Animations | 
| Nenue@6 | 133 F.animate_regions = {} | 
| Nenue@6 | 134 setmetatable(F.animate_regions, { | 
| Nenue@6 | 135   __newindex = function (t,k,v) | 
| Nenue@6 | 136     rawset(t,k,v) | 
| Nenue@6 | 137     v.animationID = k | 
| Nenue@6 | 138     F.SetAnimationGroup(v) | 
| Nenue@6 | 139   end | 
| Nenue@6 | 140 }) | 
| Nenue@6 | 141 | 
| Nenue@6 | 142 --- Constructs the generic status frame | 
| Nenue@6 | 143 function F:SetFrameLayout(c) | 
| Nenue@6 | 144   local print = GetPrint(c.trace) | 
| Nenue@6 | 145   self.trace = c.trace or self.trace | 
| Nenue@6 | 146 | 
| Nenue@6 | 147   self.db = c | 
| Nenue@6 | 148   self.labels = {} | 
| Nenue@6 | 149 | 
| Nenue@6 | 150   self.name = self:GetName() | 
| Nenue@6 | 151   self.combat = InCombatLockdown() | 
| Nenue@6 | 152   self:SetPoint(c.anchor, c.parent, c.anchorTo, c.x, c.y) | 
| Nenue@6 | 153   self:SetSize(c.width, c.height) | 
| Nenue@6 | 154   self:SetFrameStrata(c.strata) | 
| Nenue@6 | 155   self.throttle_rate = 0.010 | 
| Nenue@6 | 156   self.throttle_point = GetTime() | 
| Nenue@6 | 157 | 
| Nenue@6 | 158   if c.backdrop then | 
| Nenue@6 | 159     c.backdrop.edgeSize = c.padding*4 | 
| Nenue@6 | 160     self:SetBackdrop(c.backdrop) | 
| Nenue@6 | 161   end | 
| Nenue@6 | 162   if c.background_color and c.border_color then | 
| Nenue@6 | 163     self:SetBackdropColor(unpack(c.background_color)) | 
| Nenue@6 | 164     self:SetBackdropBorderColor(unpack(c.border_color)) | 
| Nenue@6 | 165   end | 
| Nenue@6 | 166 | 
| Nenue@6 | 167   --@debug@ | 
| Nenue@6 | 168   print(namef('SetFrameLayout'),'(', valuet(self:GetName()),')') | 
| Nenue@6 | 169   print(cText('  dimensions:'), cNum(c.width), 'by', cNum(c.height), '::', c.x, c.y,  c.anchor, c.anchorTo, c.parent) | 
| Nenue@6 | 170   --@end-debug@ | 
| Nenue@6 | 171 | 
| Nenue@6 | 172   self.width = c.width | 
| Nenue@6 | 173   self.height = c.height | 
| Nenue@6 | 174   self.foreground_inset = c.foreground_inset | 
| Nenue@6 | 175   self.padding = c.padding | 
| Nenue@6 | 176   self.spacing = c.spacing | 
| Nenue@6 | 177   self.alpha = c.alpha | 
| Nenue@6 | 178 | 
| Nenue@6 | 179   self.combatFade = c.combatFade | 
| Nenue@6 | 180   self.alpha_fade_in = c.alpha_fade_in or c.alpha_fade | 
| Nenue@6 | 181   self.alpha_fade_out = c.alpha_fade_out or c.alpha_fade | 
| Nenue@6 | 182   print('  fade on combat =', self.combatFade) | 
| Nenue@6 | 183   for _, type in ipairs({'alpha', 'alpha_ooc'}) do | 
| Nenue@6 | 184     self[type] = c[type] | 
| Nenue@6 | 185     _G.print('DB', self:GetName(), type, self[type]) | 
| Nenue@6 | 186     for _, subtype in ipairs({'_passive', '_active'}) do | 
| Nenue@6 | 187       self[type..subtype] = c[type..subtype] or self[type] | 
| Nenue@6 | 188       _G.print('DB', self:GetName(), type..subtype, self[type..subtype]) | 
| Nenue@6 | 189       for _, subsubtype in ipairs({'_empty', '_half', '_full'}) do | 
| Nenue@6 | 190         self[type..subtype..subsubtype] = c[type..subtype..subsubtype] or self[type..subtype] | 
| Nenue@6 | 191         _G.print('DB', self:GetName(), type..subtype..subsubtype, self[type..subtype..subsubtype]) | 
| Nenue@6 | 192         self[type..subsubtype] = c[type..subsubtype] or self[type..subtype] | 
| Nenue@6 | 193         _G.print('DB', self:GetName(), type..subsubtype, self[type..subsubtype]) | 
| Nenue@6 | 194       end | 
| Nenue@6 | 195     end | 
| Nenue@6 | 196   end | 
| Nenue@6 | 197   self.UpdateAlpha = F.UpdateAlpha | 
| Nenue@6 | 198   --if c.combatFade then | 
| Nenue@6 | 199   self.faderID = #F.animate_regions+1 | 
| Nenue@6 | 200   F.animate_regions[#F.animate_regions+1] = self | 
| Nenue@6 | 201   print(cText('  animation target ID #'), cNum(self.faderID)) | 
| Nenue@6 | 202   --end | 
| Nenue@6 | 203 | 
| Nenue@6 | 204   self:UpdateAlpha(InCombatLockdown()) | 
| Nenue@6 | 205 | 
| Nenue@6 | 206   if self.lefttext then | 
| Nenue@6 | 207     print('  auto-lefttext') | 
| Nenue@6 | 208     F.SetFontLayout(self.lefttext, c.lefttext or c) | 
| Nenue@6 | 209   end | 
| Nenue@6 | 210   if self.righttext then | 
| Nenue@6 | 211     print('  auto-righttext') | 
| Nenue@6 | 212     F.SetFontLayout(self.righttext, c.righttext or c) | 
| Nenue@6 | 213   end | 
| Nenue@6 | 214 end | 
| Nenue@6 | 215 | 
| Nenue@6 | 216 --- Seeds basic animations, else a template can be specified by the frame data | 
| Nenue@6 | 217 function F:SetAnimationGroup(group) | 
| Nenue@6 | 218   local print = GetPrint(self.trace) | 
| Nenue@6 | 219 | 
| Nenue@6 | 220   group = group or self.animationClass or nil | 
| Nenue@6 | 221   --@debug@ | 
| Nenue@6 | 222   if not group then | 
| Nenue@6 | 223     print('  |cFFFF44AAseeding debug animations', self:GetName()) | 
| Nenue@6 | 224     self.__flash = self:CreateAnimationGroup(self:GetName()..'Flasher') | 
| Nenue@6 | 225     self.__flash:SetToFinalAlpha(true) | 
| Nenue@6 | 226     local fade1 = self.__flash:CreateAnimation('Alpha') | 
| Nenue@6 | 227     fade1:SetChange(-1) | 
| Nenue@6 | 228     fade1:SetDuration(.6) | 
| Nenue@6 | 229     fade1:SetOrder(1) | 
| Nenue@6 | 230     local fade2 = self.__flash:CreateAnimation('Alpha') | 
| Nenue@6 | 231     fade2:SetChange(1) | 
| Nenue@6 | 232     fade2:SetDuration(.6) | 
| Nenue@6 | 233     fade2:SetOrder(2) | 
| Nenue@6 | 234     fade2:SetEndDelay(.6) | 
| Nenue@6 | 235     --@debug@ | 
| Nenue@6 | 236     self.__flash.fade1 = fade1 | 
| Nenue@6 | 237     self.__flash.fade2 = fade2 | 
| Nenue@6 | 238     self.__flash:SetLooping('NONE') | 
| Nenue@6 | 239     self.__flash:SetScript('OnFinished', function() | 
| Nenue@6 | 240       print(self:GetName(), '[>>>] Done animating flash.') | 
| Nenue@6 | 241       self.flashing = nil | 
| Nenue@6 | 242     end)--@end-debug@ | 
| Nenue@6 | 243     self.Flash = F.Flash | 
| Nenue@6 | 244 | 
| Nenue@6 | 245     self.__fade = self:CreateAnimationGroup(self:GetName()..'Fader') | 
| Nenue@6 | 246     self.__fade:SetToFinalAlpha(true) | 
| Nenue@6 | 247     self.__fade:SetScript('OnFinished', function() | 
| Nenue@6 | 248       print(self:GetName(), '[>>>] Done animating fade.') | 
| Nenue@6 | 249       self.fading = nil | 
| Nenue@6 | 250       local a = self.__flash.fade1:GetToAlpha() | 
| Nenue@6 | 251       --self:SetAlpha(a) | 
| Nenue@6 | 252       if a == 0 and not self.__fade.noHide then | 
| Nenue@6 | 253         self:Hide() | 
| Nenue@6 | 254       end | 
| Nenue@6 | 255       if self.__fade.queuedFade then | 
| Nenue@6 | 256         print('[>>>]  ', cWord(self:GetName())..'.'..cKey('__fade:'), 'starting queued fade') | 
| Nenue@6 | 257         local fadeTo, fadeDuration, noHide = unpack(self.__fade.queuedFade) | 
| Nenue@6 | 258         self.__fade.queuedFade = nil | 
| Nenue@6 | 259         self:Fade(fadeTo, fadeDuration, noHide) | 
| Nenue@6 | 260       end | 
| Nenue@6 | 261     end) | 
| Nenue@6 | 262     self.Fade = F.Fade | 
| Nenue@6 | 263   end | 
| Nenue@6 | 264   --@end-debug@ | 
| Nenue@6 | 265   if not self.animationID then | 
| Nenue@6 | 266     tinsert(F.animate_regions, self) -- uses rawset, so won't death loop | 
| Nenue@6 | 267     self.animationID = #F.animate_regions | 
| Nenue@6 | 268   end | 
| Nenue@6 | 269 end | 
| Nenue@6 | 270 | 
| Nenue@6 | 271 function F:Flash(duration, peak, valley, holdUp, holdDown) | 
| Nenue@6 | 272   local print = GetPrint(self.trace) | 
| Nenue@6 | 273 | 
| Nenue@6 | 274   local fl = self.__flash | 
| Nenue@6 | 275   print('[>>>]', self:GetName(), duration, peak, valley, holdUp, holdDown) | 
| Nenue@6 | 276   fl.fade1:SetFromAlpha(valley) | 
| Nenue@6 | 277   fl.fade1:SetToAlpha(peak) | 
| Nenue@6 | 278   fl.fade1:SetDuration(duration) | 
| Nenue@6 | 279   fl.fade1:SetEndDelay(holdUp) | 
| Nenue@6 | 280   fl.fade2:SetFromAlpha(peak) | 
| Nenue@6 | 281   fl.fade2:SetToAlpha(valley) | 
| Nenue@6 | 282   fl.fade2:SetDuration(duration) | 
| Nenue@6 | 283   fl.fade2:SetEndDelay(2) | 
| Nenue@6 | 284   self.flashing = true | 
| Nenue@6 | 285   fl:Play() | 
| Nenue@6 | 286 end | 
| Nenue@6 | 287 | 
| Nenue@6 | 288 --- Fade to a value; fading to 0 will hide the frame | 
| Nenue@6 | 289 function F:Fade(duration, fadeTo, noHide) | 
| Nenue@6 | 290 | 
| Nenue@6 | 291   print('|cFFFF6600[>>>]', cText('Fade('), self:GetName(), cText(')')) | 
| Nenue@6 | 292   local fader = self.__fade | 
| Nenue@6 | 293   local fade1 = self.__flash.fade1 | 
| Nenue@6 | 294   if fader:IsPlaying() then | 
| Nenue@6 | 295     self.__fade.queuedFade = {duration, fadeTo, noHide } | 
| Nenue@6 | 296     print('    ', cText('playing:'), cNum(fader:GetDuration())..'s', cNum(fade1:GetToAlpha())) | 
| Nenue@6 | 297     print('    ', cPink('queued {'),  cNum(duration)..'s', cNum(self:GetAlpha()), 'to', cNum(fadeTo), '}') | 
| Nenue@6 | 298     return | 
| Nenue@6 | 299   else | 
| Nenue@6 | 300     print('    ', cNum('starting {'), cNum(duration), cNum(self:GetAlpha()), 'to', cNum(fadeTo), '}') | 
| Nenue@6 | 301   end | 
| Nenue@6 | 302   fade1:SetParent(fader) | 
| Nenue@6 | 303   fade1:SetFromAlpha(self:GetAlpha()) | 
| Nenue@6 | 304   fade1:SetToAlpha(fadeTo) | 
| Nenue@6 | 305   fade1:SetDuration(duration) | 
| Nenue@6 | 306   fade1:SetOrder(1) | 
| Nenue@6 | 307   self.__fade.noHide = noHide | 
| Nenue@6 | 308   self.fading = true | 
| Nenue@6 | 309   fader:Play() | 
| Nenue@6 | 310 end | 
| Nenue@6 | 311 | 
| Nenue@6 | 312 function F:Beep() | 
| Nenue@6 | 313   if self.quiet then | 
| Nenue@6 | 314     return | 
| Nenue@6 | 315   end | 
| Nenue@6 | 316   PlaySoundKitID(F.beepkit) -- random anub'rhekan sounds | 
| Nenue@6 | 317 end | 
| Nenue@6 | 318 | 
| Nenue@6 | 319 | 
| Nenue@6 | 320 --- Defines the corners used in filling operations | 
| Nenue@6 | 321 local directionBase = { | 
| Nenue@6 | 322   ['LEFT'] = 'TOPRIGHT', | 
| Nenue@6 | 323   ['RIGHT'] = 'TOPLEFT', | 
| Nenue@6 | 324   ['UP'] = 'BOTTOMLEFT', | 
| Nenue@6 | 325   ['DOWN'] = 'TOPLEFT' | 
| Nenue@6 | 326 } | 
| Nenue@6 | 327 local directionPeak ={ | 
| Nenue@6 | 328   ['LEFT'] = 'BOTTOMLEFT', | 
| Nenue@6 | 329   ['RIGHT'] = 'BOTTOMRIGHT', | 
| Nenue@6 | 330   ['UP'] = 'TOPRIGHT', | 
| Nenue@6 | 331   ['DOWN'] = 'BOTTOMRIGHT', | 
| Nenue@6 | 332 } | 
| Nenue@6 | 333 local directionPeakTo = { | 
| Nenue@6 | 334   ['LEFT'] = 'BOTTOMRIGHT', | 
| Nenue@6 | 335   ['RIGHT'] = 'BOTTOMLEFT', | 
| Nenue@6 | 336   ['UP'] = 'BOTTOMRIGHT', | 
| Nenue@6 | 337   ['DOWN'] = 'TOPRIGHT' | 
| Nenue@6 | 338 } | 
| Nenue@6 | 339 local anchorInverse = {['LEFT'] = 'RIGHT', ['RIGHT'] = 'LEFT', ['TOP'] = 'BOTTOM', ['BOTTOM'] = 'TOP' } | 
| Nenue@6 | 340 --- Directional coefficients for corner positions | 
| Nenue@6 | 341 -- [1] = end X, [2] = end Y, [3] = base X, [4] = base Y | 
| Nenue@6 | 342 local directionCoord = { | 
| Nenue@6 | 343   ['LEFT']   = {-1,  0, -1, -1}, | 
| Nenue@6 | 344   ['RIGHT']  = { 1,  0, 1, -1}, | 
| Nenue@6 | 345   ['UP']     = { 0, 1, 1, 1}, | 
| Nenue@6 | 346   ['DOWN']   = { 0, -1, 1, -1}, | 
| Nenue@6 | 347   ['CENTER'] = {.5, .5, 1, 1} | 
| Nenue@6 | 348 } | 
| Nenue@6 | 349 local paddingScale = { | 
| Nenue@6 | 350   ['UP'] = 1, | 
| Nenue@6 | 351   ['DOWN'] = -1, | 
| Nenue@6 | 352   ['LEFT'] = -1, | 
| Nenue@6 | 353   ['RIGHT'] = 1, | 
| Nenue@6 | 354 } | 
| Nenue@6 | 355 local embedScale = { | 
| Nenue@6 | 356   ['LEFT'] = {1, false}, | 
| Nenue@6 | 357   ['RIGHT'] = {-1, false}, | 
| Nenue@6 | 358   ['TOP'] = {false, -1}, | 
| Nenue@6 | 359   ['BOTTOM'] = {false, 1} | 
| Nenue@6 | 360 } | 
| Nenue@6 | 361 | 
| Nenue@6 | 362 --- Determines the correct relative X offset for a given progress ratio | 
| Nenue@6 | 363 --- x = 0 + padding + spacing + i, where i = {embedded | icon_size +spacing} | 
| Nenue@6 | 364 -- Factors padding and spacing parameters, including icon embedding dimensions. | 
| Nenue@6 | 365 -- @param self frame on which the foreground/background textures and config data exist | 
| Nenue@6 | 366 -- @param ratio progess from 0 to 1; 0 returns the starting corner coordinate, 1 returns end corner | 
| Nenue@6 | 367 -- @param scale overrides the pixel fill length, with starting corner used as scaling origin | 
| Nenue@6 | 368 local TranslateX    = function(self, ratio, scale) | 
| Nenue@6 | 369   if not scale then | 
| Nenue@6 | 370     scale = self.fill_width | 
| Nenue@6 | 371   end | 
| Nenue@6 | 372   if self.fill_inverse then | 
| Nenue@6 | 373     ratio = 1 - ratio | 
| Nenue@6 | 374   end | 
| Nenue@6 | 375   _G.print('Update', 'dx', self.fill_x) | 
| Nenue@6 | 376   local x = | 
| Nenue@6 | 377       scale * ratio * directionCoord[self.fill_direction][1] | 
| Nenue@6 | 378   return min(x, scale) + self.fill_x | 
| Nenue@6 | 379 end | 
| Nenue@6 | 380 | 
| Nenue@6 | 381 --- Determines the correct relative Y offset for a given progress ratio | 
| Nenue@6 | 382 -- Factors padding and spacing parameters, including icon embedding dimensions. | 
| Nenue@6 | 383 -- @param self frame on which the foreground/background textures and config data exist | 
| Nenue@6 | 384 -- @param ratio progess from 0 to 1; 0 returns the starting corner coordinate, 1 returns end corner | 
| Nenue@6 | 385 -- @param scale overrides the pixel fill length, with starting corner used as scaling origin | 
| Nenue@6 | 386 local TranslateY    = function(self, ratio, scale) | 
| Nenue@6 | 387   if not scale then | 
| Nenue@6 | 388     scale = self.fill_height | 
| Nenue@6 | 389   end | 
| Nenue@6 | 390   if self.fill_inverse then | 
| Nenue@6 | 391     ratio = 1 - ratio | 
| Nenue@6 | 392   end | 
| Nenue@6 | 393 | 
| Nenue@6 | 394   _G.print('Update', 'dy', self.fill_y) | 
| Nenue@6 | 395   -- (height of bar offset by the size of any overlapping element) * progress ratio, offset by the size of any overlapping embed + inset | 
| Nenue@6 | 396   local y = | 
| Nenue@6 | 397       scale * ratio * directionCoord[self.fill_direction][2] - self.foreground_inset | 
| Nenue@6 | 398   return min(y, scale) + self.fill_y | 
| Nenue@6 | 399 end | 
| Nenue@6 | 400 local SetProgress = function(self, progress, scaleX, scaleY) | 
| Nenue@6 | 401   _G.print('Update', cText(self:GetName()), | 
| Nenue@6 | 402     "\n     d:", progress, 'dX:', directionCoord[self.fill_direction][1], 'dY:', directionCoord[self.fill_direction][2], 'dI:', self.fill_inverse, | 
| Nenue@6 | 403     "\n  peak:", self.fill_anchor, self.fill_anchorTo, TranslateX(self, progress), TranslateY(self,progress)) | 
| Nenue@6 | 404 | 
| Nenue@6 | 405   self.foreground:SetPoint(self.fill_anchor, self.background, self.fill_anchorTo, TranslateX(self, progress, scaleX), TranslateY(self, progress, scaleY)) | 
| Nenue@6 | 406 end | 
| Nenue@6 | 407 | 
| Nenue@6 | 408 --- Assigns textures to the generic foreground background bar regions | 
| Nenue@6 | 409 -- Called as F.SetStatusTextures(MyFrame, config pointer) | 
| Nenue@6 | 410 -- foreground_inset - number of pixels by which the foreground edges occlude the background (basically always negative) | 
| Nenue@6 | 411 -- padding - number of pixels between the background edge and frame edge (basically always positive) | 
| Nenue@6 | 412 function F:SetStatusTextures(c) | 
| Nenue@6 | 413   local print = GetPrint(self.trace) | 
| Nenue@6 | 414 | 
| Nenue@6 | 415   if c == nil then | 
| Nenue@6 | 416     c = self.db or lastdb | 
| Nenue@6 | 417     if not c then | 
| Nenue@6 | 418       error('No config table found') | 
| Nenue@6 | 419     end | 
| Nenue@6 | 420   end | 
| Nenue@6 | 421   local relativeTo = ParentValue(self, c.parent, c.parentKey) | 
| Nenue@6 | 422 | 
| Nenue@6 | 423 | 
| Nenue@6 | 424   self.fill_direction = c.fill_direction or 'RIGHT' | 
| Nenue@6 | 425   self.fill_inset = c.padding - c.foreground_inset  -- foreground edge / frame edge | 
| Nenue@6 | 426   self.fill_width = self.width - self.fill_inset*2       -- foreground left / right edges | 
| Nenue@6 | 427   self.fill_height = self.height - self.fill_inset*2     --           " top / bottom " | 
| Nenue@6 | 428   self.fill_inverse = c.fill_inverse | 
| Nenue@6 | 429   self.fill_x, self.fill_y = 0, 0 | 
| Nenue@6 | 430   self.fill_insets = { | 
| Nenue@6 | 431     LEFT = self.fill_inset, | 
| Nenue@6 | 432     TOP = self.fill_inset, | 
| Nenue@6 | 433     BOTTOM = self.fill_inset, | 
| Nenue@6 | 434     RIGHT = self.fill_inset | 
| Nenue@6 | 435   } | 
| Nenue@6 | 436 | 
| Nenue@6 | 437 | 
| Nenue@6 | 438   -- create filling points | 
| Nenue@6 | 439   self.fill_base     = directionBase[self.fill_direction] | 
| Nenue@6 | 440   self.fill_anchor   =   directionPeak[self.fill_direction] | 
| Nenue@6 | 441   self.fill_anchorTo =   directionPeakTo[self.fill_direction] | 
| Nenue@6 | 442   print("   foreground:", self.fill_base, self.fill_base, TranslateX(self, 0), TranslateY(self, 0)) | 
| Nenue@6 | 443   print("   foreground fill:", self.fill_anchor, self.fill_anchorTo) | 
| Nenue@6 | 444 | 
| Nenue@6 | 445   -- calculate icon embed | 
| Nenue@6 | 446   if self.icon and self.icon.embedded then | 
| Nenue@6 | 447     print(cText('#### EMBED ####')) | 
| Nenue@6 | 448     -- change anchor point so the icon is inside | 
| Nenue@6 | 449     self.icon.anchor = self.icon.anchorTo | 
| Nenue@6 | 450     print('   * Icon anchor:' , cText(self.icon.anchor), 'to', cText(self.icon.anchorTo)) | 
| Nenue@6 | 451     print('   * Fill start:', cText(self.fill_base)) | 
| Nenue@6 | 452 | 
| Nenue@6 | 453 | 
| Nenue@6 | 454     local coordSet = {nil, nil} | 
| Nenue@6 | 455     local baseSet = {nil, nil } | 
| Nenue@6 | 456     local endSet = {nil, nil} | 
| Nenue@6 | 457     for dir, coords in pairs(embedScale) do | 
| Nenue@6 | 458       if self.icon.anchor:match(dir) then | 
| Nenue@6 | 459         print('   xtrans { matches', dir, 'include {', coords[1], coords[2], '}') | 
| Nenue@6 | 460         if not coordSet[1] then coordSet[1] = coords[1] end | 
| Nenue@6 | 461         if not coordSet[2] then coordSet[2] = coords[2] end | 
| Nenue@6 | 462 | 
| Nenue@6 | 463         -- the embedding position can overlap either corner | 
| Nenue@6 | 464         if self.fill_base:match(dir) then | 
| Nenue@6 | 465           print('   base corner also matches') | 
| Nenue@6 | 466           if not baseSet[1] then baseSet[1] = coords[1] end | 
| Nenue@6 | 467           if not baseSet[2] then baseSet[2] = coords[2] end | 
| Nenue@6 | 468         else | 
| Nenue@6 | 469 | 
| Nenue@6 | 470           if not endSet[1] then endSet[1] = coords[1] end | 
| Nenue@6 | 471           if not endSet[2] then endSet[2] = coords[2] end | 
| Nenue@6 | 472         end | 
| Nenue@6 | 473       end | 
| Nenue@6 | 474     end | 
| Nenue@6 | 475 | 
| Nenue@6 | 476     -- make sure there are values if none of them matched at all for some reason | 
| Nenue@6 | 477     coordSet = {coordSet[1] or 0, coordSet[2] or 0} | 
| Nenue@6 | 478     baseSet = {baseSet[1] or 0, baseSet[2] or 0 } | 
| Nenue@6 | 479     -- needs to produce a negative number | 
| Nenue@6 | 480     endSet = {endSet[1] or 0, endSet[2] or 0 } | 
| Nenue@6 | 481 | 
| Nenue@6 | 482 | 
| Nenue@6 | 483     print('  == xtrans push =', unpack(coordSet)) | 
| Nenue@6 | 484     print('  == fbase delta =', unpack(baseSet)) | 
| Nenue@6 | 485     print('  == ftail delta =', unpack(endSet)) | 
| Nenue@6 | 486 | 
| Nenue@6 | 487     -- determine the foreground displacement | 
| Nenue@6 | 488 | 
| Nenue@6 | 489     self.icon_dx = (min(self.fill_width, self.fill_height) + self.spacing) | 
| Nenue@6 | 490     self.icon_dy = (min(self.fill_width, self.fill_height) + self.spacing) | 
| Nenue@6 | 491     print('   * Foreground compression:', cNum(self.icon_dx)) | 
| Nenue@6 | 492 | 
| Nenue@6 | 493     self.icon_size = self.icon.size | 
| Nenue@6 | 494     self.icon_x = self.padding * baseSet[1] - (self.icon.size - self.icon_dx) | 
| Nenue@6 | 495     self.icon_y = self.padding * baseSet[2] - (self.icon.size - self.icon_dy) | 
| Nenue@6 | 496     print('   * Icon dims:' , cNum(self.icon_size), ' offset:', cNum(self.icon_dx)) | 
| Nenue@6 | 497 | 
| Nenue@6 | 498 | 
| Nenue@6 | 499     local ofi = self.fill_insets[self.fill_direction] | 
| Nenue@6 | 500     print('   * Fill inset('..cWord(self.fill_direction)..') from', cNum(ofi), 'to', cNum(self.fill_insets[self.fill_direction])) | 
| Nenue@6 | 501 | 
| Nenue@6 | 502     -- used to place the starting corner | 
| Nenue@6 | 503     self.fill_x = (self.icon_dx) * baseSet[1] | 
| Nenue@6 | 504     self.fill_y = (self.icon_dy) * baseSet[2] | 
| Nenue@6 | 505     print('   * fill offset dX:', self.fill_x) | 
| Nenue@6 | 506     print('   * fill offset dY:', self.fill_y) | 
| Nenue@6 | 507 | 
| Nenue@6 | 508     -- amount taken off of fill scale, subtract spacing | 
| Nenue@6 | 509     self.icon_dx_cut = abs(self.icon_dx * -baseSet[1]) | 
| Nenue@6 | 510     self.icon_dy_cut = abs(self.icon_dy * -baseSet[2]) | 
| Nenue@6 | 511 | 
| Nenue@6 | 512     local ofw, ofh = self.fill_width, self.fill_height | 
| Nenue@6 | 513     self.fill_width = self.fill_width - self.icon_dx_cut | 
| Nenue@6 | 514     self.fill_height = self.fill_height - self.icon_dy_cut | 
| Nenue@6 | 515     print('   * Scale dX:', self.icon_dx_cut, cNum(ofw), 'to', cNum(self.fill_width)) | 
| Nenue@6 | 516     print('   * Scale dY:', self.icon_dy_cut, cNum(ofh), 'to', cNum(self.fill_height)) | 
| Nenue@6 | 517 | 
| Nenue@6 | 518     self.icon:ClearAllPoints() | 
| Nenue@6 | 519     self.icon:SetPoint(self.icon.anchor, self, self.icon.anchorTo, self.icon_x, self.padding * coordSet[2]) | 
| Nenue@6 | 520     self.icon:SetSize(self.icon_size, self.icon_size) | 
| Nenue@6 | 521   end | 
| Nenue@6 | 522 | 
| Nenue@6 | 523   --@debug@ | 
| Nenue@6 | 524   print(namet('SetStatusTextures'),'(', valuef(self:GetName()), ')') | 
| Nenue@6 | 525   print('   form:', self.padding,'-', self.foreground_inset, '+', self.fill_width, self.padding,'-', self.foreground_inset, '+','x', self.padding,'-', self.foreground_inset, '+', self.fill_height, self.padding,'-', self.foreground_inset, '+') | 
| Nenue@6 | 526   print('  ', valuen(concat(c.background_color,', ')),valuet(c.background_texture), valuen(concat(c.foreground_color,', ')), valuet(c.foreground_texture)) | 
| Nenue@6 | 527   print('   background:', self.padding, self.padding, 'BOTTOMLEFT', 'BOTTOMLEFT' , '::', -self.padding, -self.padding, 'TOPRIGHT', 'TOPRIGHT') | 
| Nenue@6 | 528   --@end-debug@ | 
| Nenue@6 | 529 | 
| Nenue@6 | 530   self.background:ClearAllPoints() | 
| Nenue@6 | 531   self.background:SetPoint('BOTTOMLEFT', self, 'BOTTOMLEFT', self.padding, self.padding) | 
| Nenue@6 | 532   self.background:SetPoint('TOPRIGHT', self, 'TOPRIGHT', -self.padding, -self.padding) | 
| Nenue@6 | 533   if c.background_texture ~= '' and c.background_texture ~= nil then | 
| Nenue@6 | 534     self.background:SetTexture(c.background_texture) | 
| Nenue@6 | 535     self.background:SetVertexColor(unpack(c.background_color)) | 
| Nenue@6 | 536   else | 
| Nenue@6 | 537     self.background:SetTexture(unpack(c.background_color)) | 
| Nenue@6 | 538   end | 
| Nenue@6 | 539   self.background:SetBlendMode(c.background_blend) | 
| Nenue@6 | 540 | 
| Nenue@6 | 541   if c.foreground_texture ~= '' and c.foreground_texture ~= nil then | 
| Nenue@6 | 542     self.foreground:SetTexture(c.foreground_texture) | 
| Nenue@6 | 543     self.foreground:SetVertexColor(unpack(c.foreground_color)) | 
| Nenue@6 | 544   else | 
| Nenue@6 | 545     self.foreground:SetTexture(unpack(c.foreground_color)) | 
| Nenue@6 | 546   end | 
| Nenue@6 | 547   self.foreground:SetBlendMode(c.foreground_blend) | 
| Nenue@6 | 548 | 
| Nenue@6 | 549   self.foreground:ClearAllPoints() | 
| Nenue@6 | 550   local dx = (directionCoord[self.fill_direction][3] * -self.foreground_inset) + self.fill_x | 
| Nenue@6 | 551   local dy = (directionCoord[self.fill_direction][4] * -self.foreground_inset) + self.fill_y | 
| Nenue@6 | 552   print('   foreground base:', cNum(dx), cNum(dy)) | 
| Nenue@6 | 553   self.foreground:SetPoint(self.fill_base, self.background, self.fill_base, dx, dy) | 
| Nenue@6 | 554 | 
| Nenue@6 | 555   SetProgress(self, 1) | 
| Nenue@6 | 556 | 
| Nenue@6 | 557   self.TranslateX = TranslateX | 
| Nenue@6 | 558   self.TranslateY = TranslateY | 
| Nenue@6 | 559   self.SetFillPoints = SetFillPoints | 
| Nenue@6 | 560   self.SetProgress = SetProgress | 
| Nenue@6 | 561 end | 
| Nenue@6 | 562 --- Sets properties for a generated FontString | 
| Nenue@6 | 563 -- Takes the FontString object as a self, and applies config values. | 
| Nenue@6 | 564 -- In particalur, the anchor parent is derived from either a fixed number of GetParent() or global name | 
| Nenue@6 | 565 -- @usage Region:SetFontLayout([table]) | 
| Nenue@6 | 566 function F:SetFontLayout (c) | 
| Nenue@6 | 567   local print = GetPrint(self.trace) | 
| Nenue@6 | 568 | 
| Nenue@6 | 569   if c == nil then | 
| Nenue@6 | 570     c = lastdb | 
| Nenue@6 | 571     if not c then | 
| Nenue@6 | 572       error('No config table found') | 
| Nenue@6 | 573     end | 
| Nenue@6 | 574   end | 
| Nenue@6 | 575   local relativeTo = ParentValue(self, c.parent, c.parentKey) | 
| Nenue@6 | 576 | 
| Nenue@6 | 577   --@debug@ | 
| Nenue@6 | 578   print(namet('FontLayout'),'(', valuet(self:GetName()), ')', valuet(c.font), valuet(c.size), valuet(c.outline)) | 
| Nenue@6 | 579   print('  ', valuen(c.anchor or 'CENTER'), relativeTo:GetName(), valuen(c.anchorTo or 'CENTER'), valued(c.x or 0), | 
| Nenue@6 | 580     valued(c.y or 0)) | 
| Nenue@6 | 581   --@end-debug@ | 
| Nenue@6 | 582   self:SetPoint( | 
| Nenue@6 | 583     c.anchor or 'CENTER', | 
| Nenue@6 | 584     relativeTo, | 
| Nenue@6 | 585     c.anchorTo or 'CENTER', | 
| Nenue@6 | 586     c.x or 0, | 
| Nenue@6 | 587     c.y or 0) | 
| Nenue@6 | 588   self:SetSize( | 
| Nenue@6 | 589     c.width or relativeTo:GetWidth(), | 
| Nenue@6 | 590     c.height or relativeTo:GetHeight()) | 
| Nenue@6 | 591   self:SetFont( | 
| Nenue@6 | 592     c.font, | 
| Nenue@6 | 593     c.size, | 
| Nenue@6 | 594     c.outline) | 
| Nenue@6 | 595   self:SetJustifyH(c.justifyH or 'CENTER') | 
| Nenue@6 | 596   self:SetJustifyV(c.justifyV or 'MIDDLE') | 
| Nenue@6 | 597   self:SetTextColor(unpack(c.text_color or {1,1,1,1})) | 
| Nenue@6 | 598 end | 
| Nenue@6 | 599 | 
| Nenue@6 | 600 --- For setting up widget pieces | 
| Nenue@6 | 601 function F:SetTextureLayout(c) | 
| Nenue@6 | 602   local print = GetPrint(self.trace) | 
| Nenue@6 | 603 | 
| Nenue@6 | 604   if c == nil then | 
| Nenue@6 | 605     c = lastdb | 
| Nenue@6 | 606     if not c then | 
| Nenue@6 | 607       error('No config table found') | 
| Nenue@6 | 608     end | 
| Nenue@6 | 609   end | 
| Nenue@6 | 610   local relativeTo = ParentValue(self, c.parent, c.parentKey) | 
| Nenue@6 | 611 | 
| Nenue@6 | 612   self.size = c.size | 
| Nenue@6 | 613   self.width = c.width | 
| Nenue@6 | 614   self.height = c.height | 
| Nenue@6 | 615   self.x = c.x | 
| Nenue@6 | 616   self.y = c.y | 
| Nenue@6 | 617   self.embedded = c.embedded | 
| Nenue@6 | 618   self.anchor = c.anchor | 
| Nenue@6 | 619   self.anchorTo = c.anchorTo | 
| Nenue@6 | 620 | 
| Nenue@6 | 621   self:SetPoint(c.anchor, relativeTo, c.anchorTo, c.x, c.y) | 
| Nenue@6 | 622   self:SetSize(c.size or c.width, c.size or c.height) | 
| Nenue@6 | 623   self:SetAlpha(c.alpha) | 
| Nenue@6 | 624   self:SetDesaturated(c.desaturated or false) | 
| Nenue@6 | 625   print('|cFF00FFFFSetTextureLayout(|r', self:GetName(), '|cFF00FFFF)|r') | 
| Nenue@6 | 626   print('  ', c.anchor, relativeTo, c.anchorT, c.x, c.v) | 
| Nenue@6 | 627   if c.combatFade and not (relativeTo.faderID and F.animate_regions[relativeTo.faderID]) then | 
| Nenue@6 | 628     tinsert(F.animate_regions, self) | 
| Nenue@6 | 629     self.faderID = #F.animate_regions | 
| Nenue@6 | 630     --@debug@ | 
| Nenue@6 | 631     print('register fadeable texture #'..self.faderID) | 
| Nenue@6 | 632     --@end-debug@ | 
| Nenue@6 | 633   end | 
| Nenue@6 | 634 end | 
| Nenue@6 | 635 | 
| Nenue@6 | 636 local alphaSubType = { | 
| Nenue@6 | 637   [1] = '_passive', | 
| Nenue@6 | 638   [2] = '_active' | 
| Nenue@6 | 639 } | 
| Nenue@6 | 640 local alphaFillType = { | 
| Nenue@6 | 641   [1] = '_empty', | 
| Nenue@6 | 642   [2] = '_half', | 
| Nenue@6 | 643   [3] = '_full', | 
| Nenue@6 | 644 } | 
| Nenue@6 | 645 function F:UpdateAlpha(inCombat, displayState, fillState) | 
| Nenue@6 | 646   local print = function() end | 
| Nenue@6 | 647   print(cWord('UpdateAlpha(')..self:GetName()..cWord(')')) | 
| Nenue@6 | 648   local alphaType = inCombat and 'alpha' or 'alpha_ooc' | 
| Nenue@6 | 649   local alphaDuration = inCombat and 'alpha_fade_in' or 'alpha_fade_out' | 
| Nenue@6 | 650   local displayState = displayState or self.displayState or nil | 
| Nenue@6 | 651   local fillState = fillState or self.fillState or nil | 
| Nenue@6 | 652 | 
| Nenue@6 | 653   local alphaSubType = '' | 
| Nenue@6 | 654   if displayState then | 
| Nenue@6 | 655     alphaSubType = (displayState == 1) and '_passive' or ((displayState == 2) and '_active' or '' ) | 
| Nenue@6 | 656   end | 
| Nenue@6 | 657 | 
| Nenue@6 | 658   local alphaFillType = '' | 
| Nenue@6 | 659   if fillState then | 
| Nenue@6 | 660     alphaFillType = (fillState == 1) and '_half' or ((fillState == 2) and '_full' or '_empty') | 
| Nenue@6 | 661   end | 
| Nenue@6 | 662 | 
| Nenue@6 | 663   local fadeTo = self[alphaType..alphaSubType..alphaFillType] | 
| Nenue@6 | 664   local fadeDuration = self[alphaDuration] or 0 | 
| Nenue@6 | 665   print(' alphaKey:', cWord(alphaType..alphaSubType..alphaFillType)) | 
| Nenue@6 | 666   print(' alphaTo:', cNum(fadeTo), 'duration:', cNum(fadeDuration)) | 
| Nenue@6 | 667   if self:IsVisible() and fadeDuration ~= 0 then | 
| Nenue@6 | 668     self:Fade(fadeDuration, fadeTo or (inCombat and 1 or 0.5), true) | 
| Nenue@6 | 669     print('   |cFFFFFF00  :Fade()|r', 'dur='..cNum(fadeDuration), cNum(fadeTo), cWord(self:GetName())) | 
| Nenue@6 | 670   else | 
| Nenue@6 | 671     self:SetAlpha(fadeTo) | 
| Nenue@6 | 672     print('   |cFF00FF00  :SetAlpha('..fadeTo..')|r', cText(self:GetName())) | 
| Nenue@6 | 673   end | 
| Nenue@6 | 674 end | 
| Nenue@6 | 675 | 
| Nenue@6 | 676 --- Sets an OnUpdate within a time-throttled wrapper | 
| Nenue@6 | 677 -- throttle rate should be slightly smaller than 1/average frame rate | 
| Nenue@6 | 678 function F:SetFrameScript(updateFunc, showFunc, hideFunc, ...) | 
| Nenue@6 | 679   local print = GetPrint(self.trace) | 
| Nenue@6 | 680 | 
| Nenue@6 | 681   if not self.__oldscripts then | 
| Nenue@6 | 682     self.__oldscripts = {} | 
| Nenue@6 | 683   end | 
| Nenue@6 | 684 | 
| Nenue@6 | 685   self:SetScript('OnUpdate', nil) -- clear any scripts | 
| Nenue@6 | 686   self:SetSCript('OnUpdate', function(self) | 
| Nenue@6 | 687     if GetTime() < self.throttle_time then | 
| Nenue@6 | 688       return | 
| Nenue@6 | 689     end | 
| Nenue@6 | 690     self.throttle_time = self.throttle_time + self.throttle_rate | 
| Nenue@6 | 691     updateFunc(self) | 
| Nenue@6 | 692   end) -- put the new function in its place | 
| Nenue@6 | 693   local changeSet = { | 
| Nenue@6 | 694     { self.__oldscripts,onUpdate = self:GetScript('OnUpdate') }, | 
| Nenue@6 | 695   } | 
| Nenue@6 | 696 | 
| Nenue@6 | 697   if showFunc then | 
| Nenue@6 | 698     tinsert(changeSet, | 
| Nenue@6 | 699       {onShow = self:GetScript('OnShow')}) | 
| Nenue@6 | 700     self:SetScript('OnShow', showFunc) | 
| Nenue@6 | 701   end | 
| Nenue@6 | 702 | 
| Nenue@6 | 703   if hideFunc then | 
| Nenue@6 | 704     tinsert(changeSet, | 
| Nenue@6 | 705       {onHide = self:GetScript('OnShow')}) | 
| Nenue@6 | 706     self:SetScript('OnHide', hideFunc) | 
| Nenue@6 | 707   end | 
| Nenue@6 | 708 end | 
| Nenue@6 | 709 | 
| Nenue@6 | 710 --- Embed | 
| Nenue@6 | 711 function F:Embed(object) | 
| Nenue@6 | 712   print('Doing embed') | 
| Nenue@6 | 713   for k, v in pairs(ui_embeds) do | 
| Nenue@6 | 714     print('embedding Set'..k..'Layout') | 
| Nenue@6 | 715     object['Set'..k..'Layout'] = self[v] | 
| Nenue@6 | 716   end | 
| Nenue@6 | 717   object.SetStatusTextures = self.SetStatusTextures | 
| Nenue@6 | 718 | 
| Nenue@6 | 719   --- map a generic layout method if embedded into a frame object | 
| Nenue@6 | 720   if object.GetObjectType and ui_embeds[object.GetObjectType()] then | 
| Nenue@6 | 721     if ui_embeds[object.GetObjectType()] then | 
| Nenue@6 | 722       object.SetLayout = ui_embeds[object.GetObjectType()] | 
| Nenue@6 | 723     end | 
| Nenue@6 | 724   end | 
| Nenue@6 | 725 end |