annotate AceGUIWidget-lib-st.lua @ 11:952c3ac0e783

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