farmbuyer@1: --[[ farmbuyer@1: Not really meant for public use. Stuff that I keep using everywhere and farmbuyer@1: got tired of reimplementing, or even copy-and-pasting. The notes here are farmbuyer@1: reminders to myself. farmbuyer@1: farmbuyer@1: Library contents: farmbuyer@1: - author_debug farmbuyer@1: Evaluates to true if I'm hacking on something. farmbuyer@1: farmbuyer@19: - tableprint(t[,f]) farmbuyer@1: A single print() call to the contents of T, including nils; strings are farmbuyer@73: cleaned up with respect to embedded '|'/control chars. A single space farmbuyer@73: is used during concatenation of T. If a function F is passed, calls that farmbuyer@73: instead of print(). Returns the accumulated string and either T or the farmbuyer@73: returned values of F, depending on which was used. farmbuyer@1: farmbuyer@1: - safeprint(...) farmbuyer@19: Same as tableprint() on the argument list. Returns the results of tableprint. farmbuyer@45: Generates some garbage. farmbuyer@1: farmbuyer@1: - safeiprint(...) farmbuyer@19: Same as safeprint() but with numbers inserted. Returns the results farmbuyer@45: of tableprint. Generates some garbage. farmbuyer@19: Ex: safeiprint(a,b,c) --> <1>,a,<2>,b,<3>,c farmbuyer@1: farmbuyer@45: - safefprint/safefiprint(f,...) farmbuyer@45: Takes a function F as first parameter, for passing to tableprint(). farmbuyer@45: farmbuyer@1: - t = StaticPopup(t) farmbuyer@1: Fills out "typical" settings inside T, especially if T contains any kind farmbuyer@1: of editbox: farmbuyer@1: + cannot accept an empty editbox farmbuyer@39: + pressing Enter runs OnAccept (also will not accept empty editbox) farmbuyer@1: + editbox grabs keyboard focus farmbuyer@1: + OnAccept runs with editbox's text in dialog.usertext farmbuyer@1: Returns T. farmbuyer@1: farmbuyer@1: - nullfunc() farmbuyer@1: Empty placeholder function. Will be less useful if WoW ever moves to Lua 5.2. farmbuyer@1: This is a fascinating and educational place to insert print calls... farmbuyer@1: farmbuyer@1: - tabledump(t)/dumptable(t) farmbuyer@1: If author_debug, this runs the builtin /dump command on T. Otherwise nothing. farmbuyer@1: farmbuyer@1: - DoOnceNextUpdate(f) farmbuyer@1: Runs F on the next frame refresh cycle. Multiple calls in one cycle will farmbuyer@1: stack LIFO. Calls *while* processing the stack are safe, and will be stacked farmbuyer@1: up for the next cycle. farmbuyer@6: farmbuyer@6: - safecall (func, ...) farmbuyer@6: A modified copy of the xpcall wrapper duplicated in every Ace3 file in the farmbuyer@6: whole damn library. farmbuyer@6: farmbuyer@6: - new(...), del(t), copy(t), clear() farmbuyer@6: Ditto for table recycling. farmbuyer@1: ]] farmbuyer@1: farmbuyer@92: local MAJOR, MINOR = "LibFarmbuyer", 19 farmbuyer@1: assert(LibStub,MAJOR.." requires LibStub") farmbuyer@1: local lib = LibStub:NewLibrary(MAJOR, MINOR) farmbuyer@1: if not lib then return end farmbuyer@1: farmbuyer@1: _G[MAJOR] = lib farmbuyer@1: farmbuyer@1: ---------------------------------------------------------------------- farmbuyer@6: --[[ farmbuyer@6: Recycling functions yoinked from AceConfigDialog and tweaked farmbuyer@6: ]] farmbuyer@1: local new, del, copy, clear farmbuyer@6: do farmbuyer@6: local pool = setmetatable({},{__mode="k"}) farmbuyer@6: function clear() farmbuyer@6: wipe(pool) farmbuyer@6: end farmbuyer@6: function new(...) -- slightly modified variant, takes optional initializers farmbuyer@6: local t = next(pool) farmbuyer@6: if t then farmbuyer@6: pool[t] = nil farmbuyer@6: for i = 1, select('#',...) do farmbuyer@6: t[i] = select(i,...) farmbuyer@6: end farmbuyer@6: return t farmbuyer@6: else farmbuyer@6: return {...} farmbuyer@6: end farmbuyer@6: end farmbuyer@6: function copy(t) farmbuyer@6: local c = new() farmbuyer@6: for k, v in pairs(t) do farmbuyer@6: c[k] = v farmbuyer@6: end farmbuyer@6: return c farmbuyer@6: end farmbuyer@6: function del(t) farmbuyer@6: wipe(t) farmbuyer@6: pool[t] = true farmbuyer@6: end farmbuyer@6: end farmbuyer@6: lib.new, lib.del, lib.copy, lib.clear = new, del, copy, clear farmbuyer@1: farmbuyer@1: farmbuyer@1: ---------------------------------------------------------------------- farmbuyer@1: --[[ farmbuyer@1: safeprint farmbuyer@1: ]] farmbuyer@56: local tconcat, tostring, tonumber = table.concat, tostring, tonumber farmbuyer@1: local function undocontrol(c) farmbuyer@1: return ("\\%.3d"):format(c:byte()) farmbuyer@1: end farmbuyer@1: function lib.safeprint(...) farmbuyer@1: local args = { n=select('#',...), ... } farmbuyer@19: return lib.tableprint(args) farmbuyer@1: end farmbuyer@45: function lib.safefprint(f,...) farmbuyer@45: local args = { n=select('#',...), ... } farmbuyer@45: return lib.tableprint(args,f) farmbuyer@45: end farmbuyer@1: function lib.safeiprint(...) farmbuyer@1: local args = { n=select('#',...), ... } farmbuyer@1: local last = args.n farmbuyer@1: while last > 0 do farmbuyer@1: table.insert (args, last, "<"..last..">") farmbuyer@1: last = last - 1 farmbuyer@1: end farmbuyer@1: args.n = 2 * args.n farmbuyer@19: return lib.tableprint(args) farmbuyer@1: end farmbuyer@45: function lib.safefiprint(f,...) farmbuyer@45: local args = { n=select('#',...), ... } farmbuyer@45: local last = args.n farmbuyer@45: while last > 0 do farmbuyer@45: table.insert (args, last, "<"..last..">") farmbuyer@45: last = last - 1 farmbuyer@45: end farmbuyer@45: args.n = 2 * args.n farmbuyer@45: return lib.tableprint(args,f) farmbuyer@45: end farmbuyer@19: function lib.tableprint(t,f) farmbuyer@1: for i = 1, (tonumber(t.n) or #t) do farmbuyer@1: t[i] = tostring(t[i]):gsub('\124','\124\124') farmbuyer@1: :gsub('(%c)', undocontrol) farmbuyer@1: end farmbuyer@56: local msg = tconcat(t,' ', 1, tonumber(t.n) or #t) farmbuyer@45: if type(f) == 'function' then farmbuyer@45: return msg,f(msg) farmbuyer@1: else farmbuyer@19: print(msg) farmbuyer@19: return msg,t farmbuyer@1: end farmbuyer@1: end farmbuyer@1: farmbuyer@1: -- See below for global versions. farmbuyer@1: farmbuyer@1: farmbuyer@1: ---------------------------------------------------------------------- farmbuyer@1: local StaticPopupDialogs = _G.StaticPopupDialogs farmbuyer@1: farmbuyer@1: local function EditBoxOnTextChanged_notempty (editbox) -- this is also called when first shown farmbuyer@1: if editbox:GetText() ~= "" then farmbuyer@1: editbox:GetParent().button1:Enable() farmbuyer@1: else farmbuyer@1: editbox:GetParent().button1:Disable() farmbuyer@1: end farmbuyer@1: end farmbuyer@1: local function EditBoxOnEnterPressed_accept (editbox) farmbuyer@39: if editbox:GetText() == "" then return end farmbuyer@39: local dialog = editbox:GetParent() farmbuyer@39: StaticPopupDialogs[dialog.which].OnAccept (dialog, dialog.data, dialog.data2) farmbuyer@39: dialog:Hide() farmbuyer@1: end farmbuyer@69: local function OnShow_ontop (dialog, data) farmbuyer@1: local info = StaticPopupDialogs[dialog.which] farmbuyer@69: -- ace3's elements are hardcoded to this strata, make sure popups farmbuyer@69: -- can also be seen (their toplevel=true attribute handles the farmbuyer@69: -- framelevels within the same strata) farmbuyer@69: info.saved_strata = dialog:GetFrameStrata() farmbuyer@69: dialog:SetFrameStrata("FULLSCREEN_DIALOG") farmbuyer@69: if info.hasEditBox then farmbuyer@69: dialog.editBox:SetFocus() farmbuyer@69: end farmbuyer@1: if info.farm_OnShow then farmbuyer@1: return info.farm_OnShow (dialog, data) farmbuyer@1: end farmbuyer@1: end farmbuyer@1: local function OnAccept_witheditbox (dialog, data, data2) farmbuyer@1: local info = StaticPopupDialogs[dialog.which] farmbuyer@16: --dialog.usertext = dialog[info.hasWideEditBox and "wideEditBox" or "editBox"]:GetText():trim() farmbuyer@16: dialog.usertext = dialog.editBox:GetText():trim() farmbuyer@1: if info.farm_OnAccept then farmbuyer@1: return info.farm_OnAccept (dialog, data, data2) farmbuyer@1: end farmbuyer@1: end farmbuyer@69: local function OnHide_cleanup (dialog, data) farmbuyer@69: local info = StaticPopupDialogs[dialog.which] farmbuyer@69: if info.farm_OnHide then farmbuyer@69: return info.farm_OnHide (dialog, data) farmbuyer@69: end farmbuyer@16: dialog.data = nil farmbuyer@16: dialog.data2 = nil farmbuyer@69: dialog:SetFrameStrata(info.saved_strata or "DIALOG") farmbuyer@16: end farmbuyer@1: farmbuyer@1: --[[ farmbuyer@1: StaticPopup farmbuyer@1: ]] farmbuyer@1: function lib.StaticPopup (t) farmbuyer@57: if t.hasEditBox then farmbuyer@57: t.EditBoxOnTextChanged = EditBoxOnTextChanged_notempty farmbuyer@57: t.EditBoxOnEnterPressed = EditBoxOnEnterPressed_accept farmbuyer@1: if t.OnAccept then farmbuyer@1: t.farm_OnAccept = t.OnAccept farmbuyer@1: end farmbuyer@57: t.OnAccept = OnAccept_witheditbox farmbuyer@1: -- this calls OnCancel with "clicked", unless noCancelOnEscape is set farmbuyer@57: t.EditBoxOnEscapePressed = StaticPopup_EscapePressed farmbuyer@57: end farmbuyer@1: farmbuyer@69: t.farm_OnShow = t.OnShow farmbuyer@69: t.OnShow = OnShow_ontop farmbuyer@69: t.farm_OnHide = t.OnHide farmbuyer@69: t.OnHide = OnHide_cleanup farmbuyer@16: farmbuyer@57: t.timeout = 0 farmbuyer@57: t.whileDead = true farmbuyer@57: t.hideOnEscape = true farmbuyer@1: t.enterClicksFirstButton = true farmbuyer@53: t.preferredIndex = 3 -- http://forums.wowace.com/showthread.php?t=19960 farmbuyer@1: farmbuyer@57: return t farmbuyer@1: end farmbuyer@1: farmbuyer@1: farmbuyer@1: ---------------------------------------------------------------------- farmbuyer@1: --[[ farmbuyer@1: This is ugly, but at least it all gets GC'd almost immediately. farmbuyer@1: ]] farmbuyer@1: function lib.nullfunc() end farmbuyer@1: farmbuyer@1: if ({ farmbuyer@1: ["Bandwagon"] = true, ["Kilvin"] = true, ["Waterfaucet"] = true, farmbuyer@1: ["Farmbuyer"] = true, ["Oxdeadbeef"] = true, ["Pointystick"] = true, farmbuyer@1: ["Angryhobbit"] = true, ["Malrubius"] = true, ["Hemogoblin"] = true, farmbuyer@16: ["Ossipago"] = true, farmbuyer@1: })[UnitName("player")] then farmbuyer@1: lib.author_debug = true farmbuyer@1: _G.safeprint = lib.safeprint farmbuyer@1: _G.safeiprint = lib.safeiprint farmbuyer@1: function lib.tabledump(t) farmbuyer@73: -- Should instead load this and then call the subcommands directly. farmbuyer@73: --_G.UIParentLoadAddOn("Blizzard_DebugTools") farmbuyer@1: _G.LibF_DEBUG = t farmbuyer@1: _G.SlashCmdList.DUMP("LibF_DEBUG") farmbuyer@1: end farmbuyer@1: else farmbuyer@92: -- make sure earlier lib's members aren't lingering farmbuyer@92: lib.author_debug = nil farmbuyer@92: _G.safeprint = nil farmbuyer@92: _G.safeiprint = nil farmbuyer@1: lib.tabledump = lib.nullfunc farmbuyer@1: end farmbuyer@1: lib.dumptable = lib.tabledump farmbuyer@1: farmbuyer@1: farmbuyer@1: ---------------------------------------------------------------------- farmbuyer@1: --[[ farmbuyer@1: DoOnceNextUpdate farmbuyer@1: ]] farmbuyer@1: do farmbuyer@1: local frame = CreateFrame("Frame", "LibFarmbuyerDONUFrame") farmbuyer@1: frame:Hide() farmbuyer@1: frame:SetScript("OnUpdate", function() farmbuyer@1: frame:Hide() farmbuyer@1: local q = frame.nexttime farmbuyer@1: local tmp farmbuyer@1: frame.nexttime = nil farmbuyer@1: while q do farmbuyer@1: tmp = q farmbuyer@1: q.f(frame) farmbuyer@1: q = q.n farmbuyer@1: del(tmp) farmbuyer@1: end farmbuyer@1: end) farmbuyer@1: farmbuyer@1: function lib.DoOnceNextUpdate (func) farmbuyer@1: local nextt = new() farmbuyer@1: nextt.f = func farmbuyer@1: nextt.n = frame.nexttime farmbuyer@1: frame.nexttime = nextt farmbuyer@1: frame:Show() farmbuyer@1: end farmbuyer@1: end farmbuyer@1: farmbuyer@1: farmbuyer@1: ---------------------------------------------------------------------- farmbuyer@6: --[[ farmbuyer@6: safecall farmbuyer@6: ]] farmbuyer@1: do farmbuyer@6: local xpcall = xpcall farmbuyer@6: farmbuyer@6: local function errorhandler(err) farmbuyer@6: --return geterrorhandler()(err) farmbuyer@6: --print("in error handler", err) farmbuyer@6: return err farmbuyer@1: end farmbuyer@6: farmbuyer@6: local template = ([[ farmbuyer@6: local xpcall, eh = ... farmbuyer@6: local method, ARGS farmbuyer@6: local function call() return method(ARGS) end farmbuyer@6: farmbuyer@6: local function dispatch (func, ...) farmbuyer@6: method = func farmbuyer@6: if not method then return end farmbuyer@6: ARGS = ... farmbuyer@6: return xpcall (call, eh) farmbuyer@1: end farmbuyer@6: farmbuyer@6: return dispatch farmbuyer@6: ]]):gsub('\t',' ') farmbuyer@6: farmbuyer@6: local function CreateDispatcher(argCount) farmbuyer@6: local ARGS = {} farmbuyer@6: for i = 1, argCount do ARGS[i] = "arg"..i end farmbuyer@19: local code = template:gsub("ARGS", tconcat(ARGS, ", ")) farmbuyer@6: return assert(loadstring(code, "LibF/safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler) farmbuyer@1: end farmbuyer@6: farmbuyer@6: local Dispatchers = setmetatable({ farmbuyer@6: [0] = function(func) farmbuyer@6: return xpcall (func, errorhandler) farmbuyer@1: end farmbuyer@6: }, { farmbuyer@6: __index = function (Ds, argCount) farmbuyer@6: local dispatcher = CreateDispatcher(argCount) farmbuyer@6: Ds[argCount] = dispatcher farmbuyer@6: return dispatcher farmbuyer@6: end farmbuyer@6: }) farmbuyer@6: farmbuyer@6: function lib.safecall (func, ...) farmbuyer@6: if type(func) == 'function' then farmbuyer@6: return Dispatchers[select('#', ...)](func, ...) farmbuyer@6: end farmbuyer@1: end farmbuyer@1: end farmbuyer@1: farmbuyer@6: farmbuyer@6: ---------------------------------------------------------------------- farmbuyer@6: farmbuyer@1: -- vim: noet