annotate AceGUIWidget-lib-st.lua @ 138:8345df517488 2.20.2

- Redo instance tagging for new GetInstanceInfo return values. Normal raids should no longer "randomly" detect as heroic mode. - If loaded during combat, do not prescan history. - Fix nil error caused by reassigning loot inside an instance after having been loaded during combat. - "Peppers!" sound test.
author Farmbuyer of US-Kilrogg <farmbuyer@gmail.com>
date Fri, 19 Oct 2012 14:34:34 -0400
parents 9232cacc9136
children
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@126 29 local Type, Version = "lib-st", 5
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@1 80 self.st = st
farmbuyer@1 81 if not st.head then
farmbuyer@49 82 error"lib-st instance has no '.head' field, must use either ScrollingTable:CreateST or this widget's CreateST first"
farmbuyer@1 83 end
farmbuyer@1 84 self.frame = st.frame -- gutsy, but looks doable
farmbuyer@1 85
farmbuyer@1 86 -- Possibly have already wrapped this ST in a previous widget, careful.
farmbuyer@126 87 self.frame.customSetPoint = rawget(self.frame,"SetPoint")
farmbuyer@126 88 self.frame.realSetPoint = self.frame.SetPoint
farmbuyer@126 89 self.frame.SetPoint = ShiftingSetPoint
farmbuyer@126 90 self.frame.SetAllPoints = ShiftingSetAllPoints
farmbuyer@1 91
farmbuyer@47 92 -- This needs the .frame field. This also unconditionally creates .obj
farmbuyer@47 93 -- inside that field and calls a SetScript on it as well.
farmbuyer@1 94 return AceGUI:RegisterAsWidget(self)
farmbuyer@1 95 end
farmbuyer@1 96
farmbuyer@1 97
farmbuyer@1 98 --[[-----------------------------------------------------------------------------
farmbuyer@1 99 Scripts
farmbuyer@1 100 -------------------------------------------------------------------------------]]
farmbuyer@1 101 --[[
farmbuyer@1 102 All of an ST's subframes are attached to its main frame, which we have in
farmbuyer@1 103 the st.frame link, and that's what AceGUI uses for all positioning. Except
farmbuyer@1 104 that ST:SetDisplayCols creates its "head" row /above/ the main frame, and
farmbuyer@1 105 so the row of labels eats into whatever upper border space AceGUI calculates,
farmbuyer@1 106 often overlapping other elements.
farmbuyer@1 107
farmbuyer@1 108 We get around this by replacing ST's main frame's SetPoint with a custom
farmbuyer@1 109 version that just moves everything down a few pixels to allow room for the
farmbuyer@1 110 head row.
farmbuyer@1 111
farmbuyer@1 112 FIXME this may need to be a secure hook (ugh, would end up calling the real
farmbuyer@1 113 setpoint twice) rather than a replacement.
farmbuyer@1 114 ]]
farmbuyer@1 115 local DEFAULT_OFFSET = 7
farmbuyer@1 116 function ShiftingSetPoint(frame,anchor,other,otheranchor,xoff,yoff)
farmbuyer@1 117 local ho,to = frame.obj.head_offset, frame.obj.tail_offset
farmbuyer@1 118 yoff = yoff or 0
farmbuyer@1 119 if anchor:sub(1,3) == "TOP" then
farmbuyer@1 120 yoff = yoff - ho
farmbuyer@1 121 elseif anchor:sub(1,6) == "BOTTOM" then
farmbuyer@1 122 yoff = yoff + to
farmbuyer@1 123 end
farmbuyer@1 124 return frame.realSetPoint(frame,anchor,other,otheranchor,xoff,yoff)
farmbuyer@1 125 end
farmbuyer@1 126 function ShiftingSetAllPoints(frame,other)
farmbuyer@1 127 ShiftingSetPoint(frame,"TOPLEFT",other,"TOPLEFT",0,0)
farmbuyer@1 128 ShiftingSetPoint(frame,"BOTTOMRIGHT",other,"BOTTOMRIGHT",0,0)
farmbuyer@1 129 end
farmbuyer@1 130
farmbuyer@1 131
farmbuyer@1 132 --[[-----------------------------------------------------------------------------
farmbuyer@1 133 Methods
farmbuyer@1 134 -------------------------------------------------------------------------------]]
farmbuyer@1 135 local methods = {
farmbuyer@1 136 -- --------------------------------------------------------------
farmbuyer@1 137 -- These are expected by AceGUI containers (and AceGUI users)
farmbuyer@1 138 --
farmbuyer@1 139 ["OnAcquire"] = function (self)
farmbuyer@1 140 -- Almost nothing can usefully be done here.
farmbuyer@1 141 self.head_offset = DEFAULT_OFFSET
farmbuyer@1 142 self.tail_offset = DEFAULT_OFFSET
farmbuyer@1 143 end,
farmbuyer@1 144
farmbuyer@1 145 ["OnRelease"] = function (self)
farmbuyer@1 146 if self.st then
farmbuyer@1 147 self.st.frame:ClearAllPoints()
farmbuyer@1 148 self.st:Hide()
farmbuyer@1 149 end
farmbuyer@1 150 self.st = nil
farmbuyer@47 151 self.frame.realSetPoint = nil
farmbuyer@47 152 self.frame.SetAllPoints = nil
farmbuyer@47 153 self.frame.SetPoint = self.frame.customSetPoint
farmbuyer@47 154 self.frame.customSetPoint = nil
farmbuyer@1 155 end,
farmbuyer@1 156
farmbuyer@1 157 --[[
farmbuyer@1 158 STs don't use a "normal" SetWidth, if we define "normal" to be the
farmbuyer@1 159 behavior of the blizzard :SetWidth. Column width is passed in during
farmbuyer@1 160 creation of the whole ST. The SetWidth defined by an ST takes no
farmbuyer@1 161 arguments; "ReCalculateWidth" would be a more precise description of
farmbuyer@1 162 what it does.
farmbuyer@1 163
farmbuyer@1 164 Parts of AceGUI look for a .width field because a widget's SetWidth
farmbuyer@1 165 sets such. ST calculates a total width and dispatches it to its member
farmbuyer@1 166 frame... but doesn't store a local copy. We need to bridge these
farmbuyer@1 167 differences.
farmbuyer@1 168
farmbuyer@1 169 This widget wrapper does not make use of On{Width,Height}Set hooks,
farmbuyer@1 170 but the acegui widget base functions do. Since we're not inheriting
farmbuyer@1 171 them, we may as well supply them.
farmbuyer@1 172 ]]
farmbuyer@1 173 ["SetWidth"] = function (self)
farmbuyer@1 174 self.st:SetWidth() -- re-total the columns
farmbuyer@1 175 local w = self.st.frame:GetWidth() -- fetch the answer back
farmbuyer@1 176 self.frame.width = w -- store it for acegui
farmbuyer@1 177 if self.OnWidthSet then
farmbuyer@1 178 self:OnWidthSet(w)
farmbuyer@1 179 end
farmbuyer@1 180 end,
farmbuyer@1 181
farmbuyer@1 182 -- Everything said about SetWidth applies here too.
farmbuyer@1 183 ["SetHeight"] = function (self)
farmbuyer@1 184 self.st:SetHeight()
farmbuyer@1 185 local h = self.st.frame:GetHeight()
farmbuyer@1 186 self.frame.height = h
farmbuyer@1 187 if self.OnHeightSet then
farmbuyer@1 188 self:OnHeightSet(h)
farmbuyer@1 189 end
farmbuyer@1 190 end,
farmbuyer@1 191
farmbuyer@1 192 -- Some of the container layouts call Show/Hide on the innermost frame
farmbuyer@1 193 -- directly. We need to make sure the slightly-higher-level routine is
farmbuyer@1 194 -- also called.
farmbuyer@1 195 ["LayoutFinished"] = function (self)
farmbuyer@1 196 if self.frame:IsShown() then
farmbuyer@1 197 self.st:Show()
farmbuyer@1 198 else
farmbuyer@1 199 self.st:Hide()
farmbuyer@1 200 end
farmbuyer@1 201 end,
farmbuyer@1 202
farmbuyer@1 203 -- --------------------------------------------------------------
farmbuyer@1 204 -- Functions specific to this widget
farmbuyer@1 205 --
farmbuyer@1 206
farmbuyer@1 207 ["GetSTLibrary"] = function (self) -- Purely for convenience
farmbuyer@1 208 return LibST
farmbuyer@1 209 end,
farmbuyer@1 210
farmbuyer@1 211 --[[
farmbuyer@1 212 Replacement wrapper, so that instead of
farmbuyer@1 213 st = ScrollingTable:CreateST( args )
farmbuyer@1 214 the user should be able to do
farmbuyer@1 215 st = AceGUI:Create("lib-st"):CreateST( args )
farmbuyer@1 216 instead, without needing to get a lib-st handle.
farmbuyer@1 217 ]]
farmbuyer@1 218 ["CreateST"] = function (self, ...)
farmbuyer@1 219 return self:WrapST( LibST:CreateST(...) )
farmbuyer@1 220 end,
farmbuyer@1 221
farmbuyer@1 222 ["WrapST"] = WrapST,
farmbuyer@1 223 }
farmbuyer@1 224
farmbuyer@1 225
farmbuyer@1 226 --[[-----------------------------------------------------------------------------
farmbuyer@1 227 Constructor
farmbuyer@1 228 -------------------------------------------------------------------------------]]
farmbuyer@1 229 local function Constructor()
farmbuyer@1 230 -- .frame not done here, see WrapST
farmbuyer@1 231 local widget = {
farmbuyer@1 232 type = Type
farmbuyer@1 233 }
farmbuyer@1 234 for method, func in pairs(methods) do
farmbuyer@1 235 widget[method] = func
farmbuyer@1 236 end
farmbuyer@1 237
farmbuyer@1 238 for _,func in ipairs(oopsfuncs) do
farmbuyer@1 239 widget[func] = Oops
farmbuyer@1 240 end
farmbuyer@1 241
farmbuyer@1 242 -- AceGUI:RegisterAsWidget needs .frame
farmbuyer@1 243 return widget
farmbuyer@1 244 end
farmbuyer@1 245
farmbuyer@1 246 AceGUI:RegisterWidgetType(Type,Constructor,Version)
farmbuyer@1 247