annotate LibFarmbuyer.lua @ 69:8442272a8418

- Make sure popup dialogs are on top of Ace3's widgets. - Minor code reorganization. Safety hook for future boss-entry code. - Avoid same bug from a couple revs ago when adding manual boss kills. - Ask players about snapshot data when manually entering boss kills. - Blizzard rearranged the button order in 3-entry popups some time ago and I failed to adapt the code until now.
author Farmbuyer of US-Kilrogg <farmbuyer@gmail.com>
date Fri, 11 May 2012 03:08:12 +0000
parents 81d5449621f8
children 32eb24fb2ebf
rev   line source
farmbuyer@1 1 --[[
farmbuyer@1 2 Not really meant for public use. Stuff that I keep using everywhere and
farmbuyer@1 3 got tired of reimplementing, or even copy-and-pasting. The notes here are
farmbuyer@1 4 reminders to myself.
farmbuyer@1 5
farmbuyer@1 6 Library contents:
farmbuyer@1 7 - author_debug
farmbuyer@1 8 Evaluates to true if I'm hacking on something.
farmbuyer@1 9
farmbuyer@19 10 - tableprint(t[,f])
farmbuyer@1 11 A single print() call to the contents of T, including nils; strings are
farmbuyer@19 12 cleaned up with respect to embedded '|'/control chars. If a function F is
farmbuyer@45 13 passed, calls that instead of print(). Returns the accumulated string and
farmbuyer@45 14 either T or the returned values of F, depending on which was used.
farmbuyer@1 15
farmbuyer@1 16 - safeprint(...)
farmbuyer@19 17 Same as tableprint() on the argument list. Returns the results of tableprint.
farmbuyer@45 18 Generates some garbage.
farmbuyer@1 19
farmbuyer@1 20 - safeiprint(...)
farmbuyer@19 21 Same as safeprint() but with <index> numbers inserted. Returns the results
farmbuyer@45 22 of tableprint. Generates some garbage.
farmbuyer@19 23 Ex: safeiprint(a,b,c) --> <1>,a,<2>,b,<3>,c
farmbuyer@1 24
farmbuyer@45 25 - safefprint/safefiprint(f,...)
farmbuyer@45 26 Takes a function F as first parameter, for passing to tableprint().
farmbuyer@45 27
farmbuyer@1 28 - t = StaticPopup(t)
farmbuyer@1 29 Fills out "typical" settings inside T, especially if T contains any kind
farmbuyer@1 30 of editbox:
farmbuyer@1 31 + cannot accept an empty editbox
farmbuyer@39 32 + pressing Enter runs OnAccept (also will not accept empty editbox)
farmbuyer@1 33 + editbox grabs keyboard focus
farmbuyer@1 34 + OnAccept runs with editbox's text in dialog.usertext
farmbuyer@1 35 Returns T.
farmbuyer@1 36
farmbuyer@1 37 - nullfunc()
farmbuyer@1 38 Empty placeholder function. Will be less useful if WoW ever moves to Lua 5.2.
farmbuyer@1 39 This is a fascinating and educational place to insert print calls...
farmbuyer@1 40
farmbuyer@1 41 - tabledump(t)/dumptable(t)
farmbuyer@1 42 If author_debug, this runs the builtin /dump command on T. Otherwise nothing.
farmbuyer@1 43
farmbuyer@1 44 - DoOnceNextUpdate(f)
farmbuyer@1 45 Runs F on the next frame refresh cycle. Multiple calls in one cycle will
farmbuyer@1 46 stack LIFO. Calls *while* processing the stack are safe, and will be stacked
farmbuyer@1 47 up for the next cycle.
farmbuyer@6 48
farmbuyer@6 49 - safecall (func, ...)
farmbuyer@6 50 A modified copy of the xpcall wrapper duplicated in every Ace3 file in the
farmbuyer@6 51 whole damn library.
farmbuyer@6 52
farmbuyer@6 53 - new(...), del(t), copy(t), clear()
farmbuyer@6 54 Ditto for table recycling.
farmbuyer@1 55 ]]
farmbuyer@1 56
farmbuyer@69 57 local MAJOR, MINOR = "LibFarmbuyer", 17
farmbuyer@1 58 assert(LibStub,MAJOR.." requires LibStub")
farmbuyer@1 59 local lib = LibStub:NewLibrary(MAJOR, MINOR)
farmbuyer@1 60 if not lib then return end
farmbuyer@1 61
farmbuyer@1 62 _G[MAJOR] = lib
farmbuyer@1 63
farmbuyer@1 64 ----------------------------------------------------------------------
farmbuyer@6 65 --[[
farmbuyer@6 66 Recycling functions yoinked from AceConfigDialog and tweaked
farmbuyer@6 67 ]]
farmbuyer@1 68 local new, del, copy, clear
farmbuyer@6 69 do
farmbuyer@6 70 local pool = setmetatable({},{__mode="k"})
farmbuyer@6 71 function clear()
farmbuyer@6 72 wipe(pool)
farmbuyer@6 73 end
farmbuyer@6 74 function new(...) -- slightly modified variant, takes optional initializers
farmbuyer@6 75 local t = next(pool)
farmbuyer@6 76 if t then
farmbuyer@6 77 pool[t] = nil
farmbuyer@6 78 for i = 1, select('#',...) do
farmbuyer@6 79 t[i] = select(i,...)
farmbuyer@6 80 end
farmbuyer@6 81 return t
farmbuyer@6 82 else
farmbuyer@6 83 return {...}
farmbuyer@6 84 end
farmbuyer@6 85 end
farmbuyer@6 86 function copy(t)
farmbuyer@6 87 local c = new()
farmbuyer@6 88 for k, v in pairs(t) do
farmbuyer@6 89 c[k] = v
farmbuyer@6 90 end
farmbuyer@6 91 return c
farmbuyer@6 92 end
farmbuyer@6 93 function del(t)
farmbuyer@6 94 wipe(t)
farmbuyer@6 95 pool[t] = true
farmbuyer@6 96 end
farmbuyer@6 97 end
farmbuyer@6 98 lib.new, lib.del, lib.copy, lib.clear = new, del, copy, clear
farmbuyer@1 99
farmbuyer@1 100
farmbuyer@1 101 ----------------------------------------------------------------------
farmbuyer@1 102 --[[
farmbuyer@1 103 safeprint
farmbuyer@1 104 ]]
farmbuyer@56 105 local tconcat, tostring, tonumber = table.concat, tostring, tonumber
farmbuyer@1 106 local function undocontrol(c)
farmbuyer@1 107 return ("\\%.3d"):format(c:byte())
farmbuyer@1 108 end
farmbuyer@1 109 function lib.safeprint(...)
farmbuyer@1 110 local args = { n=select('#',...), ... }
farmbuyer@19 111 return lib.tableprint(args)
farmbuyer@1 112 end
farmbuyer@45 113 function lib.safefprint(f,...)
farmbuyer@45 114 local args = { n=select('#',...), ... }
farmbuyer@45 115 return lib.tableprint(args,f)
farmbuyer@45 116 end
farmbuyer@1 117 function lib.safeiprint(...)
farmbuyer@1 118 local args = { n=select('#',...), ... }
farmbuyer@1 119 local last = args.n
farmbuyer@1 120 while last > 0 do
farmbuyer@1 121 table.insert (args, last, "<"..last..">")
farmbuyer@1 122 last = last - 1
farmbuyer@1 123 end
farmbuyer@1 124 args.n = 2 * args.n
farmbuyer@19 125 return lib.tableprint(args)
farmbuyer@1 126 end
farmbuyer@45 127 function lib.safefiprint(f,...)
farmbuyer@45 128 local args = { n=select('#',...), ... }
farmbuyer@45 129 local last = args.n
farmbuyer@45 130 while last > 0 do
farmbuyer@45 131 table.insert (args, last, "<"..last..">")
farmbuyer@45 132 last = last - 1
farmbuyer@45 133 end
farmbuyer@45 134 args.n = 2 * args.n
farmbuyer@45 135 return lib.tableprint(args,f)
farmbuyer@45 136 end
farmbuyer@19 137 function lib.tableprint(t,f)
farmbuyer@1 138 for i = 1, (tonumber(t.n) or #t) do
farmbuyer@1 139 t[i] = tostring(t[i]):gsub('\124','\124\124')
farmbuyer@1 140 :gsub('(%c)', undocontrol)
farmbuyer@1 141 end
farmbuyer@56 142 local msg = tconcat(t,' ', 1, tonumber(t.n) or #t)
farmbuyer@45 143 if type(f) == 'function' then
farmbuyer@45 144 return msg,f(msg)
farmbuyer@1 145 else
farmbuyer@19 146 print(msg)
farmbuyer@19 147 return msg,t
farmbuyer@1 148 end
farmbuyer@1 149 end
farmbuyer@1 150
farmbuyer@1 151 -- See below for global versions.
farmbuyer@1 152
farmbuyer@1 153
farmbuyer@1 154 ----------------------------------------------------------------------
farmbuyer@1 155 local StaticPopupDialogs = _G.StaticPopupDialogs
farmbuyer@1 156
farmbuyer@1 157 local function EditBoxOnTextChanged_notempty (editbox) -- this is also called when first shown
farmbuyer@1 158 if editbox:GetText() ~= "" then
farmbuyer@1 159 editbox:GetParent().button1:Enable()
farmbuyer@1 160 else
farmbuyer@1 161 editbox:GetParent().button1:Disable()
farmbuyer@1 162 end
farmbuyer@1 163 end
farmbuyer@1 164 local function EditBoxOnEnterPressed_accept (editbox)
farmbuyer@39 165 if editbox:GetText() == "" then return end
farmbuyer@39 166 local dialog = editbox:GetParent()
farmbuyer@39 167 StaticPopupDialogs[dialog.which].OnAccept (dialog, dialog.data, dialog.data2)
farmbuyer@39 168 dialog:Hide()
farmbuyer@1 169 end
farmbuyer@69 170 local function OnShow_ontop (dialog, data)
farmbuyer@1 171 local info = StaticPopupDialogs[dialog.which]
farmbuyer@69 172 -- ace3's elements are hardcoded to this strata, make sure popups
farmbuyer@69 173 -- can also be seen (their toplevel=true attribute handles the
farmbuyer@69 174 -- framelevels within the same strata)
farmbuyer@69 175 info.saved_strata = dialog:GetFrameStrata()
farmbuyer@69 176 dialog:SetFrameStrata("FULLSCREEN_DIALOG")
farmbuyer@69 177 if info.hasEditBox then
farmbuyer@69 178 dialog.editBox:SetFocus()
farmbuyer@69 179 end
farmbuyer@1 180 if info.farm_OnShow then
farmbuyer@1 181 return info.farm_OnShow (dialog, data)
farmbuyer@1 182 end
farmbuyer@1 183 end
farmbuyer@1 184 local function OnAccept_witheditbox (dialog, data, data2)
farmbuyer@1 185 local info = StaticPopupDialogs[dialog.which]
farmbuyer@16 186 --dialog.usertext = dialog[info.hasWideEditBox and "wideEditBox" or "editBox"]:GetText():trim()
farmbuyer@16 187 dialog.usertext = dialog.editBox:GetText():trim()
farmbuyer@1 188 if info.farm_OnAccept then
farmbuyer@1 189 return info.farm_OnAccept (dialog, data, data2)
farmbuyer@1 190 end
farmbuyer@1 191 end
farmbuyer@69 192 local function OnHide_cleanup (dialog, data)
farmbuyer@69 193 local info = StaticPopupDialogs[dialog.which]
farmbuyer@69 194 if info.farm_OnHide then
farmbuyer@69 195 return info.farm_OnHide (dialog, data)
farmbuyer@69 196 end
farmbuyer@16 197 dialog.data = nil
farmbuyer@16 198 dialog.data2 = nil
farmbuyer@69 199 dialog:SetFrameStrata(info.saved_strata or "DIALOG")
farmbuyer@16 200 end
farmbuyer@1 201
farmbuyer@1 202 --[[
farmbuyer@1 203 StaticPopup
farmbuyer@1 204 ]]
farmbuyer@1 205 function lib.StaticPopup (t)
farmbuyer@57 206 if t.hasEditBox then
farmbuyer@57 207 t.EditBoxOnTextChanged = EditBoxOnTextChanged_notempty
farmbuyer@57 208 t.EditBoxOnEnterPressed = EditBoxOnEnterPressed_accept
farmbuyer@1 209 if t.OnAccept then
farmbuyer@1 210 t.farm_OnAccept = t.OnAccept
farmbuyer@1 211 end
farmbuyer@57 212 t.OnAccept = OnAccept_witheditbox
farmbuyer@1 213 -- this calls OnCancel with "clicked", unless noCancelOnEscape is set
farmbuyer@57 214 t.EditBoxOnEscapePressed = StaticPopup_EscapePressed
farmbuyer@57 215 end
farmbuyer@1 216
farmbuyer@69 217 t.farm_OnShow = t.OnShow
farmbuyer@69 218 t.OnShow = OnShow_ontop
farmbuyer@69 219 t.farm_OnHide = t.OnHide
farmbuyer@69 220 t.OnHide = OnHide_cleanup
farmbuyer@16 221
farmbuyer@57 222 t.timeout = 0
farmbuyer@57 223 t.whileDead = true
farmbuyer@57 224 t.hideOnEscape = true
farmbuyer@1 225 t.enterClicksFirstButton = true
farmbuyer@53 226 t.preferredIndex = 3 -- http://forums.wowace.com/showthread.php?t=19960
farmbuyer@1 227
farmbuyer@57 228 return t
farmbuyer@1 229 end
farmbuyer@1 230
farmbuyer@1 231
farmbuyer@1 232 ----------------------------------------------------------------------
farmbuyer@1 233 --[[
farmbuyer@1 234 This is ugly, but at least it all gets GC'd almost immediately.
farmbuyer@1 235 ]]
farmbuyer@1 236 function lib.nullfunc() end
farmbuyer@1 237
farmbuyer@1 238 if ({
farmbuyer@1 239 ["Bandwagon"] = true, ["Kilvin"] = true, ["Waterfaucet"] = true,
farmbuyer@1 240 ["Farmbuyer"] = true, ["Oxdeadbeef"] = true, ["Pointystick"] = true,
farmbuyer@1 241 ["Angryhobbit"] = true, ["Malrubius"] = true, ["Hemogoblin"] = true,
farmbuyer@16 242 ["Ossipago"] = true,
farmbuyer@1 243 })[UnitName("player")] then
farmbuyer@1 244 lib.author_debug = true
farmbuyer@1 245 _G.safeprint = lib.safeprint
farmbuyer@1 246 _G.safeiprint = lib.safeiprint
farmbuyer@1 247 function lib.tabledump(t)
farmbuyer@1 248 _G.UIParentLoadAddOn("Blizzard_DebugTools")
farmbuyer@1 249 _G.LibF_DEBUG = t
farmbuyer@1 250 _G.SlashCmdList.DUMP("LibF_DEBUG")
farmbuyer@1 251 end
farmbuyer@1 252 else
farmbuyer@1 253 lib.tabledump = lib.nullfunc
farmbuyer@1 254 end
farmbuyer@1 255 lib.dumptable = lib.tabledump
farmbuyer@1 256
farmbuyer@1 257
farmbuyer@1 258 ----------------------------------------------------------------------
farmbuyer@1 259 --[[
farmbuyer@1 260 DoOnceNextUpdate
farmbuyer@1 261 ]]
farmbuyer@1 262 do
farmbuyer@1 263 local frame = CreateFrame("Frame", "LibFarmbuyerDONUFrame")
farmbuyer@1 264 frame:Hide()
farmbuyer@1 265 frame:SetScript("OnUpdate", function()
farmbuyer@1 266 frame:Hide()
farmbuyer@1 267 local q = frame.nexttime
farmbuyer@1 268 local tmp
farmbuyer@1 269 frame.nexttime = nil
farmbuyer@1 270 while q do
farmbuyer@1 271 tmp = q
farmbuyer@1 272 q.f(frame)
farmbuyer@1 273 q = q.n
farmbuyer@1 274 del(tmp)
farmbuyer@1 275 end
farmbuyer@1 276 end)
farmbuyer@1 277
farmbuyer@1 278 function lib.DoOnceNextUpdate (func)
farmbuyer@1 279 local nextt = new()
farmbuyer@1 280 nextt.f = func
farmbuyer@1 281 nextt.n = frame.nexttime
farmbuyer@1 282 frame.nexttime = nextt
farmbuyer@1 283 frame:Show()
farmbuyer@1 284 end
farmbuyer@1 285 end
farmbuyer@1 286
farmbuyer@1 287
farmbuyer@1 288 ----------------------------------------------------------------------
farmbuyer@6 289 --[[
farmbuyer@6 290 safecall
farmbuyer@6 291 ]]
farmbuyer@1 292 do
farmbuyer@6 293 local xpcall = xpcall
farmbuyer@6 294
farmbuyer@6 295 local function errorhandler(err)
farmbuyer@6 296 --return geterrorhandler()(err)
farmbuyer@6 297 --print("in error handler", err)
farmbuyer@6 298 return err
farmbuyer@1 299 end
farmbuyer@6 300
farmbuyer@6 301 local template = ([[
farmbuyer@6 302 local xpcall, eh = ...
farmbuyer@6 303 local method, ARGS
farmbuyer@6 304 local function call() return method(ARGS) end
farmbuyer@6 305
farmbuyer@6 306 local function dispatch (func, ...)
farmbuyer@6 307 method = func
farmbuyer@6 308 if not method then return end
farmbuyer@6 309 ARGS = ...
farmbuyer@6 310 return xpcall (call, eh)
farmbuyer@1 311 end
farmbuyer@6 312
farmbuyer@6 313 return dispatch
farmbuyer@6 314 ]]):gsub('\t',' ')
farmbuyer@6 315
farmbuyer@6 316 local function CreateDispatcher(argCount)
farmbuyer@6 317 local ARGS = {}
farmbuyer@6 318 for i = 1, argCount do ARGS[i] = "arg"..i end
farmbuyer@19 319 local code = template:gsub("ARGS", tconcat(ARGS, ", "))
farmbuyer@6 320 return assert(loadstring(code, "LibF/safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
farmbuyer@1 321 end
farmbuyer@6 322
farmbuyer@6 323 local Dispatchers = setmetatable({
farmbuyer@6 324 [0] = function(func)
farmbuyer@6 325 return xpcall (func, errorhandler)
farmbuyer@1 326 end
farmbuyer@6 327 }, {
farmbuyer@6 328 __index = function (Ds, argCount)
farmbuyer@6 329 local dispatcher = CreateDispatcher(argCount)
farmbuyer@6 330 Ds[argCount] = dispatcher
farmbuyer@6 331 return dispatcher
farmbuyer@6 332 end
farmbuyer@6 333 })
farmbuyer@6 334
farmbuyer@6 335 function lib.safecall (func, ...)
farmbuyer@6 336 if type(func) == 'function' then
farmbuyer@6 337 return Dispatchers[select('#', ...)](func, ...)
farmbuyer@6 338 end
farmbuyer@1 339 end
farmbuyer@1 340 end
farmbuyer@1 341
farmbuyer@6 342
farmbuyer@6 343 ----------------------------------------------------------------------
farmbuyer@6 344
farmbuyer@1 345 -- vim: noet