changeset 116:fc2ff128835a

- Reset the 'clean' markers on all default-function option toggles. - Fix a long-standing FIXME: Move all lib-scrollingtable and other "display-only" data out of g_loot entries and into their own subclass- style table; feed that to ST's SetData instead. No more 'cols'.
author Farmbuyer of US-Kilrogg <farmbuyer@gmail.com>
date Thu, 16 Aug 2012 17:11:57 -0400
parents 289c7667adab
children dbdab3780757
files core.lua gui.lua options.lua text_tabs.lua verbage.lua
diffstat 5 files changed, 159 insertions(+), 116 deletions(-) [+]
line wrap: on
line diff
--- a/core.lua	Tue Aug 14 20:37:12 2012 -0400
+++ b/core.lua	Thu Aug 16 17:11:57 2012 -0400
@@ -27,7 +27,6 @@
 - hour          0-23, on the *physical instance server*, not the realm server
 - minute        0-59, ditto
 - stamp         time_t on the local computer
-- cols          graphical display data; cleared when logging out
 
 Time specific g_loot indices:
 - startday      table with month/day/year/text fields from makedate()
@@ -1240,9 +1239,6 @@
 	if worth_saving then
 		opts.autoshard = self.sharder
 		opts.threshold = self.threshold
-		for i,e in ipairs(g_loot) do
-			e.cols = nil
-		end
 		_G.OuroLootSV = g_loot
 	else
 		_G.OuroLootSV = nil
@@ -2237,7 +2233,7 @@
 	end
 
 	self.threshold = opts.threshold or self.threshold -- in the case of restoring but not tracking
-	self:gui_init (g_loot, g_uniques)
+	local g_loot_wrapper = self:gui_init (g_loot, g_uniques)
 	opts.autoshard = nil
 	opts.threshold = nil
 
@@ -2247,7 +2243,7 @@
 		self:zero_printed_fenceposts(0)  -- g_loot.printed.* = 0
 	end
 	if possible_st then
-		possible_st:SetData(g_loot)
+		possible_st:SetData(g_loot_wrapper)
 	end
 
 	self.status_text = ("%s(r%s) communicating as ident %s commrev %s"):
@@ -2256,7 +2252,8 @@
 	self:RegisterComm(self.identTg, "OnCommReceivedNocache")
 
 	if self.author_debug then
-		_G.Oloot = g_loot
+		_G.Ogloot = g_loot
+		_G.Odloot = g_loot_wrapper
 	end
 end
 
--- a/gui.lua	Tue Aug 14 20:37:12 2012 -0400
+++ b/gui.lua	Thu Aug 16 17:11:57 2012 -0400
@@ -14,6 +14,7 @@
 local eoi_st_rowheight			= 20
 local eoi_st_displayed_rows		= math.floor(416/eoi_st_rowheight)
 local eoi_st_textured_item_format = "|T%s:"..(eoi_st_rowheight-2).."|t %s[%s]|r%s"
+local eoi_st_cols               -- defined below
 -- This can get indexed by kind/reason/etc, and will default to lib-st's
 -- default "blank" background at runtime.
 local eoi_st_otherrow_bgcolortable = {
@@ -27,10 +28,6 @@
 local function eoi_st_lootrow_col3_colortable_func (data, _, realrow)
 	return eoi_st_lootrow_col3_colortable[data[realrow].disposition]
 end
-local time_column1_used_mt = { __index = {
-	[2] = {value=""},
-	[3] = {value=""},
-} }
 
 
 ------ Globals
@@ -57,6 +54,7 @@
 end
 
 local g_loot			= nil
+local g_dloot			= nil    -- GUI-related "child" of the main table
 local g_uniques			= nil
 local g_generated		= nil
 local window_title		= "Ouro Loot"
@@ -132,6 +130,58 @@
 end
 
 
+local do_g_loot_wrap
+do
+	local FOREIGN_SERVER_LABEL = FOREIGN_SERVER_LABEL
+	local wrappers = {
+		-- WTB Lua 5.2 instead of this
+		["LEN"] = function()
+			return #g_loot
+		end,
+		-- returns the display's entry and the core entry
+		["remove"] = function (dt, i)
+			local reale = tremove (g_loot, i)
+			return tremove (dt, i), reale
+		end,
+		-- counterpart
+		--[[
+		["insert"] = function (dt, i, displaye, reale)
+			tinsert (g_loot, i, reale)
+			tinsert (dt, i, displaye)
+		end,]]
+	}
+	local function wrap_e (t,index)
+		local real = g_loot[index]
+		if not real then return nil end
+
+		local e = {
+			__index = real,
+			__newindex = real,
+			cols = {},
+		}
+		if real.kind == 'loot' then
+			e.dperson = real.person_realm and
+				(real.person .. FOREIGN_SERVER_LABEL) or real.person
+		end
+		setmetatable(e,e)
+		rawset(t,index,e)
+		return e
+	end
+	function do_g_loot_wrap (g)
+		local dl = {}
+		for k,v in pairs(wrappers) do
+			dl[k] = v
+		end
+		for i,e in ipairs(g) do
+			wrap_e (dl, i)
+		end
+		return setmetatable(dl, {
+			__index = wrap_e,
+		})
+	end
+end
+
+
 ------ Behind the scenes routines
 -- Text generation
 do
@@ -313,105 +363,90 @@
 --[[
 The g_loot table is populated only with "behavior-relevant" data (names,
 links, etc).  This function runs through it and fills out the "display-
-relevant" bits (icons, user-friendly labels, etc).  Everything from the
-loot_clean index to the end of the table is filled out, loot_clean is
-updated.  Override the starting point with the argument.
+relevant" bits (icons, user-friendly labels, etc) in the g_dloot table,
+which inherits (so to speak) the corresponding row entries.
 
-XXX blizzard's scrolling update and lib-st keep finding some way of displaying
-the grid without ever calling the hooked refresh, thereby skipping this
-function and erroring on missing columnar data.  fuckit.  from now on
-this function gets called everywhere, all the time, and loops over the
-entire goddamn table each time.  If we can't find blizz's scrollframe bugs,
-we'll just work around them.  Sorry for your smoking CPU.
+Everything from the loot_clean index to the end of the table is filled out;
+loot_clean is updated.  Override this starting point with the function arg.
+]]
+function addon:_fill_out_eoi_data (opt_starting_index)
+	if #g_loot < 1 then
+		--pprint('_f_o_e_d', "#g_loot<1")
+		self.loot_clean = nil
+		opt_starting_index = nil
+	end
 
-FIXME just move this functionality to a per-entry function and call it once
-in _addlootentry.  --actually no, then the columnar data won't be updated once
-the backend data is changed on the fly.
-]]
-do
-	function addon:_fill_out_eoi_data (opt_starting_index)
-		if #g_loot < 1 then
-			--pprint('_f_o_e_d', "#g_loot<1")
+	local display_bcast_from = self.db.profile.display_bcast_from
+	local colcount = #eoi_st_cols
+
+	-- 'while true' so that we can use (inner) break as (outer) continue
+	for i = (opt_starting_index or self.loot_clean or 1), #g_loot do while true do
+		local e = g_dloot[i]
+		if e == nil then
 			self.loot_clean = nil
-			opt_starting_index = nil
+			pprint('_f_o_e_d', "index",i,"somehow still in loop past",#g_loot,"bailing")
+			-- hmm.  used to bail here.  does restarting instead cause problems?
+			return self:_fill_out_eoi_data(1)
 		end
-		for i = (opt_starting_index or self.loot_clean or 1), #g_loot do
-			local e = g_loot[i]
-			if e == nil then
-				self.loot_clean = nil
-				pprint('_f_o_e_d', "index",i,"somehow still in loop past",#g_loot,"bailing")
-				-- hmm.  used to bail here.  does restarting cause problems?
-				return self:_fill_out_eoi_data(1)
-			end
 
-			local display_bcast_from = self.db.profile.display_bcast_from
-			-- XXX FIXME a major weakness here is that we're constantly replacing
-			-- what's already been created.  Lots of garbage.  Trying to detect what
-			-- actually needs to be replaced is even worse.  We'll live with
-			-- garbage for now.
-			if e.kind == 'loot' then
-				local textured = eoi_st_textured_item_format:format (e.itexture, ITEM_QUALITY_COLORS[e.quality].hex, e.itemname, e.count or "")
-				local pdisplay = e.person_realm
-					and (e.person .. FOREIGN_SERVER_LABEL) or e.person
-				e.cols = {
-					{value = textured},
-					{value = pdisplay},
-					{}
-				}
-				-- This is horrible. Must do better.
-				if e.extratext then
-					for disp,text in self:_iter_dispositions('from_notes_text') do
-						if text == e.extratext then
-							e.disposition = disp
-							break
-						end
+		assert(type(rawget(e,'cols'))=='table')
+
+		while #e.cols < colcount do
+			e.cols[#e.cols+1] = {}
+		end
+
+		if e.kind == 'loot' then
+			local textured = eoi_st_textured_item_format:format (e.itexture,
+				ITEM_QUALITY_COLORS[e.quality].hex, e.itemname, e.count or "")
+			e.cols[1].value = textured
+			e.cols[2].value = e.dperson
+			-- This is horrible. Must do better.
+			if e.extratext then
+				for disp,text in self:_iter_dispositions('from_notes_text') do
+					if text == e.extratext then
+						e.disposition = disp
+						break
 					end
 				end
-				local ex = eoi_st_lootrow_col3_colortable[e.disposition].text
-				if e.bcast_from and display_bcast_from and e.extratext then
-					ex = e.extratext .. " (from " .. e.bcast_from .. ")"
-				elseif e.bcast_from and display_bcast_from then
-					ex = ex .. (e.disposition and " " or "")
-					     .. "(from " .. e.bcast_from .. ")"
-				elseif e.extratext then
-					ex = e.extratext
+			end
+			local ex = eoi_st_lootrow_col3_colortable[e.disposition].text
+			if e.bcast_from and display_bcast_from and e.extratext then
+				ex = e.extratext .. " (from " .. e.bcast_from .. ")"
+			elseif e.bcast_from and display_bcast_from then
+				ex = ex .. (e.disposition and " " or "")
+					 .. "(from " .. e.bcast_from .. ")"
+			elseif e.extratext then
+				ex = e.extratext
+			end
+			e.cols[3].value = ex
+
+		elseif e.kind == 'boss' then
+			local v
+			e.duration = e.duration or 0 -- can occasionally miss getting set
+			if e.reason == 'kill' then
+				if e.attempts == 1 then
+					v = "one-shot"
+				else
+					v = ("kill on %d%s attempt"):format(e.attempts or 0,
+						e.attempts==2 and "nd" or e.attempts==3 and "rd" or "th")
 				end
-				e.cols[3].value = ex
+				v = ("%s (%d:%.2d)"):format(v, math.floor(e.duration/60), math.floor(e.duration%60))
+			elseif e.reason == 'wipe' then
+				v = ("wipe (%d:%.2d)"):format(math.floor(e.duration/60), math.floor(e.duration%60))
+			end
+			e.cols[1].value = e.bossname
+			e.cols[2].value = e.instance
+			e.cols[3].value = v or ""
 
-			elseif e.kind == 'boss' then
-				local v
-				e.duration = e.duration or 0 -- can occasionally miss getting set
-				if e.reason == 'kill' then
-					if e.attempts == 1 then
-						v = "one-shot"
-					else
-						v = ("kill on %d%s attempt"):format(e.attempts or 0,
-							e.attempts==2 and "nd" or e.attempts==3 and "rd" or "th")
-					end
-					v = ("%s (%d:%.2d)"):format(v, math.floor(e.duration/60), math.floor(e.duration%60))
-				elseif e.reason == 'wipe' then
-					v = ("wipe (%d:%.2d)"):format(math.floor(e.duration/60), math.floor(e.duration%60))
-				end
-				e.cols = {
-					{value = e.bossname},
-					{value = e.instance},
-					{value = v or ""},
-				}
+		elseif e.kind == 'time' then
+			e.cols[1].value = e.startday.text
+			e.cols[2].value = ""
+			e.cols[3].value = ""
 
-			elseif e.kind == 'time' then
-				e.cols = setmetatable({
-					{value=e.startday.text},
-				}, time_column1_used_mt)
-				--[[e.cols = {
-					{value=e.startday.text},
-					{value=""},
-					{value=""},
-				}]]
-
-			end
 		end
-		self.loot_clean = #g_loot
-	end
+		break
+	end end
+	self.loot_clean = #g_loot
 end
 
 do
@@ -803,6 +838,7 @@
 function addon:gui_init (loot_pointer, uniques_pointer)
 	g_loot = assert(loot_pointer, "something went wrong at startup")
 	g_uniques = assert(uniques_pointer, "something went wrong at startup")
+	g_dloot = do_g_loot_wrap(g_loot)
 	g_generated = nil
 	tabgroup_tabs = {}
 	window_title = "Ouro Loot " .. self.version
@@ -823,6 +859,7 @@
 		end
 	end
 	dirty_tabs = nil
+	return g_dloot
 end
 
 --[[
@@ -889,7 +926,7 @@
 	end,
 
 	df_DELETE = function(rowi)
-		local gone = tremove (g_loot, rowi)
+		local dgone, gone = g_dloot:remove(rowi)
 		addon:Fire ('DelEOIEntry', gone)
 		addon:Print("Removed %s.",
 			gone.itemlink or gone.bossname or gone.startday.text)
@@ -914,7 +951,7 @@
 	["Delete remaining entries for this day"] = function(rowi,kind)
 		-- if kind is boss, also need to stop at new timestamp
 		local fencepost = addon._find_timeboss_fencepost (kind, rowi)
-		local count = fencepost and (fencepost-rowi) or (#g_loot-rowi+1)
+		local count = fencepost and (fencepost-rowi) or (#g_dloot-rowi+1)
 		repeat
 			eoi_dropdownfuncs.df_DELETE(rowi)
 			count = count - 1
@@ -922,7 +959,7 @@
 	end,
 
 	["Rebroadcast this loot entry"] = function(rowi)
-		local e = g_loot[rowi]
+		local e = g_dloot[rowi]
 		-- This only works because GetItemInfo accepts multiple argument formats
 		addon:vbroadcast('loot', e.person, e.unique, e.itemlink, e.count, e.cols[3].value)
 		addon:Print("Rebroadcast entry", rowi, e.itemlink)
@@ -930,11 +967,11 @@
 
 	["Rebroadcast this boss"] = function(rowi,kind)
 		-- if kind is boss, also need to stop at new timestamp
-		local fencepost = addon._find_timeboss_fencepost (kind, rowi) or #g_loot
+		local fencepost = addon._find_timeboss_fencepost (kind, rowi) or #g_dloot
 		-- this could be a lot of traffic, but frankly it's counterproductive
 		-- to try to micromanage when ChatThrottleLib is already doing so
 		repeat
-			local e = g_loot[rowi]
+			local e = g_dloot[rowi]
 			if e.kind == 'boss' then
 				addon:vbroadcast('boss', e.reason, e.bossname, e.instance)
 			elseif e.kind == 'loot' then
@@ -1205,7 +1242,7 @@
 end
 
 function eoi_editcell (row_index, cell_frame)
-	local e = g_loot[row_index]
+	local e = g_dloot[row_index]
 	if not e then return end   -- how the hell could we get this far?
 	local celldata = e.cols[3]
 	local box = AceGUI:Create("EditBox")
@@ -1329,7 +1366,7 @@
 	end
 end
 
-local eoi_st_cols = {
+eoi_st_cols = {
 	{  -- col 1
 		name	= "Item",
 		width	= 250,
@@ -1381,7 +1418,7 @@
 	-- through this loop.
 	addon:_fill_out_eoi_data(1)
 	-- safety check  begin
-	for i,e in ipairs(g_loot) do
+	for i,e in ipairs(g_dloot) do
 		if type(e.cols) ~= 'table' then
 			addon:Print("ARGH, index",i,"bad in eoi_OGS, type",type(e.cols),
 				"entry kind", e.kind, "data", e.itemname or e.bossname or e.startday.text,
@@ -1390,7 +1427,7 @@
 		end
 	end
 	-- safety check  end
-	ST:SetData(g_loot)
+	ST:SetData(g_dloot)
 	ST:EnableSelection(true)
 	ST:RegisterEvents{
 		OnEnter = eoi_st_OnEnter,
@@ -1411,7 +1448,7 @@
 	ST.OuroLoot_Refresh = function (self, opt_index)
 		addon:_fill_out_eoi_data(opt_index)
 		-- safety check  begin
-		for i,e in ipairs(g_loot) do
+		for i,e in ipairs(g_dloot) do
 			if type(e.cols) ~= 'table' then
 				addon:Print("ARGH, index",i,"bad in eoi refresh, refreshed at", opt_index, "type",type(e.cols),
 					"entry kind", e.kind, "data", e.itemname or e.bossname or e.startday.text,
@@ -1521,7 +1558,7 @@
 	if type(name_or_lineno) == 'string' then
 		-- uh
 	elseif type(name_or_lineno) == 'number' then
-		if name_or_lineno < 1 or name_or_lineno > #g_loot then
+		if name_or_lineno < 1 or name_or_lineno > #g_dloot then
 			return
 		end
 		local scrollhere = -9
@@ -2485,11 +2522,13 @@
 -- each time.  The topmost call to our OnAccept will then finish by hiding the
 -- (very last) dialog.
 --
--- This is really, really hideous to read.
+-- This is really, really hideous to read.  Maybe increment a 'stage' counter
+-- so the code flows top-down, rather than testing for missing data and going
+-- backwards.
 local function eoi_st_insert_OnAccept_boss (dialog, data, data2)
 	if data.all_done then
-		-- It'll probably be the final entry in the table, but there might have
-		-- been real loot happening while the user was clicking and typing.
+		-- boss_index will probably be the final entry in the table, but there
+		-- might have been real loot happening while the user was typing.
 		local boss_index = addon._addBossEntry{
 			kind		= 'boss',
 			bossname	= (gui.opts.snarky_boss and addon.boss_abbrev[data.name] or data.name) or data.name,
--- a/options.lua	Tue Aug 14 20:37:12 2012 -0400
+++ b/options.lua	Thu Aug 16 17:11:57 2012 -0400
@@ -80,6 +80,8 @@
 		w:SetValue(opts[opt])
 		w:SetCallback("OnValueChanged", opt_func or (function(_w,event,value)
 			opts[opt] = value
+			addon.loot_clean = nil
+			addon.hist_clean = nil
 		end))
 	end
 	return w
@@ -180,11 +182,11 @@
 
 	-- showing the "(from Rebroadcasterdude)" in the notes column
 	w = mktoggle('display_bcast_from', "Show rebroadcasting player", stdw,
-		[[Include "from PlayerName" in the Notes column for loot that was broadcast to you.  (Not included in forum output).]],
+		[[Include "from PlayerName" in the Notes column for loot that was broadcast to you.  (Not included in forum output).]])--[[
 		function(_w,_e,value)
 			opts.display_bcast_from = value
 			addon.loot_clean = nil
-		end)
+		end)]]
 	container:AddChild(w)
 
 	-- prefilling g_uniques with history
--- a/text_tabs.lua	Tue Aug 14 20:37:12 2012 -0400
+++ b/text_tabs.lua	Thu Aug 16 17:11:57 2012 -0400
@@ -20,8 +20,6 @@
 
 Preconditions:
   + LAST_PRINTED < #LOOT
-  + all "display-relevant" information for the main Loot tab has been filled
-    out (e.g., LOOT[i].cols[3] might have extra text, etc)
   + LOOT.TTYPE is a non-nil string containing all text in the text box (and
     if the user has edited the text box, this string will be updated).  Do not
     change this, but like GENERATED.TTYPE it is available for examination.
--- a/verbage.lua	Tue Aug 14 20:37:12 2012 -0400
+++ b/verbage.lua	Thu Aug 16 17:11:57 2012 -0400
@@ -17,6 +17,12 @@
 
 - Being able to drag rows up and down the main loot grid would be awesome.  Coding
 that would be likely to drive me batshiat insane.
+
+- Something to NOT do:  sort cross-realm recipients into history realms based
+on the realm of the recipient instead of the realm of the player.  While this
+would be useful for building up a history across realms... why would you want
+to do that?  Massive data piling up that wouldn't be noticed unless the user
+makes a habit of clicking the realm dropdown menu and looking around history.
 ]]
 
 local helptree = {