annotate AceGUIWidget-lib-st.lua @ 47:1070a14cfee4

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