changeset 69:8442272a8418

- Make sure popup dialogs are on top of Ace3's widgets. - Minor code reorganization. Safety hook for future boss-entry code. - Avoid same bug from a couple revs ago when adding manual boss kills. - Ask players about snapshot data when manually entering boss kills. - Blizzard rearranged the button order in 3-entry popups some time ago and I failed to adapt the code until now.
author Farmbuyer of US-Kilrogg <farmbuyer@gmail.com>
date Fri, 11 May 2012 03:08:12 +0000
parents 3bed6d51e077
children cdee65c1bd8c
files LibFarmbuyer.lua core.lua gui.lua text_tabs.lua verbage.lua
diffstat 5 files changed, 210 insertions(+), 126 deletions(-) [+]
line wrap: on
line diff
--- a/LibFarmbuyer.lua	Wed May 09 09:38:14 2012 +0000
+++ b/LibFarmbuyer.lua	Fri May 11 03:08:12 2012 +0000
@@ -54,7 +54,7 @@
   Ditto for table recycling.
 ]]
 
-local MAJOR, MINOR = "LibFarmbuyer", 16
+local MAJOR, MINOR = "LibFarmbuyer", 17
 assert(LibStub,MAJOR.." requires LibStub")
 local lib = LibStub:NewLibrary(MAJOR, MINOR)
 if not lib then return end
@@ -167,10 +167,16 @@
 	StaticPopupDialogs[dialog.which].OnAccept (dialog, dialog.data, dialog.data2)
 	dialog:Hide()
 end
-local function OnShow_witheditbox (dialog, data)
+local function OnShow_ontop (dialog, data)
 	local info = StaticPopupDialogs[dialog.which]
-	--dialog[info.hasWideEditBox and "wideEditBox" or "editBox"]:SetFocus()
-	dialog.editBox:SetFocus()
+	-- ace3's elements are hardcoded to this strata, make sure popups
+	-- can also be seen (their toplevel=true attribute handles the
+	-- framelevels within the same strata)
+	info.saved_strata = dialog:GetFrameStrata()
+	dialog:SetFrameStrata("FULLSCREEN_DIALOG")
+	if info.hasEditBox then
+		dialog.editBox:SetFocus()
+	end
     if info.farm_OnShow then
         return info.farm_OnShow (dialog, data)
     end
@@ -183,9 +189,14 @@
         return info.farm_OnAccept (dialog, data, data2)
     end
 end
-local function OnHide_cleanup (dialog)
+local function OnHide_cleanup (dialog, data)
+	local info = StaticPopupDialogs[dialog.which]
+    if info.farm_OnHide then
+        return info.farm_OnHide (dialog, data)
+    end
 	dialog.data = nil
 	dialog.data2 = nil
+	dialog:SetFrameStrata(info.saved_strata or "DIALOG")
 end
 
 --[[
@@ -195,10 +206,6 @@
 	if t.hasEditBox then
 		t.EditBoxOnTextChanged = EditBoxOnTextChanged_notempty
 		t.EditBoxOnEnterPressed = EditBoxOnEnterPressed_accept
-		if t.OnShow then
-			t.farm_OnShow = t.OnShow
-		end
-		t.OnShow = OnShow_witheditbox
 		if t.OnAccept then
 			t.farm_OnAccept = t.OnAccept
 		end
@@ -207,9 +214,10 @@
 		t.EditBoxOnEscapePressed = StaticPopup_EscapePressed
 	end
 
-	if not t.OnHide then
-		t.OnHide = OnHide_cleanup
-	end
+	t.farm_OnShow = t.OnShow
+	t.OnShow = OnShow_ontop
+	t.farm_OnHide = t.OnHide
+	t.OnHide = OnHide_cleanup
 
 	t.timeout = 0
 	t.whileDead = true
--- a/core.lua	Wed May 09 09:38:14 2012 +0000
+++ b/core.lua	Fri May 11 03:08:12 2012 +0000
@@ -40,7 +40,9 @@
                 up; can be 0 if we're outside an instance and the player
                 inside has an older version
 - duration      in seconds; may be missing (only present if local)
-- raidersnap    copy of g_loot.raiders at the time of the boss event
+- raidersnap    copy of g_loot.raiders at the time of the boss event; may be
+                empty for manual snapshots the player didn't want included
+                (not necessarily an "error" if this is missing entirely)
 
 Loot specific g_loot indices:
 - person        recipient
@@ -107,7 +109,7 @@
 
 ------ Constants
 local option_defaults = {
-	['datarev'] = 18,    -- cheating, this isn't actually an option
+	['datarev'] = 19,    -- cheating, this isn't actually an option
 	['popup_on_join'] = true,
 	['register_slashloot'] = true,
 	['scroll_to_bottom'] = true,
@@ -616,6 +618,11 @@
 			end
 		end
 
+		bumpers[18] = bumpers[16]
+			-- In the not-very-many days between 16 and 19, I managed to break
+			-- the exact same data in the exact same way.  At least they're
+			-- not actually running the same loop twice... probably... sigh.
+
 		--[===[
 		local real = bumpers
 		bumpers = newproxy(true)
@@ -997,9 +1004,10 @@
 		-- this is set on various boss interactions, so we've got a kill/wipe
 		-- entry already
 		if addon.latest_instance then return end
-		addon.latest_instance = instance_tag()
-		local ss, max = addon:snapshot_raid()
-		addon:_mark_boss_kill (addon._addLootEntry{
+		--addon.latest_instance = instance_tag()
+		local ss, max, inst = addon:snapshot_raid()
+		addon.latest_instance = inst
+		addon:_mark_boss_kill (addon._addBossEntry{
 			kind='boss', reason='kill', bossname=[[trash]],
 			instance=addon.latest_instance, duration=0,
 			raidersnap=ss, maxsize=max
@@ -1204,8 +1212,8 @@
 		end
 
 	elseif cmd == "fake" then  -- maybe comment this out for real users
-		self:_mark_boss_kill (self._addLootEntry{
-			kind='boss',reason='kill',bossname="Baron Steamroller",instance=instance_tag(),duration=0
+		self:_mark_boss_kill (self._addBossEntry{
+			kind='boss',reason='kill',bossname="Baron Steamroller",duration=0
 		})
 		self:CHAT_MSG_LOOT ('manual', my_name, 54797)
 		if self.display then
@@ -1581,7 +1589,7 @@
 				end
 			end
 		end
-		bossi = addon._addLootEntry(boss)
+		bossi = addon._addBossEntry(boss)
 		-- addon.
 		bossi = addon._adjustBossOrder (bossi, g_boss_signpost) or bossi
 		g_boss_signpost = nil
@@ -1657,6 +1665,7 @@
 		local attempts = 1
 		local first
 
+		-- Maybe redo this to only collapse *contiguous* wipes...?
 		local i,d = 1,g_loot[1]
 		while d ~= e do
 			if d.bossname and
@@ -1820,6 +1829,23 @@
 		return index
 	end
 
+	-- Safety wrapper only.
+	-- XXX Maybe pprint something here.
+	function addon._addBossEntry (e)
+		local ret = addon._addLootEntry(e)
+		assert(e.kind=='boss')
+		local needSize = e.maxsize == nil
+		local needSnap = e.raidersnap == nil
+		local needInst = e.instance == nil
+		if needSize or needSnap then
+			local ss, max, inst = addon:snapshot_raid()
+			if needSize then e.maxsize = max end
+			if needSnap then e.raidersnap = ss end
+			if needInst then e.instance = inst end
+		end
+		return ret
+	end
+
 	-- Problem:  (1) boss kill happens, (2) fast looting happens, (3) boss
 	-- cache cleanup fires.  Result:  loot shows up before boss kill entry.
 	-- Solution:  We need to shuffle the boss entry above any of the loot
--- a/gui.lua	Wed May 09 09:38:14 2012 +0000
+++ b/gui.lua	Fri May 11 03:08:12 2012 +0000
@@ -711,7 +711,7 @@
 		notCheckable = true,
 	}},
 	{
-		"Change from 'wipe' to 'kill'|Also collapses other wipe entries.",
+		"Change from 'wipe' to 'kill'|Also collapses previous wipe entries.",
 		"Rebroadcast this boss%boss|Broadcasts the kill event and all subsequent loot until next boss.",
 		"Delete this boss event|Permanent, no going back!",
 		"Delete remaining entries for this boss%boss|Erases everything from here down until a new boss/day.\n\nHold down the Shift key to also delete the player's corresponding History entry.",
@@ -2195,104 +2195,6 @@
 
 
 ------ Popup dialogs
--- Callback for each Next/Accept stage of inserting a new loot row via dropdown
-local function eoi_st_insert_OnAccept_boss (dialog, data)
-	if data.all_done then
-		-- It'll probably be the final entry in the table, but there might have
-		-- been real loot happening at the same time.
-		local boss_index = addon._addLootEntry{
-			kind		= 'boss',
-			bossname	= (OuroLootSV_opts.snarky_boss and addon.boss_abbrev[data.name] or data.name) or data.name,
-			reason		= 'kill',
-			instance	= data.instance,
-			duration	= 0,
-		}
-		local entry = tremove(g_loot,boss_index)
-		tinsert(g_loot,data.rowindex,entry)
-		addon:_mark_boss_kill(data.rowindex)
-		data.display:GetUserData("eoiST"):OuroLoot_Refresh(data.rowindex)
-		dialog.data = nil   -- free up memory
-		addon:Print("Inserted %s %s (entry %d).", data.kind, data.name, data.rowindex)
-		return
-	end
-
-	local text = dialog.editBox:GetText()
-
-	-- second click
-	if data.name and text then
-		data.instance = text
-		data.all_done = true
-		-- in future do one more thing, for now just jump to the check
-		return eoi_st_insert_OnAccept_boss (dialog, data)
-	end
-
-	-- first click
-	if text then
-		data.name = text
-		local getinstance = StaticPopup_Show("OUROL_EOI_INSERT","instance")
-		getinstance.data = data
-		getinstance.editBox:SetText((addon.instance_tag()))
-		-- This suppresses auto-hide (which would case the getinstance dialog
-		-- to go away), but only when mouse clicking.  OnEnter is on its own.
-		return true
-	end
-end
-
-local function eoi_st_insert_OnAccept_loot (dialog, data)
-	if data.all_done then
-		--local real_rebroadcast, real_enabled = addon.rebroadcast, addon.enabled
-		--g_rebroadcast, g_enabled = false, true
-		data.display:Hide()
-		local loot_index = addon:CHAT_MSG_LOOT ("manual", data.recipient, data.name, data.notes)
-		--g_rebroadcast, g_enabled = real_g_rebroadcast, real_g_enabled
-		local entry = tremove(g_loot,loot_index)
-		tinsert(g_loot,data.rowindex,entry)
-		--data.display:GetUserData("eoiST"):OuroLoot_Refresh(data.rowindex)
-		addon:_fill_out_eoi_data(data.rowindex)
-		addon:BuildMainDisplay()
-		dialog.data = nil
-		addon:Print("Inserted %s %s (entry %d).", data.kind, data.name, data.rowindex)
-		return
-	end
-
-	local text = dialog.editBox:GetText():trim()
-
-	-- third click
-	if data.name and data.recipient and text then
-		data.notes = (text ~= "<none>") and text or nil
-		data.all_done = true
-		return eoi_st_insert_OnAccept_loot (dialog, data)
-	end
-
-	-- second click
-	if data.name and text then
-		data.recipient = text
-		local getnotes = StaticPopup_Show("OUROL_EOI_INSERT","notes")
-		getnotes.data = data
-		getnotes.editBox:SetText("<none>")
-		getnotes.editBox:HighlightText()
-		return true
-	end
-
-	-- first click
-	if text then
-		data.name = text
-		dialog:Hide()  -- technically a "different" one about to be shown
-		local getrecipient = StaticPopup_Show("OUROL_EOI_INSERT","recipient")
-		getrecipient.data = data
-		getrecipient.editBox:SetText("")
-		return true
-	end
-end
-
-local function eoi_st_insert_OnAccept (dialog, data)
-	if data.kind == 'boss' then
-		return eoi_st_insert_OnAccept_boss (dialog, data)
-	elseif data.kind == 'loot' then
-		return eoi_st_insert_OnAccept_loot (dialog, data)
-	end
-end
-
 StaticPopupDialogs["OUROL_CLEAR"] = flib.StaticPopup{
 	text = "Clear current loot information and text?",
 	button1 = YES,
@@ -2356,17 +2258,18 @@
 }
 
 StaticPopupDialogs["OUROL_REMIND"] = flib.StaticPopup{
-	text = "Do you wish to activate Ouro Loot?\n\n(Hit the Escape key to close this window without clicking)",
+	text = "Do you wish to activate Ouro Loot?\n\n(Hit the Escape key to close this window without clicking; Enter is the same as Activate)",
 	button1 = "Activate recording",  -- "accept", left
-	button3 = "Broadcast only",      -- "alt", middle
-	button2 = "Help",                -- "cancel", right
+	button2 = "Broadcast Only",      -- "cancel", middle
+	button3 = HELP_LABEL,            -- "alt", right
 	OnAccept = function (dialog, addon)
 		addon:Activate()
 	end,
-	OnAlt = function (dialog, addon)
+	noCancelOnEscape = true,
+	OnCancel = function (dialog, addon)
 		addon:Activate(nil,true)
 	end,
-	OnCancel = function (dialog, addon)
+	OnAlt = function (dialog, addon)
 		-- hitting escape also calls this, but the 3rd arg would be "clicked"
 		-- in both cases, not useful here.
 		local helpbutton = dialog.button2
@@ -2381,6 +2284,128 @@
 	end,
 }
 
+-- Callback for each Next/Accept stage of inserting a new loot or boss row via
+-- dropdown.  Thanks to noCancelOnReuse, each Show done here will technically
+-- Hide and redisplay the same dialog, passing along the same 'data' structure
+-- each time.  The topmost call to our OnAccept will then finish by hiding the
+-- (very last) dialog.
+--
+-- This is really, really hideous to read.
+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 at the same time.
+		local boss_index = addon._addBossEntry{
+			kind		= 'boss',
+			bossname	= (OuroLootSV_opts.snarky_boss and addon.boss_abbrev[data.name] or data.name) or data.name,
+			reason		= 'kill',
+			instance	= data.instance,
+			duration	= 0,
+			maxsize		= data.max_raid_size,
+			raidersnap	= data.yes_snap or {},
+		}
+		local entry = tremove(g_loot,boss_index)
+		tinsert(g_loot,data.rowindex,entry)
+		addon:_mark_boss_kill(data.rowindex)
+		data.display:GetUserData("eoiST"):OuroLoot_Refresh(data.rowindex)
+		dialog.data = nil   -- free up memory
+		addon:Print("Inserted %s %s (entry %d).", data.kind, data.name, data.rowindex)
+		return
+	end
+
+	-- third click
+	if data.name and data.instance then
+		data.all_done = true
+		-- this is how we distinguish OnAccept from OnCancel ("clicked"); the
+		-- 3rd param is handled all in StaticPopup_OnClick
+		if data2 ~= 'clicked' then
+			data.yes_snap = data.maybe_snap
+		end
+		return eoi_st_insert_OnAccept_boss (dialog, data)
+	end
+
+	local text = dialog.editBox:GetText():trim()
+
+	-- second click
+	if data.name and text then
+		data.instance = text
+		-- not "resuing" this dialog in the same sense as with loot
+		dialog.data = nil
+		dialog:Hide()
+		local getsnap = StaticPopup_Show("OUROL_EOI_INSERT_INCLUDE_RAIDERSNAP")
+		getsnap.data = data
+		return true
+	end
+
+	-- first click
+	if text then
+		data.name = text
+		local maybe_instance
+		data.maybe_snap, data.max_raid_size, maybe_instance = addon:snapshot_raid()
+		local getinstance = StaticPopup_Show("OUROL_EOI_INSERT","instance")
+		getinstance.data = data
+		getinstance.editBox:SetText(maybe_instance)
+		-- This suppresses auto-hide (which would cause the getinstance dialog
+		-- to go away), but only when mouse clicking.  OnEnter is on its own.
+		return true
+	end
+end
+
+local function eoi_st_insert_OnAccept_loot (dialog, data)
+	if data.all_done then
+		--local real_rebroadcast, real_enabled = addon.rebroadcast, addon.enabled
+		--g_rebroadcast, g_enabled = false, true
+		data.display:Hide()
+		local loot_index = addon:CHAT_MSG_LOOT ("manual", data.recipient, data.name, data.notes)
+		--g_rebroadcast, g_enabled = real_g_rebroadcast, real_g_enabled
+		local entry = tremove(g_loot,loot_index)
+		tinsert(g_loot,data.rowindex,entry)
+		--data.display:GetUserData("eoiST"):OuroLoot_Refresh(data.rowindex)
+		addon:_fill_out_eoi_data(data.rowindex)
+		addon:BuildMainDisplay()
+		dialog.data = nil
+		addon:Print("Inserted %s %s (entry %d).", data.kind, data.name, data.rowindex)
+		return
+	end
+
+	local text = dialog.editBox:GetText():trim()
+
+	-- third click
+	if data.name and data.recipient and text then
+		data.notes = (text ~= "<none>") and text or nil
+		data.all_done = true
+		return eoi_st_insert_OnAccept_loot (dialog, data)
+	end
+
+	-- second click
+	if data.name and text then
+		data.recipient = text
+		local getnotes = StaticPopup_Show("OUROL_EOI_INSERT","notes")
+		getnotes.data = data
+		getnotes.editBox:SetText("<none>")
+		getnotes.editBox:HighlightText()
+		return true
+	end
+
+	-- first click
+	if text then
+		data.name = text
+		dialog:Hide()  -- technically a "different" one about to be shown
+		local getrecipient = StaticPopup_Show("OUROL_EOI_INSERT","recipient")
+		getrecipient.data = data
+		getrecipient.editBox:SetText("")
+		return true
+	end
+end
+
+local function eoi_st_insert_OnAccept (dialog, data)
+	if data.kind == 'boss' then
+		return eoi_st_insert_OnAccept_boss (dialog, data)
+	elseif data.kind == 'loot' then
+		return eoi_st_insert_OnAccept_loot (dialog, data)
+	end
+end
+
 -- The data member here is a table built with:
 -- {rowindex=<GUI row receiving click>, display=_d, kind=<loot/boss>}
 do
@@ -2408,10 +2433,8 @@
 	t.enterClicksFirstButton = nil  -- no effect with editbox focused
 	t.OnAccept = eoi_st_insert_OnAccept
 	StaticPopupDialogs["OUROL_EOI_INSERT"] = t
-end
 
--- This seems to be gratuitous use of metatables, really.
-do
+	-- This seems to be gratuitous use of metatables, really.
 	local OEIL = {
 		text = "Paste the new item into here, then click Next or press Enter:",
 		__index = StaticPopupDialogs["OUROL_EOI_INSERT"]
@@ -2425,6 +2448,24 @@
 			return true
 		end
 	end)
+
+	t = flib.StaticPopup{
+	-- Concatenate this once at load time.  There is no ITEM_QUALITY_LEGENDARY constant.
+		text = "Include a snapshot of the " .. ITEM_QUALITY_COLORS[5].hex
+			.. "CURRENT|r raid?\n\nClicking '" .. YES .. "' will allow this entry to "
+			.. "appear in attendance lists, but with the roster as it is NOW, not as it "
+			.. "was THEN.  Clicking '" .. NO .."' means this kill cannot be included in "
+			.. "attendance.\n\n(Enter = '" .. YES .."', Escape = '" .. CANCEL .. "')",
+		button1 = YES,     -- "accept", left
+		button2 = NO,      -- "cancel", middle
+		button3 = CANCEL,  -- "alt", right
+	}
+	-- Hitting Escape still hides the frame, but doesn't run OnCancel (which
+	-- is for the "No" button, not the "Cancel"/OnAlt button).  Dizzy yet?
+	t.noCancelOnEscape = true
+	t.OnAccept = eoi_st_insert_OnAccept_boss
+	t.OnCancel = eoi_st_insert_OnAccept_boss
+	StaticPopupDialogs["OUROL_EOI_INSERT_INCLUDE_RAIDERSNAP"] = t
 end
 
 StaticPopupDialogs["OUROL_REASSIGN_ENTER"] = flib.StaticPopup{
--- a/text_tabs.lua	Wed May 09 09:38:14 2012 +0000
+++ b/text_tabs.lua	Fri May 11 03:08:12 2012 +0000
@@ -176,7 +176,7 @@
 		local e = loot[i]
 
 		if e.kind == 'boss' and e.reason == 'kill' then
-			-- This could, concievably, be different on a per-boss basis
+			-- Raid size can potentially be different on a per-boss basis
 			-- (e.g., "we're dropping to 10-man for the PvP boss")
 			local i,o = do_attendance (e.raidersnap, e.maxsize / MEMBERS_PER_RAID_GROUP)
 
--- a/verbage.lua	Wed May 09 09:38:14 2012 +0000
+++ b/verbage.lua	Fri May 11 03:08:12 2012 +0000
@@ -512,6 +512,13 @@
 the loot grid.  The surefire way to avoid this is to not release spirit until
 DBM announces the wipe, but the problem isn't serious enough to really worry
 about.  (Right-click the spurious entries and delete them.)
+
+When a boss is killed, ALL previous wipes for that boss are removed and
+collapsed... even if they're on other days with other raids.  If you only
+raid with one guild, this can result in some amusing statistics ("kill
+on 27th attempt" would actually mean something), but if there are multiple
+raid configurations without clearing loot in between, then this number
+is simply garbage.
 ]]
 
 T.todo_todolist = todo