diff gui.lua @ 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 67bf97136273
children ec5174529e0f
line wrap: on
line diff
--- 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,