annotate AceGUIWidget-lib-st.lua @ 66:43913e02a1ef

Detect LFR loot as best we can, and bundle it into the same warning given for heroic loot formatted by name only. Less tedious method of bumping data revisions.
author Farmbuyer of US-Kilrogg <farmbuyer@gmail.com>
date Fri, 27 Apr 2012 10:11:56 +0000
parents fd3dd12f96ce
children 9232cacc9136
rev   line source
farmbuyer@1 1 --[[-----------------------------------------------------------------------------
farmbuyer@1 2 lib-st Beta Wrapper Widget
farmbuyer@1 3
farmbuyer@1 4 lib-st does not recycle the objects (called "ST" here) that it creates and
farmbuyer@1 5 returns. We therefore do not try to hold onto an ST when the widget is
farmbuyer@1 6 being recycled. This means that Constructor() does very little work, and
farmbuyer@1 7 does not actually construct an ST.
farmbuyer@1 8
farmbuyer@1 9 OnAcquire cannot construct an ST either, because we don't yet have any
farmbuyer@1 10 creation parameters from the user to feed to CreateST. (Allowing such to
farmbuyer@1 11 be passed along from AceGUI:Create() would require changes to core AceGUI
farmbuyer@1 12 code, and I don't feel like trying to overcome that inertia.)
farmbuyer@1 13
farmbuyer@1 14 The upshot is that the widget returned from Create is broken and useless
farmbuyer@1 15 until its CreateST member has been called. This means that correct behavior
farmbuyer@1 16 depends entirely on the user remembering to do so.
farmbuyer@1 17
farmbuyer@1 18 "The gods do not protect fools. Fools are protected by more capable fools."
farmbuyer@1 19 - Ringworld
farmbuyer@1 20
farmbuyer@1 21
farmbuyer@1 22 Version 1 initial functioning implementation
farmbuyer@1 23 Version 2 reshuffle to follow new AceGUI widget coding style
farmbuyer@1 24 Version 3 add .tail_offset, defaulting to same absolute value as .head_offset
farmbuyer@47 25 Version 4 restore original frame methods, as fortold by ancient prophecy
farmbuyer@49 26 Version 5 don't bogart the widget object
farmbuyer@1 27 -farmbuyer
farmbuyer@1 28 -------------------------------------------------------------------------------]]
farmbuyer@47 29 local Type, Version = "lib-st", 4
farmbuyer@1 30 local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
farmbuyer@1 31 if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
farmbuyer@1 32
farmbuyer@1 33 -- Lua APIs
farmbuyer@1 34 local ipairs, error = ipairs, error
farmbuyer@1 35
farmbuyer@1 36 -- WoW APIs
farmbuyer@1 37 local debugstack = debugstack
farmbuyer@1 38 local CreateFrame = CreateFrame
farmbuyer@1 39
farmbuyer@1 40
farmbuyer@1 41 --[[-----------------------------------------------------------------------------
farmbuyer@1 42 Support functions
farmbuyer@1 43 -------------------------------------------------------------------------------]]
farmbuyer@1 44
farmbuyer@1 45 -- Some AceGUI functions simply Won't Work in this context. Name them
farmbuyer@1 46 -- here, and code calling them will get a somewhat informative error().
farmbuyer@1 47 local oopsfuncs = {
farmbuyer@1 48 'SetRelativeWidth', 'SetRelativeHeight',
farmbuyer@1 49 'SetFullWidth', 'SetFullHeight',
farmbuyer@1 50 }
farmbuyer@1 51 local err = "Oops! The AceGUI function you tried to call (%s) does not "
farmbuyer@1 52 .. "make sense with lib-st and has not been implemented."
farmbuyer@1 53
farmbuyer@1 54 local function Oops(self)
farmbuyer@1 55 -- if you ever wanted an example of "brown paper bag" code, here it is
farmbuyer@1 56 local ds = debugstack(0)
farmbuyer@1 57 local func = ds:match("AceGUIWidget%-lib%-st%.lua:%d+:%s+in function `(%a+)'")
farmbuyer@1 58 error(err:format(func or "?"))
farmbuyer@1 59 end
farmbuyer@1 60
farmbuyer@1 61
farmbuyer@1 62 --[[
farmbuyer@1 63 Users with an ST already constructed can drop it into a widget directly
farmbuyer@1 64 using this routine. It must be safe to call this more than once with
farmbuyer@1 65 new widgets on the same ST.
farmbuyer@1 66
farmbuyer@1 67 This is where most of the intelligence of the wrapper is located. That
farmbuyer@1 68 is, if you can call my code "intelligent" with a straight face. Lemme
farmbuyer@1 69 try again.
farmbuyer@1 70
farmbuyer@1 71 Think of the widget wrapper as a brain. When ALL THREE neurons manage
farmbuyer@1 72 to fire at the same time and produce a thought, this function represents
farmbuyer@1 73 the thought. Sigh.
farmbuyer@1 74 ]]
farmbuyer@1 75 local ShiftingSetPoint, ShiftingSetAllPoints
farmbuyer@1 76 local function WrapST (self, st)
farmbuyer@1 77 if not st.frame then
farmbuyer@1 78 error"lib-st instance has no '.frame' field... wtf did you pass to this function?"
farmbuyer@1 79 end
farmbuyer@49 80 --if st.frame.obj and (st.frame.obj ~= self) then
farmbuyer@49 81 -- error"lib-st instance already has an '.obj' field from a different widget, cannot use with AceGUI!"
farmbuyer@49 82 --end
farmbuyer@1 83 self.st = st
farmbuyer@1 84 if not st.head then
farmbuyer@49 85 error"lib-st instance has no '.head' field, must use either ScrollingTable:CreateST or this widget's CreateST first"
farmbuyer@1 86 end
farmbuyer@1 87 self.frame = st.frame -- gutsy, but looks doable
farmbuyer@1 88
farmbuyer@1 89 -- Possibly have already wrapped this ST in a previous widget, careful.
farmbuyer@49 90 --if st.frame.obj ~= self then
farmbuyer@47 91 self.frame.customSetPoint = rawget(self.frame,"SetPoint")
farmbuyer@1 92 self.frame.realSetPoint = self.frame.SetPoint
farmbuyer@1 93 self.frame.SetPoint = ShiftingSetPoint
farmbuyer@1 94 self.frame.SetAllPoints = ShiftingSetAllPoints
farmbuyer@49 95 --end
farmbuyer@1 96
farmbuyer@47 97 -- This needs the .frame field. This also unconditionally creates .obj
farmbuyer@47 98 -- inside that field and calls a SetScript on it as well.
farmbuyer@1 99 return AceGUI:RegisterAsWidget(self)
farmbuyer@1 100 end
farmbuyer@1 101
farmbuyer@1 102
farmbuyer@1 103 --[[-----------------------------------------------------------------------------
farmbuyer@1 104 Scripts
farmbuyer@1 105 -------------------------------------------------------------------------------]]
farmbuyer@1 106 --[[
farmbuyer@1 107 All of an ST's subframes are attached to its main frame, which we have in
farmbuyer@1 108 the st.frame link, and that's what AceGUI uses for all positioning. Except
farmbuyer@1 109 that ST:SetDisplayCols creates its "head" row /above/ the main frame, and
farmbuyer@1 110 so the row of labels eats into whatever upper border space AceGUI calculates,
farmbuyer@1 111 often overlapping other elements.
farmbuyer@1 112
farmbuyer@1 113 We get around this by replacing ST's main frame's SetPoint with a custom
farmbuyer@1 114 version that just moves everything down a few pixels to allow room for the
farmbuyer@1 115 head row.
farmbuyer@1 116
farmbuyer@1 117 FIXME this may need to be a secure hook (ugh, would end up calling the real
farmbuyer@1 118 setpoint twice) rather than a replacement.
farmbuyer@1 119 ]]
farmbuyer@1 120 local DEFAULT_OFFSET = 7
farmbuyer@1 121 function ShiftingSetPoint(frame,anchor,other,otheranchor,xoff,yoff)
farmbuyer@1 122 local ho,to = frame.obj.head_offset, frame.obj.tail_offset
farmbuyer@1 123 yoff = yoff or 0
farmbuyer@1 124 if anchor:sub(1,3) == "TOP" then
farmbuyer@1 125 yoff = yoff - ho
farmbuyer@1 126 elseif anchor:sub(1,6) == "BOTTOM" then
farmbuyer@1 127 yoff = yoff + to
farmbuyer@1 128 end
farmbuyer@1 129 return frame.realSetPoint(frame,anchor,other,otheranchor,xoff,yoff)
farmbuyer@1 130 end
farmbuyer@1 131 function ShiftingSetAllPoints(frame,other)
farmbuyer@1 132 ShiftingSetPoint(frame,"TOPLEFT",other,"TOPLEFT",0,0)
farmbuyer@1 133 ShiftingSetPoint(frame,"BOTTOMRIGHT",other,"BOTTOMRIGHT",0,0)
farmbuyer@1 134 end
farmbuyer@1 135
farmbuyer@1 136
farmbuyer@1 137 --[[-----------------------------------------------------------------------------
farmbuyer@1 138 Methods
farmbuyer@1 139 -------------------------------------------------------------------------------]]
farmbuyer@1 140 local methods = {
farmbuyer@1 141 -- --------------------------------------------------------------
farmbuyer@1 142 -- These are expected by AceGUI containers (and AceGUI users)
farmbuyer@1 143 --
farmbuyer@1 144 ["OnAcquire"] = function (self)
farmbuyer@1 145 -- Almost nothing can usefully be done here.
farmbuyer@1 146 self.head_offset = DEFAULT_OFFSET
farmbuyer@1 147 self.tail_offset = DEFAULT_OFFSET
farmbuyer@1 148 end,
farmbuyer@1 149
farmbuyer@1 150 ["OnRelease"] = function (self)
farmbuyer@1 151 if self.st then
farmbuyer@1 152 self.st.frame:ClearAllPoints()
farmbuyer@1 153 self.st:Hide()
farmbuyer@1 154 end
farmbuyer@1 155 self.st = nil
farmbuyer@47 156 self.frame.realSetPoint = nil
farmbuyer@47 157 self.frame.SetAllPoints = nil
farmbuyer@47 158 self.frame.SetPoint = self.frame.customSetPoint
farmbuyer@47 159 self.frame.customSetPoint = nil
farmbuyer@1 160 end,
farmbuyer@1 161
farmbuyer@1 162 --[[
farmbuyer@1 163 STs don't use a "normal" SetWidth, if we define "normal" to be the
farmbuyer@1 164 behavior of the blizzard :SetWidth. Column width is passed in during
farmbuyer@1 165 creation of the whole ST. The SetWidth defined by an ST takes no
farmbuyer@1 166 arguments; "ReCalculateWidth" would be a more precise description of
farmbuyer@1 167 what it does.
farmbuyer@1 168
farmbuyer@1 169 Parts of AceGUI look for a .width field because a widget's SetWidth
farmbuyer@1 170 sets such. ST calculates a total width and dispatches it to its member
farmbuyer@1 171 frame... but doesn't store a local copy. We need to bridge these
farmbuyer@1 172 differences.
farmbuyer@1 173
farmbuyer@1 174 This widget wrapper does not make use of On{Width,Height}Set hooks,
farmbuyer@1 175 but the acegui widget base functions do. Since we're not inheriting
farmbuyer@1 176 them, we may as well supply them.
farmbuyer@1 177 ]]
farmbuyer@1 178 ["SetWidth"] = function (self)
farmbuyer@1 179 self.st:SetWidth() -- re-total the columns
farmbuyer@1 180 local w = self.st.frame:GetWidth() -- fetch the answer back
farmbuyer@1 181 self.frame.width = w -- store it for acegui
farmbuyer@1 182 if self.OnWidthSet then
farmbuyer@1 183 self:OnWidthSet(w)
farmbuyer@1 184 end
farmbuyer@1 185 end,
farmbuyer@1 186
farmbuyer@1 187 -- Everything said about SetWidth applies here too.
farmbuyer@1 188 ["SetHeight"] = function (self)
farmbuyer@1 189 self.st:SetHeight()
farmbuyer@1 190 local h = self.st.frame:GetHeight()
farmbuyer@1 191 self.frame.height = h
farmbuyer@1 192 if self.OnHeightSet then
farmbuyer@1 193 self:OnHeightSet(h)
farmbuyer@1 194 end
farmbuyer@1 195 end,
farmbuyer@1 196
farmbuyer@1 197 -- Some of the container layouts call Show/Hide on the innermost frame
farmbuyer@1 198 -- directly. We need to make sure the slightly-higher-level routine is
farmbuyer@1 199 -- also called.
farmbuyer@1 200 ["LayoutFinished"] = function (self)
farmbuyer@1 201 if self.frame:IsShown() then
farmbuyer@1 202 self.st:Show()
farmbuyer@1 203 else
farmbuyer@1 204 self.st:Hide()
farmbuyer@1 205 end
farmbuyer@1 206 end,
farmbuyer@1 207
farmbuyer@1 208 -- --------------------------------------------------------------
farmbuyer@1 209 -- Functions specific to this widget
farmbuyer@1 210 --
farmbuyer@1 211
farmbuyer@1 212 ["GetSTLibrary"] = function (self) -- Purely for convenience
farmbuyer@1 213 return LibST
farmbuyer@1 214 end,
farmbuyer@1 215
farmbuyer@1 216 --[[
farmbuyer@1 217 Replacement wrapper, so that instead of
farmbuyer@1 218 st = ScrollingTable:CreateST( args )
farmbuyer@1 219 the user should be able to do
farmbuyer@1 220 st = AceGUI:Create("lib-st"):CreateST( args )
farmbuyer@1 221 instead, without needing to get a lib-st handle.
farmbuyer@1 222 ]]
farmbuyer@1 223 ["CreateST"] = function (self, ...)
farmbuyer@1 224 return self:WrapST( LibST:CreateST(...) )
farmbuyer@1 225 end,
farmbuyer@1 226
farmbuyer@1 227 ["WrapST"] = WrapST,
farmbuyer@1 228 }
farmbuyer@1 229
farmbuyer@1 230
farmbuyer@1 231 --[[-----------------------------------------------------------------------------
farmbuyer@1 232 Constructor
farmbuyer@1 233 -------------------------------------------------------------------------------]]
farmbuyer@1 234 local function Constructor()
farmbuyer@1 235 -- .frame not done here, see WrapST
farmbuyer@1 236 local widget = {
farmbuyer@1 237 type = Type
farmbuyer@1 238 }
farmbuyer@1 239 for method, func in pairs(methods) do
farmbuyer@1 240 widget[method] = func
farmbuyer@1 241 end
farmbuyer@1 242
farmbuyer@1 243 for _,func in ipairs(oopsfuncs) do
farmbuyer@1 244 widget[func] = Oops
farmbuyer@1 245 end
farmbuyer@1 246
farmbuyer@1 247 -- AceGUI:RegisterAsWidget needs .frame
farmbuyer@1 248 return widget
farmbuyer@1 249 end
farmbuyer@1 250
farmbuyer@1 251 AceGUI:RegisterWidgetType(Type,Constructor,Version)
farmbuyer@1 252