changeset 15:3a2beea01a28

Use a paged window instead of a huge one. Make LoD. Show flag #14 rather than trying to skip it, but override the column header.
author Farmbuyer of US-Kilrogg <farmbuyer@gmail.com>
date Fri, 03 Aug 2012 03:16:07 -0400
parents efa948aae82f
children b9897e874fac
files WhichRankDoesWhat.toc main.lua
diffstat 2 files changed, 212 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/WhichRankDoesWhat.toc	Wed Aug 01 17:15:51 2012 -0400
+++ b/WhichRankDoesWhat.toc	Fri Aug 03 03:16:07 2012 -0400
@@ -5,6 +5,8 @@
 ## Author: Farmbuyer of US-Kilrogg
 ## SavedVariables: wrdwDB
 ## OptionalDeps: Ace3, lib-st, LibFarmbuyer
+## LoadOnDemand: 1
+## LoadWith: Blizzard_GuildUI, Blizzard_GuildControlUI, Blizzard_GuildBankUI
 
 #@no-lib-strip@
 libs\LibStub\LibStub.lua
--- a/main.lua	Wed Aug 01 17:15:51 2012 -0400
+++ b/main.lua	Fri Aug 03 03:16:07 2012 -0400
@@ -42,6 +42,7 @@
 					name = L["Guild Control for non-GMs"],
 					desc = L["Make the grayed-out Guild Control button activate this addon instead."],
 					type = 'toggle',
+					width = 'double',   -- else it gets cut off
 					order = 10,
 				},
 				break1 = {
@@ -74,11 +75,15 @@
 local AceGUI = LibStub("AceGUI-3.0")
 local st_rowheight         = 25
 local st_displayed_rows    = 15 --math.floor(366/st_rowheight)
-local st_colwidth          = 65
+local st_colwidth          = 80 --65
+local cols_per_group       = 6
+local num_flagsets
 local sidetabs
 local incomplete
+local flagmap
 
--- Remove children ST widgets without explicitly Release()'ing them.
+-- Remove children ST widgets without explicitly Release()'ing them.  As there
+-- are no children other than STs, no "normal" widget resources are leaked.
 local function DisownChildren (container)
 	for i,v in ipairs(container.children) do
 		container.children[i] = nil
@@ -87,6 +92,11 @@
 	end
 end
 
+local function setstatus(txt)
+	addon.display:SetStatusText(txt)
+	addon.tooltip = #txt > 40 and txt or nil
+end
+
 
 -----------------------------------------------------------------------------
 addon = LibStub("AceAddon-3.0"):NewAddon(addon, nametag,
@@ -140,11 +150,14 @@
 		if not NUM_RANK_FLAGS then
 			UIParentLoadAddOn("Blizzard_GuildControlUI")
 		end
-		hooksecurefunc("GuildFrame_CheckPermissions", function()
+		local function noreallyitsokay()
 			GuildControlButton:Enable()
 			GuildControlButton:SetScript("OnClick", onclick)
 			GuildControlButton:SetScript("OnEnter", onenter)
-		end)
+		end
+		hooksecurefunc("GuildInfoFrame_UpdatePermissions", noreallyitsokay)
+		-- This doesn't seem to be used anymore...?
+		hooksecurefunc("GuildFrame_CheckPermissions", noreallyitsokay)
 	end
 end
 
@@ -180,12 +193,12 @@
 
 -- Something somewhere has changed, redo the cache
 do
-	local text = '|cffff1010' .. L["Guild flags have changed!"] .. '|r' ..
+	local text = '|cffff1010' .. L["Guild flags have changed!"] .. '|r  ' ..
 	             L["You must close and reopen this window to display the changes."]
 	function addon:GUILD_RANKS_UPDATE()
 		self.perms = nil
 		if (not incomplete) and self.display and self.display:IsVisible() then
-			self.display:SetStatusText(text)
+			setstatus(text)
 		end
 	end
 end
@@ -197,28 +210,46 @@
 
 	-- http://www.wowace.com/addons/lib-st/pages/set-data/minimal-dataset-format/
 	local p,v = {}, {}
+	flagmap = {}
+	num_flagsets = math.floor(NUM_RANK_FLAGS/cols_per_group + 1)
+	for flagset = 1, num_flagsets do
+		p[flagset] = {}
+	end
+
 	for r = 1, GuildControlGetNumRanks() do
 		GuildControlSetRank(r)
 
-		-- permissions
+		-- permissions (most special handling goes here)
+		-- flag 14 is no longer used
+		-- flags 15 and 16 may have numeric values not just a boolean
+		-- flag 21 is... not included yet, apparently
 		local flags = { GuildControlGetRankFlags() }
-		local row = { GuildControlGetRankName(r) }
-		for c = 1, NUM_RANK_FLAGS do if c ~= 14 then
-			local newcol = #row + 1
-			if c == 15 or c == 16 then
-				local val = GetGuildBankWithdrawGoldLimit()
-				row[newcol] = flags[c] and ((val == -1) and check or val) or ""
-			else
-				row[newcol] = flags[c] and check or ""
-			end
-		end end
-		p[r] = row
+		for flagset = 1, num_flagsets do
+			local row = { GuildControlGetRankName(r) }
+			for c_offset = 1, cols_per_group do while true do
+				local c = (flagset-1) * cols_per_group + c_offset
+				--if c == 14 or c > NUM_RANK_FLAGS then break end
+				if c > NUM_RANK_FLAGS then break end
+				local newcol = #row + 1
+				flagmap[flagset..'x'..newcol] = c
+				if c == 15 or c == 16 then
+					local val = GetGuildBankWithdrawGoldLimit()
+					row[newcol] = flags[c] and ((val == -1) and check or val) or ""
+				elseif c == 14 then
+					row[newcol] = ""
+				else
+					row[newcol] = flags[c] and check or ""
+				end
+				break
+			end end
+			p[flagset][r] = row
+		end
 
 		-- guild vault
 		local banktabs = {}
 		for t = 1, GetNumGuildBankTabs() do
 			-- isViewable, canDeposit, editText, numWithdrawals 
-			banktabs[t] = { row[1], GetGuildBankTabPermissions(t) }
+			banktabs[t] = { GuildControlGetRankName(r), GetGuildBankTabPermissions(t) }
 			banktabs[t][2] = banktabs[t][2] and check or ""
 			banktabs[t][3] = banktabs[t][3] and check or ""
 			banktabs[t][4] = banktabs[t][4] and check or ""
@@ -239,8 +270,6 @@
 end
 
 
-local function setstatus(txt)  addon.display:SetStatusText(txt)  end
-
 local make_sidetab
 do
 	local lastclicked
@@ -286,6 +315,9 @@
 		local function pick_a_tab (tab, id)
 			DisownChildren(self.display)
 			self.display:AddChild(self.vault_sts[id-offset])
+			local buttons = self.display:GetUserData("extra buttons")
+			buttons['prev']:Disable()
+			buttons['next']:Disable()
 		end
 		for t = 1, GetNumGuildBankTabs() do
 			local name, icon = GetGuildBankTabInfo(t)
@@ -301,6 +333,86 @@
 end
 
 
+-- The "closebutton" variable isn't accessible through the widget.  I should
+-- probably just constuct an entire Frame-equse thing by hand instead...  gah.
+local function FIXFRAME (container, ...)
+	for i = 1, select('#',...) do
+		local child = select(i,...)
+		if child:GetObjectType() == "Button" and child:GetText() == CLOSE then
+			container:SetUserData("close button", child)
+			return
+		end
+	end
+end
+
+local function adjust_flagset (button)
+	local key = button.button_key
+	assert (key == 'prev' or key == 'next')
+	local flagset = addon.current_main_st
+	if key == 'prev' then
+		flagset = flagset - 1
+	else
+		flagset = flagset + 1
+	end
+	return flagset
+end
+
+local function AddedButton_OnEnter (button)
+	-- not very generic, that's okay until we need to be
+	local high = adjust_flagset(button) * cols_per_group
+	local low = high - cols_per_group + 1
+	if high > NUM_RANK_FLAGS then high = NUM_RANK_FLAGS end
+	setstatus(L["Show flag columns %d - %d"]:format(low,high))
+end
+local function AddedButton_OnLeave (button)
+	setstatus("")
+end
+local function AddedButton_OnClick (button)
+	addon:DoMainST(adjust_flagset(button))
+	-- the buttons may have changed state, adjust their status text
+	if button:IsEnabled() then
+		AddedButton_OnEnter (button)
+	else
+		AddedButton_OnLeave (button)
+	end
+end
+
+local function AddButton (container, key, label)
+	assert(not tonumber(key))
+	local all = container:GetUserData("extra buttons") or {}
+	container:SetUserData("extra buttons", all)
+	local n = #all
+	local closebutton = assert(container:GetUserData("close button"), "something horrible")
+	local b = CreateFrame("Button", nil, container.frame, "UIPanelButtonTemplate")
+	b.button_key = key
+	b.obj = self
+	b:SetScript("OnClick", AddedButton_OnClick)
+	b:SetScript("OnEnter", AddedButton_OnEnter)
+	b:SetScript("OnLeave", AddedButton_OnLeave)
+	b:SetText(label)
+	b:SetHeight(20)
+	b:SetWidth(50)    -- "Close" is 100
+	b:SetPoint("BOTTOMRIGHT", closebutton, "BOTTOMLEFT", -5, 0)
+	b:Show()
+	all[n+1] = b
+	all[key] = b
+
+	for i = n, 1, -1 do
+		local ob = all[i]
+		ob:ClearAllPoints()
+		ob:SetPoint("BOTTOMRIGHT", all[i+1], "BOTTOMLEFT", -5, 0)
+	end
+	-- The Frame's statusbar is not accessible via the Frame widget itself.
+	-- Which is nice and properly encapsulated and all, but also inconvenient.
+	-- We'll take the long route there.
+	local sb = container.statustext:GetParent()
+	assert (sb.obj == container)
+	sb:ClearAllPoints()
+	sb:SetPoint("BOTTOMLEFT", 15, 15)   -- default
+	sb:SetPoint("BOTTOMRIGHT", all[1], "BOTTOMLEFT", -5, 0)
+end
+
+
 local function st_OnEnter (rowFrame, cellFrame, data, cols, row, realrow, column, sttable, button, ...)
 	if (row == nil) or (realrow == nil) then -- mouseover column header
 		setstatus(cellFrame:GetText():gsub('\n',' '))
@@ -319,38 +431,55 @@
 end
 
 
-function addon:BuildMainST (permissions, parent_frame)
+local function OnEnterStatusBar (container)
+	if not addon.tooltip then return end
+	GameTooltip:SetOwner (container.frame, "ANCHOR_RIGHT")
+	GameTooltip:ClearLines()
+	GameTooltip:AddLine (nametag)
+	GameTooltip:AddLine (addon.tooltip, 0.8, 0.8, 0.8, 1)
+	GameTooltip:Show()
+end
+
+
+function addon:BuildMainSTs (permissions, parent_frame)
+	local errtxt = "flagset %d, column %d, failed to map to a flag number"
 	-- if this language uses a trailing colon, strip it
-	local tmp = GUILDCONTROL_RANKLABEL:gsub(":$","")
-	local cols = {{
-		name = tmp,
-		width = 10 * #tmp,
-	}}
-	for i = 1, NUM_RANK_FLAGS do if i ~= 14 then
-		table.insert(cols,{
-			name = _G['GUILDCONTROL_OPTION'..i],
-			width = st_colwidth,
-		})
-	end end
+	local ranklabel = GUILDCONTROL_RANKLABEL:gsub(":$","")
+	self.main_sts = {}
 
-	local ST = LibStub("ScrollingTable"):CreateST (cols, st_displayed_rows, st_rowheight, nil, parent_frame)
-	ST:Hide()
+	for flagset = 1, #permissions do
+		local cols = {{
+			name = ranklabel,
+			width = 10 * #ranklabel,
+		}}
+		for c = #cols+1, #permissions[flagset][1] do  -- all ranks work here
+			local f = flagmap[flagset..'x'..c]
+			if not f then error(errtxt:format(flagset, c)) end
+			table.insert(cols,{
+				-- the only special handling outside BuildPerms
+				name = _G[f == 14 and 'UNUSED' or 'GUILDCONTROL_OPTION'..f],
+				width = st_colwidth,
+			})
+		end
 
-	ST:SetData(permissions, --[[minimal format=]]true)
-	ST:RegisterEvents{
-		OnEnter = st_OnEnter,
-		OnLeave = st_OnLeave,
-		OnClick = st_OnClick,
-		OnDoubleClick = st_OnClick,
-	}
+		local ST = LibStub("ScrollingTable"):CreateST (cols, st_displayed_rows, st_rowheight, --[[highlight=]]nil, parent_frame)
+		ST:Hide()
 
-	return ST
+		ST:SetData(permissions[flagset], --[[minimal format=]]true)
+		ST:RegisterEvents{
+			OnEnter = st_OnEnter,
+			OnLeave = st_OnLeave,
+			OnClick = st_OnClick,
+			OnDoubleClick = st_OnClick,
+		}
+		self.main_sts[flagset] = ST
+	end
 end
 
 function addon:BuildVaultSTs (permissions, parent_frame)
 	self.vault_sts = {}
 	local cols = {
-		self.main_st.st.cols[1],
+		self.main_sts[1].st.cols[1],
 		{ name = GUILDCONTROL_VIEW_TAB, width = 80 },
 		{ name = GUILDCONTROL_DEPOSIT_ITEMS, width = 80 },
 		{ name = GUILDCONTROL_UPDATE_TEXT, width = 80 },
@@ -358,7 +487,7 @@
 	}
 
 	for tab = 1, #permissions do
- 		local ST = LibStub("ScrollingTable"):CreateST (cols, st_displayed_rows, st_rowheight, nil, parent_frame)
+ 		local ST = LibStub("ScrollingTable"):CreateST (cols, st_displayed_rows, st_rowheight, --[[highlight=]]nil, parent_frame)
 		ST:Hide()
 		ST:SetData(permissions[tab], --[[minimal format=]]true)
 		ST:RegisterEvents{
@@ -372,6 +501,16 @@
 end
 
 
+function addon:DoMainST (index)
+	self.current_main_st = index
+	DisownChildren(self.display)
+	self.display:AddChild(self.main_sts[index])
+	local buttons = self.display:GetUserData("extra buttons")
+	buttons['prev'][index <= 1 and 'Disable' or 'Enable'](buttons['prev'])
+	buttons['next'][index >= num_flagsets and 'Disable' or 'Enable'](buttons['next'])
+end
+
+
 -- Under normal conditions, this massive wodge is built once, and then merely
 -- :Show'n and :Hide'n.  Only if info gets out of date do we release/destroy
 -- the UI elements and rebuild.
@@ -385,11 +524,16 @@
 		self.display:SetLayout("Fill")
 		self.display:EnableResize(false)
 		self.display:SetStatusTable{
-			width = (st_colwidth+4) * (NUM_RANK_FLAGS-1)  -- flag columns
+			width = (st_colwidth+4) * cols_per_group      -- flag columns
 			        + 105,                                -- rank label column
 			height = 500,
 		}
 		self.display:ApplyStatus()
+		FIXFRAME (self.display, self.display.frame:GetChildren())
+		AddButton (self.display, 'prev', "<<")
+		AddButton (self.display, 'next', ">>")
+		self.display:SetCallback("OnEnterStatusBar", OnEnterStatusBar)
+		self.display:SetCallback("OnLeaveStatusBar", GameTooltip_Hide)
 		self.display:SetCallback("OnClose", function(_d)
 			if incomplete or (not self.perms) then
 				-- stuff changed while open
@@ -401,6 +545,12 @@
 					s:SetParent(nil)   -- Blizzard does this too.  Huh.
 				end end
 				sidetabs = nil
+				for i,b in ipairs(_d:GetUserData("extra buttons")) do
+					b.obj = nil
+					b:Hide()
+					b:ClearAllPoints()
+					b:SetParent(nil)
+				end
 				AceGUI:Release(_d)
 			end
 		end)
@@ -418,23 +568,26 @@
 			s:ClearAllPoints()
 			s:SetParent(nil)   -- Blizzard does this too.  Huh.
 		end end
-		if self.main_st and self.main_st.st then
-			self.main_st:Release()
-		end
+		if self.main_sts then for i = 1, #self.main_sts do
+			if self.main_sts[i] and self.main_sts[i].st then
+				self.main_sts[i]:Release()
+			end
+		end end
 		if self.vault_sts then for i = 1, #self.vault_sts do
 			if self.vault_sts[i] and self.vault_sts[i].st then
 				self.vault_sts[i]:Release()
 			end
 		end end
-		self.main_st = nil
+		self.main_sts = nil
 		self.vault_sts = nil
 	end
-	if not self.main_st then
-		local st = self:BuildMainST (self.perms, self.display.content)
-		self.main_st = AceGUI:Create("lib-st"):WrapST(st)
-		self.main_st.head_offset = 20
-		--st_widget.tail_offset = 5
-		self.display:AddChild(self.main_st)
+	if not self.main_sts then
+		self:BuildMainSTs (self.perms, self.display.content)
+		for i,st in ipairs(self.main_sts) do
+			self.main_sts[i] = AceGUI:Create("lib-st"):WrapST(st)
+			self.main_sts[i].head_offset = 20
+		end
+		self:DoMainST(1)
 
 		self:BuildVaultSTs (self.vault, self.display.content)
 		for i,st in ipairs(self.vault_sts) do
@@ -445,8 +598,7 @@
 
 	if need_tabs or incomplete then
 		local maintab = make_sidetab(1, function (this, id)
-			DisownChildren(self.display)
-			self.display:AddChild(self.main_st)
+			self:DoMainST(self.current_main_st)
 		end)
 		maintab.tooltip = [[Rank permissions]]
 		maintab:SetChecked(true)