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