Mercurial > wow > ouroloot
changeset 125:a9cf9b2fbf9b
- Fix interactions with AddonLoader.
- Plugins get a :Print with a clickable prefix, with overrideable behaviors.
- 'Deactivate' event gets a [wrapper around] current raiders table.
- Fix sorting bug in player history data.
- Smarter status line text when viewing unfiltered history.
- Do not disable history regeneration button when current history is empty.
- :BuildMainDisplay can handle the CLI args now.
author | Farmbuyer of US-Kilrogg <farmbuyer@gmail.com> |
---|---|
date | Sun, 19 Aug 2012 21:08:59 -0400 |
parents | 1a248faf1a3b |
children | 9232cacc9136 |
files | core.lua gui.lua options.lua verbage.lua |
diffstat | 4 files changed, 163 insertions(+), 85 deletions(-) [+] |
line wrap: on
line diff
--- a/core.lua Fri Aug 17 02:48:13 2012 -0400 +++ b/core.lua Sun Aug 19 21:08:59 2012 -0400 @@ -21,6 +21,8 @@ - join time player joined the raid (or first time we've seen them) - leave time player left the raid (or time we've left the raid, if 'online' is not 'no_longer') +- needinfo true if haven't yet gotten close enough to player to request + unit data; SHOULD be missing Common g_loot entry indices: - kind time/boss/loot @@ -444,8 +446,10 @@ -- -- Returns an opaque token and a matching number. Calling tostring() on -- the token will yield a formatted clickable string that can be displayed - -- in chat. The MethodName and raw function callbacks will both be - -- passed the addon table and the same matching number. + -- in local chat. Clicking a tab_title hyperlink opens the GUI to that + -- tab; the MethodName and raw function callbacks will be passed the addon + -- table, the same matching number, and the mouse button (ala OnClick) as + -- arguments. -- -- This is largely an excuse to fool around with Lua data constructs. function addon.format_hypertext (text, color, func) @@ -473,14 +477,15 @@ if ltype ~= "OuroLoot" then return end arg = tonumber(arg) local f = func_map[text_map[arg]] - if type(f) == 'function' then - f (addon, arg) - elseif type(f) == 'string' then + local t = type(f) + if t == 'string' then if type(addon[f]) == 'function' then - addon[f](addon,arg) -- method name + addon[f](addon,arg,mousebutton) -- method else - addon:BuildMainDisplay(f) -- tab title fragment + addon:BuildMainDisplay(f) -- tab title fragment end + elseif t == 'function' then + f (addon, arg, mousebutton) end end) @@ -754,7 +759,7 @@ g_restore_p = OuroLootSV ~= nil self.dprint('flow', "oninit sets restore as", g_restore_p) - -- Primarily for plugins, but can be of use to me also... + -- Primarily for plugins, but can be of use to me also... LCALLBACK self.callbacks = LibStub("CallbackHandler-1.0"):New(self) --function self.callbacks:OnUsed (target_aka_self, eventname) end --function self.callbacks:OnUnused (target_aka_self, eventname) end @@ -870,11 +875,12 @@ self:RegisterEvent("PLAYER_LOGOUT") self:RegisterEvent(RAID_ROSTER_UPDATE_EVENT,"RAID_ROSTER_UPDATE") - -- Cribbed from Talented. I like the way jerry thinks: the first string - -- argument can be a format spec for the remainder of the arguments. - -- AceConsole:Printf isn't used because we can't specify a prefix without - -- jumping through ridonkulous hoops. The part about overriding :Print - -- with a version using prefix hyperlinks is my fault. + -- This Print cribbed from Talented. I like the way jerry thinks: the + -- first string argument can be a format spec for the remainder of the + -- arguments. AceConsole:Printf isn't used because we can't specify a + -- prefix without jumping through ridonkulous hoops. + -- + -- Everything dealing with a prefix hyperlink is my fault. -- -- CFPrint added instead of the usual Print testing of the first arg for -- frame-ness, which would slow down all printing and only rarely be useful. @@ -1012,7 +1018,10 @@ frame creation. ]] local bliz = CreateFrame("Frame") - bliz.name = "Ouro Loot" + bliz.name = "Ouro Loot" -- must match X-LoadOn-InterfaceOptions + if AddonLoader then + AddonLoader:RemoveInterfaceOptions(bliz.name) + end bliz:SetScript("OnShow", function(_b) local button = CreateFrame("Button",nil,_b,"UIPanelButtonTemplate") button:SetWidth(150) @@ -1020,9 +1029,9 @@ button:SetScript("OnClick", function() InterfaceOptionsFrameCancel:Click() HideUIPanel(GameMenuFrame) - addon:OpenMainDisplayToTab"Options" + addon:BuildMainDisplay('opt') end) - button:SetText('"/ouroloot opt"') + button:SetText('"/ouroloot options"') button:SetPoint("TOPLEFT",20,-20) _b:SetScript("OnShow",nil) end) @@ -1048,32 +1057,67 @@ - db: (OUT) AceDB object, set during init. - opts: (OUT) Pointer to plugin's "db.profile" subtable. - OnInitialize, [default_]OnEnable, register_text_generator, register_tab_control - are all inherited. + Inherited unchanged: + + Inherited module variants: + - OnInitialize, OnEnable + - register_text_generator, register_tab_control: also flag plugin as + a text-generating module in main addon ]] local prototype = {} - local registry + local textgen_registry, chat_prefixes, chat_codes -- By default, no plugins. First one in sets up code for any after. - addon.get_plugin = flib.nullfunc - - -- Fires before the plugin's own OnEnable (inherited or otherwise). + addon.get_textgen_plugin = flib.nullfunc + + -- Called as part of NewModule, after embedding and metas are done. + -- Mostly this is one-time setup stuff that we don't need until a plugin + -- is actually built. function addon:OnModuleCreated (plugin) - if not registry then - registry = {} - addon.get_plugin = function(a,t) return registry[t] end - prototype.register_text_generator = function(p,t,...) - registry[t] = p - return addon:register_text_generator(t,...) - end - prototype.register_tab_control = function(p,t,...) - registry[t] = p - return addon:register_tab_control(t,...) + textgen_registry, chat_prefixes, chat_codes = {}, {}, {} + addon.get_textgen_plugin = function(a,t) + return textgen_registry[t] + end + prototype.register_text_generator = function(p,t,...) + textgen_registry[t] = p + return addon:register_text_generator(t,...) + end + prototype.register_tab_control = function(p,t,...) + textgen_registry[t] = p + return addon:register_tab_control(t,...) + end + + function addon:ModulePrefixClick (codenum, mousebutton) + local plugin = assert(chat_codes[codenum]) + if not plugin:IsEnabled() then return end + if mousebutton == 'LeftButton' then + if plugin.PrefixLeftClick then + plugin:PrefixLeftClick(codenum) + else + self:BuildMainDisplay() + end + elseif mousebutton == 'RightButton' then + local uniqueval = plugin.name + if plugin.PrefixRightClick then + uniqueval = plugin:PrefixRightClick(codenum) + end + self:BuildMainDisplay('opt',uniqueval) end end + function addon:OnModuleCreated (plugin) + local token, code = self.format_hypertext (plugin.moduleName, + --[[heirloom]]7, "ModulePrefixClick") + chat_prefixes[plugin] = token + chat_codes[code] = plugin + -- remove the libraries' embedded pointers so that the prototype + -- can be inherited + plugin.Print = nil + end + + return self:OnModuleCreated(plugin) end - local function module_OnInit (plugin) + function prototype.OnInitialize (plugin) if plugin.option_defaults then plugin.db = addon.db:RegisterNamespace (plugin.moduleName, plugin.option_defaults) plugin.opts = plugin.db.profile @@ -1081,14 +1125,14 @@ end end - local function module_OnEnable (plugin) - end - - local function module_GetOption (plugin, info) + --function prototype.OnEnable (plugin) + --end + + function prototype.GetOption (plugin, info) local name = info[#info] return plugin.db.profile[name] end - local function module_SetOption (plugin, info, value) + function prototype.SetOption (plugin, info, value) local name = info[#info] plugin.db.profile[name] = value local arg = info.arg @@ -1097,11 +1141,16 @@ end end - prototype.OnInitialize = module_OnInit - prototype.OnEnable = module_OnEnable - prototype.default_OnEnable = module_OnEnable - prototype.GetOption = module_GetOption - prototype.SetOption = module_SetOption + -- may eventually just rework the main print routines and inherit all 3 + function prototype.Print (plugin, str, ...) + local AC = LibStub("AceConsole-3.0") + local ps = tostring(chat_prefixes[plugin]) + if type(str) == 'string' and str:find("%", nil, --[[plainmatch=]]true) then + return AC:Print (ps, str:format(...)) + else + return AC:Print (ps, str, ...) + end + end addon:SetDefaultModuleLibraries("AceConsole-3.0") addon:SetDefaultModulePrototype(prototype) @@ -1139,8 +1188,9 @@ The two boolean predicates are self-explanatory. The threshold is an ITEM_QUALITY_* constant integer. -'Deactivate' - After all system events have been unregistered. +'Deactivate', raiderdata + After all system events have been unregistered. Argument is a holder of + the current g_loot.raiders table (in 'raidersnap'). 'Reset' Clicking "Clear Loot", after all data manipulation is finished. @@ -1930,7 +1980,10 @@ self:UnregisterEvent("PLAYER_ENTERING_WORLD") self:UnregisterEvent("CHAT_MSG_LOOT") _LFR_suppressing = nil - self:Fire ('Deactivate') + -- Passing .raiders directly doesn't work with a proxy (again, WTB Lua + -- 5.2 and its __pairs iterators). Give it the same structure as a boss + -- entry instead. + self:Fire ('Deactivate', { raidersnap = g_loot.raiders }) self:Print("Deactivated.") end @@ -3057,7 +3110,7 @@ return L > R -- reverse of normal order, newest first end local function sort_player (p) - local new_uniques, uniques_bywhen, when_array = new(), new(), new() + local new_uniques, uniques_bywhen, when_array = {}, new(), new() for u,tstamp in pairs(p.when) do uniques_bywhen[tstamp] = u when_array[#when_array+1] = tstamp @@ -3067,7 +3120,8 @@ new_uniques[i] = uniques_bywhen[tstamp] end p.unique = new_uniques - del(new_uniques) del(uniques_bywhen) del(when_array) + del(uniques_bywhen) + del(when_array) end function addon:repair_history_integrity()
--- a/gui.lua Fri Aug 17 02:48:13 2012 -0400 +++ b/gui.lua Sun Aug 19 21:08:59 2012 -0400 @@ -458,6 +458,10 @@ function addon:_fill_out_hist_data (opt_starting_index) local new, del = flib.new, flib.del + if not self.history.st then + self.history.st = {} + self.hist_clean = nil + end -- Clearing history finishes this function with #hist==0 and hist_clean==0. -- The next call typically detects this (#<1) and handles it. If loot is -- recorded before then, it results in hist_clean==0 and #hist==1, which @@ -466,9 +470,6 @@ self.hist_clean = nil opt_starting_index = nil end - if not self.history.st then - self.history.st = {} - end -- for now if self.hist_clean == #self.history then return end @@ -1865,12 +1866,12 @@ container:AddChild(st_widget) -- If we're focused on one player, but have deleted all entries for -- that player, don't sit there stuck on a blank grid. - if history_filter_who and #histST.filtered < 1 then + if history_filter_who and #histST.filtered > 0 then + setstatus(hist_name_status) + else history_filter_who = nil histST:SetFilter(history_filter_by_recent) setstatus(hist_normal_status) - else - setstatus(hist_name_status) end local b @@ -1907,7 +1908,6 @@ b = mkbutton("Regenerate", [[Erases all history entries from the displayed realm, and regenerates it from current loot information.]]) b:SetFullWidth(true) - b:SetDisabled (#addon.history == 0) b:SetCallback("OnClick", function(_b) local dialog = StaticPopup_Show("OUROL_HIST_REGEN", addon.history.realm) dialog.data = addon @@ -2070,9 +2070,10 @@ gui.mkbutton = mkbutton --[[ -Creates the main window. +Creates the main window. Can jump directly to a tab (and feed it CLI +routine arguments), if given the appropriate tab code. ]] -function addon:BuildMainDisplay (opt_tabselect) +function addon:BuildMainDisplay (opt_tabselect, opt_tabselect_CLI_arg) if self.display then -- try to get everything to update, rebuild, refresh... ugh, no self.display:Hide() @@ -2284,26 +2285,30 @@ end) tabs:SetCallback("OnTabLeave", statusy_OnLeave) tabs:SetUserData("special buttons group",tab_specials) - tabs:SelectTab((opt_tabselect and #opt_tabselect>0) - and opt_tabselect or "eoi") + + local whichtab, tabargs = "eoi" + if opt_tabselect and #opt_tabselect > 0 then + whichtab, tabargs = opt_tabselect, opt_tabselect_CLI_arg + end + tabs:SelectTab(whichtab) display:AddChildren (tabs, control) display:ApplyStatus() + display:Show() -- without this, only appears every *other* function call - display:Show() -- without this, only appears every *other* function call + if tabargs and tabs_CLI_special[whichtab] then + tabs_CLI_special[whichtab](tabargs) + end return display end --- Searches tab titles from left to right. +-- Searches tab title texts from left to right. function addon:OpenMainDisplayToTab (text, opt_arg) text = '^'..text:lower() for _,tab in ipairs(gui.taborder) do local v = gui.tabtexts[tab] if v and v.title:lower():find(text) then - self:BuildMainDisplay(tab) - if opt_arg and tabs_CLI_special[tab] then - tabs_CLI_special[tab](opt_arg) - end + self:BuildMainDisplay (tab, opt_arg) return true end end @@ -2384,7 +2389,7 @@ StaticPopupDialogs["OUROL_HIST_REGEN"] = flib.StaticPopup{ -- Concatenate this once at load time. There is no ITEM_QUALITY_LEGENDARY constant. text = "Erase all history entries from " .. ITEM_QUALITY_COLORS[5].hex - .. "%s|r, and generate it anew from current loot?", + .. "%s|r, and generate it anew from current loot?|n|nNote this obeys the current setting of the 'Suppress history for cross-realm players' option.", button1 = YES, button2 = NO, OnAccept = function (dialog, addon, data2)
--- a/options.lua Fri Aug 17 02:48:13 2012 -0400 +++ b/options.lua Sun Aug 19 21:08:59 2012 -0400 @@ -750,6 +750,7 @@ -- widget container status tables (will have things magically appear -- inside them that we wish to preserve) +local options_treegroup -- careful, this is deliberately not preserved local status_for_scroll = {} local status_for_select = { treewidth = 160 } @@ -800,6 +801,7 @@ local tabs_OGS = function (container, specials) container:SetLayout("Fill") local left = AceGUI:Create("TreeGroup") + options_treegroup = left left:SetStatusTable(status_for_select) left:SetLayout("Fill") left:SetFullWidth(true) @@ -846,12 +848,18 @@ if preload then preload() end end +local tabs_cli = function (unique) + if not controls[unique] then return end + options_treegroup:SetSelected(unique) + options_treegroup:SetUserData("options restore scroll", false) +end + addon:register_tab_control_AT_END ("opt", [[Options]], [[Options for fine-tuning behavior]], tabs_OGS, [[ The "be chatty" options can be noisy, but they make the |cffff8000[Ouro Loot]|r link much more useful. See <Help -- Handy Tips> for details! -]]) +]], tabs_cli) --------------- @@ -873,14 +881,18 @@ --[[ PLUGIN is the module table itself. (This does not actually have to be a plugin created with :[Constrained]NewModule, as long as it has a - GetName method and + 'name' field and - TEXT is passed - if OPTIONS is a table, then OPTIONS.args.name exists -PARENT is nil to register in the tree list directly. -TEXT is either the text to display in the tree list, or nil to use the - moduleName field out of PLUGIN (not :GetName()). +UNIQUE and PARENT control placement in the tree list. UNIQUE is a unique + string, or nil to use the module's unique name (this can only be used once + obviously, or it's not "unique"). PARENT is nil to display at the main + level of options, or a previously-registered return value to display as a + child of that option. +TEXT is either the text to display in the tree list, or nil to use + PLUGIN:GetName(). OPTIONS is either - I) an aceconfig-style options table + I) an aceconfig-style options table (uses PLUGIN:GetName()) II) a function to call directly (I) Will augment options.args.name with coloring/sizing, if it exists. @@ -893,13 +905,16 @@ the "button" clicked in the lefthand tree list. Will append a reset button IFF an options database has been registered already. + +XXX - the PARENT functionality hasn't been implmented yet cuz I'm lazy ]] -function addon:register_options_entry (plugin, parent, text, options) - -- if this changes at all, fix up plugin_reset_button accordingly - local code = plugin:GetName() +function addon:register_options_entry (plugin, unique, parent, text, options) + unique = (unique and tostring(unique)) + or assert(plugin.name, "plugin has no 'name' field") + --if parent - text = text or plugin.moduleName + text = text or plugin:GetName() local handler local pdb = plugin.moduleName and @@ -907,10 +922,10 @@ if type(options) == 'table' then -- AceConfig-style options table - aceconfig_list[code] = true + aceconfig_list[unique] = true if not options.args.name then options.args.name = { - name = plugin.moduleName, + name = plugin:GetName(), type = 'description', } end @@ -948,7 +963,7 @@ if pdb then handler = function (sf) sf:AddChildren(mktitle(text)) - local ret = options (sf, plugin, code) + local ret = options (sf, plugin, unique) local w = mkbutton("Reset", ([[Reset settings for <%s> plugin back to defaults. Shift-click to also trigger a UI reload.]]):format(text)) w:SetRelativeWidth(0.3) @@ -962,7 +977,7 @@ else handler = function (sf) sf:AddChildren(mktitle(text)) - return options (sf, plugin, code) + return options (sf, plugin, unique) end end @@ -970,19 +985,19 @@ error(("Error: 'options' parameter for plugin '%s' is neither table nor function"):format(plugin:GetName())) end - if not controls[code] then - controls[code] = {} + if not controls[unique] then + controls[unique] = {} end - table.insert (controls[code], handler) + table.insert (controls[unique], handler) table.insert (options_tree, insertion_index, { - value = code, - text = text, -- maybe call markup on this? + value = unique, + text = '++ '..text, -- maybe call markup on this? }) insertion_index = insertion_index + 1 -- The treegroup will rescan options_tree (via RefreshTree) several times -- before the player actually sees anything; no more work needs doing. - return -- something that can be used as 'parent' + return unique -- something that can be used as 'parent'? end
--- a/verbage.lua Fri Aug 17 02:48:13 2012 -0400 +++ b/verbage.lua Sun Aug 19 21:08:59 2012 -0400 @@ -9,6 +9,9 @@ "near" another boss entry with nonzero duration, can we just safely assume that's the real entry and delete the zero entry altogether? +- Loading enough plugin tabs to grow a second tab row causes the ST frames +to be too large. + - Rework candidate groups into the expiring caches. - Break more methods out into private routines.