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@19: cleaned up with respect to embedded '|'/control chars. If a function F is farmbuyer@19: passed, calls that instead of print(). Returns the results of F, or the farmbuyer@19: text string passed to print(), 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@1: farmbuyer@1: - safeiprint(...) farmbuyer@19: Same as safeprint() but with numbers inserted. Returns the results farmbuyer@19: of tableprint. farmbuyer@19: Ex: safeiprint(a,b,c) --> <1>,a,<2>,b,<3>,c farmbuyer@1: 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@1: + pressing Enter runs OnAccept 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@19: local MAJOR, MINOR = "LibFarmbuyer", 12 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@19: local tconcat = table.concat 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@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@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@19: local msg = tconcat(t,' ', i, tonumber(t.n) or #t) farmbuyer@19: if f then farmbuyer@19: return 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@1: local dialog = editbox:GetParent() farmbuyer@1: StaticPopupDialogs[dialog.which].OnAccept (dialog, dialog.data, dialog.data2) farmbuyer@1: dialog:Hide() farmbuyer@1: end farmbuyer@1: local function OnShow_witheditbox (dialog, data) farmbuyer@1: local info = StaticPopupDialogs[dialog.which] farmbuyer@16: --dialog[info.hasWideEditBox and "wideEditBox" or "editBox"]:SetFocus() farmbuyer@16: dialog.editBox:SetFocus() 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@16: local function OnHide_cleanup (dialog) farmbuyer@16: dialog.data = nil farmbuyer@16: dialog.data2 = nil farmbuyer@16: end farmbuyer@1: farmbuyer@1: --[[ farmbuyer@1: StaticPopup farmbuyer@1: ]] farmbuyer@1: function lib.StaticPopup (t) farmbuyer@1: if t.hasEditBox then farmbuyer@1: t.EditBoxOnTextChanged = EditBoxOnTextChanged_notempty farmbuyer@1: t.EditBoxOnEnterPressed = EditBoxOnEnterPressed_accept farmbuyer@1: if t.OnShow then farmbuyer@1: t.farm_OnShow = t.OnShow farmbuyer@1: end farmbuyer@1: t.OnShow = OnShow_witheditbox farmbuyer@1: if t.OnAccept then farmbuyer@1: t.farm_OnAccept = t.OnAccept farmbuyer@1: end farmbuyer@1: t.OnAccept = OnAccept_witheditbox farmbuyer@1: -- this calls OnCancel with "clicked", unless noCancelOnEscape is set farmbuyer@1: t.EditBoxOnEscapePressed = StaticPopup_EscapePressed farmbuyer@1: end farmbuyer@1: farmbuyer@16: if not t.OnHide then farmbuyer@16: t.OnHide = OnHide_cleanup farmbuyer@16: end farmbuyer@16: farmbuyer@1: t.timeout = 0 farmbuyer@1: t.whileDead = true farmbuyer@1: t.hideOnEscape = true farmbuyer@1: t.enterClicksFirstButton = true farmbuyer@1: farmbuyer@1: 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@1: _G.UIParentLoadAddOn("Blizzard_DebugTools") farmbuyer@1: _G.LibF_DEBUG = t farmbuyer@1: _G.SlashCmdList.DUMP("LibF_DEBUG") farmbuyer@1: end farmbuyer@1: else 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