view main.lua @ 20:b93513c75014

Removed tag beta4
author Farmbuyer of US-Kilrogg <farmbuyer@gmail.com>
date Fri, 03 Aug 2012 15:07:00 -0400
parents 3a2beea01a28
children
line wrap: on
line source
local nametag, addon = ...
local L = LibStub("AceLocale-3.0"):GetLocale(nametag)

addon.defaults = {
	profile = {
		enable = true,
		guildcontrol = true,
	},
}


addon.options = {
	name = "",
	type = 'group',
	childGroups = 'tab',
	handler = addon,    -- functions listed as strings called as addon:func
	get = "GetOption",
	set = "SetOption",
	args = {
		general = {
			name = GENERAL,
			desc = L["General options"],
			type = 'group',
			order = 10,
			args = {
				version = {
					--name = filled in during OnInit
					type = 'description',
					fontSize = "large",
					cmdHidden = true,
					width = 'full',
					order = 1,
				},
				enable = {
					name = ENABLE,
					desc = L["Use this addon"],
					type = 'toggle',
					arg  = "ToggleEnable",
					order = 5,
				},
				guildcontrol = {
					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 = {
					name = '',
					type = 'description',
					cmdHidden = true,
					width = 'full',
					order = 14,
				},
				popup = {
					name = "/wrdw",
					desc = L["Toggle WRDW window"],
					type = 'execute',
					func = function()
						InterfaceOptionsFrameCancel:Click()
						HideUIPanel(GameMenuFrame)
						addon:BuildWindow()
					end,
					order = 15,
				},
			},
		},
		--profiles =   filled in OnInit
	},
}


-----------------------------------------------------------------------------
-- other locals
local AceGUI = LibStub("AceGUI-3.0")
local st_rowheight         = 25
local st_displayed_rows    = 15 --math.floor(366/st_rowheight)
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.  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
		v.frame:Hide()
		v.frame:ClearAllPoints()
	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,
		        "AceConsole-3.0", "AceEvent-3.0")

-- Thanks to jerry for the nifty arg idea.
function addon:SetOption (info, value)
	local name = info[#info]
	self.db.profile[name] = value
	local arg = info.arg
	if arg then self[arg](self) end
end

function addon:GetOption (info)
	local name = info[#info]
	return self.db.profile[name]
end

function addon:OnInitialize()
	self.db = LibStub("AceDB-3.0"):New("wrdwDB", self.defaults, --[[Default=]]true)

	local AceDBOptions = LibStub("AceDBOptions-3.0", true)
	if AceDBOptions then
		self.options.args.profiles = AceDBOptions:GetOptionsTable(self.db)
		self.options.args.profiles.order = 200
	end

	self.options.args.general.args.version.name =
		"|cff30adffVersion " .. (GetAddOnMetadata(nametag, "Version") or "?") .. "|r"
	LibStub("AceConfig-3.0"):RegisterOptionsTable(nametag, self.options)
	self.optionsFrame = LibStub("AceConfigDialog-3.0"):AddToBlizOptions(nametag, "WhichRankDoesWhat")
	--self.optionsFrame.okay = function() pattern_editing_safe = false end
	--self.optionsFrame.refresh = self.optionsFrame.okay
	--self.optionsFrame.cancel = self.optionsFrame.okay

	self:SetEnabledState(self.db.profile.enable)
	self.OnInitialize = nil
end


function addon:OnEnable()
	self:RegisterEvent("GUILD_RANKS_UPDATE")
	self:RegisterChatCommand("wrdw", "OnSlashCommand")

	-- Ideally, most of this stuff wouldn't be done at load time at all; this
	-- whole addon should be LoD.
	if (not IsGuildLeader()) and self.db.profile.guildcontrol then
		local function onclick() addon:BuildWindow() end
		local function onenter(this) GameTooltip_AddNewbieTip(this, GUILDCONTROL, 1.0, 1.0, 1.0, "/wrdw", 1) end
		GuildFrame_LoadUI()
		if not NUM_RANK_FLAGS then
			UIParentLoadAddOn("Blizzard_GuildControlUI")
		end
		local function noreallyitsokay()
			GuildControlButton:Enable()
			GuildControlButton:SetScript("OnClick", onclick)
			GuildControlButton:SetScript("OnEnter", onenter)
		end
		hooksecurefunc("GuildInfoFrame_UpdatePermissions", noreallyitsokay)
		-- This doesn't seem to be used anymore...?
		hooksecurefunc("GuildFrame_CheckPermissions", noreallyitsokay)
	end
end

function addon:OnDisable()
	self:Print(L["You will need to relog or /reload to fully disable this addon."])
end

function addon:ToggleEnable()
	if self.db.profile.enable then
		self:Enable()
	else
		self:Disable()
	end
end

function addon:OnSlashCommand (input)
	if not NUM_RANK_FLAGS then  -- in case a GM didn't get it loaded earlier
		GuildFrame_LoadUI()
		UIParentLoadAddOn("Blizzard_GuildControlUI")
	end
	if not input or input:trim() == "" then
		if self.display and self.display:IsShown() then
			self.display:Hide()
		else
			self:BuildWindow()
		end
	else
		--LibStub("AceConfigCmd-3.0").HandleCommand(self, "wrdw", nametag, input)
		LibStub("AceConfigDialog-3.0"):Open(nametag)
	end
end


-- Something somewhere has changed, redo the cache
do
	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
			setstatus(text)
		end
	end
end


function addon:BuildPerms()
	assert(UIParentLoadAddOn("Blizzard_GuildControlUI"))
	local check = "|TInterface\\Buttons\\UI-CheckBox-Check:"..(st_rowheight+5).."|t"

	-- 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 (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() }
		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] = { 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 ""
			local withdraw = banktabs[t][5]
			banktabs[t][5] = (withdraw == -1) and check or (withdraw == 0) and "" or withdraw
		end
		v[r] = banktabs
	end
	self.perms = p
	-- This one needs to be turned inside-out to match the data requirements
	self.vault = {}
	for t = 1, GetNumGuildBankTabs() do
		self.vault[t] = {}
		for r = 1, #v do
			self.vault[t][r] = v[r][t]
		end
	end
end


local make_sidetab
do
	local lastclicked
	local function OnClick (thistab)
		if thistab == lastclicked then return end
		for i = 1, #sidetabs do
			sidetabs[i]:SetChecked(false)
		end
		thistab:SetChecked(true)  -- should be redundant, but just in case
		lastclicked = thistab
		if thistab.callback then
			thistab:callback(thistab:GetID())
		end
	end

	-- Some magic numbers here wrt the index
	function make_sidetab (index, callback)
		if not sidetabs then
			sidetabs = {}
		end

		local tab = CreateFrame("CheckButton", "WRDWTab"..index, addon.display.frame, "SpellBookSkillLineTabTemplate", index)
		if index > 1 then
			tab:SetPoint("TOPLEFT", sidetabs[index-1], "BOTTOMLEFT", 0, -17)
		else
			tab:SetNormalTexture("Interface\\SpellBook\\GuildSpellbooktabBG")
			tab.TabardEmblem:Show()
			tab.TabardIconFrame:Show()
			SetLargeGuildTabardTextures("player", tab.TabardEmblem, tab:GetNormalTexture(), tab.TabardIconFrame)
			tab:SetPoint("TOPLEFT", addon.display.frame, "TOPRIGHT", 0, -17)
		end
		tab:SetScript("OnClick", OnClick)
		--tab:SetChecked(false)  -- is default
		tab:Show()
		tab.callback = callback
		sidetabs[index] = tab
		return tab
	end

	function addon:BuildVaultTabs()
		incomplete = nil
		local offset = 1   -- number of tabs already made
		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)
			incomplete = incomplete or icon == [[Interface\Icons\INV_Misc_QuestionMark]]
			local tab = make_sidetab(t+offset, pick_a_tab)
			tab:SetNormalTexture(icon)
			tab.tooltip = name
		end
		if incomplete then
			setstatus(L["Guild vault information is incomplete.  Be closer to a vault, and give it some time.  You may need to relog and/or open the guild roster/vault to force a client update."])
		end
	end
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',' '))
		return true
	end
	return false  -- continue with default highlighting behavior
end
local function st_OnLeave (rowFrame, cellFrame, data, cols, row, realrow, column, sttable, button, ...)
	setstatus("")
	return false  -- continue with default un-highlighting behavior
end
local function st_OnClick (rowFrame, cellFrame, data, cols, row, realrow, column, sttable, button, ...)
	if (row == nil) or (realrow == nil) then return true end  -- click column header, suppress reordering
	-- more here?
	return true  -- do not do anything further
end


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 ranklabel = GUILDCONTROL_RANKLABEL:gsub(":$","")
	self.main_sts = {}

	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

		local ST = LibStub("ScrollingTable"):CreateST (cols, st_displayed_rows, st_rowheight, --[[highlight=]]nil, parent_frame)
		ST:Hide()

		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_sts[1].st.cols[1],
		{ name = GUILDCONTROL_VIEW_TAB, width = 80 },
		{ name = GUILDCONTROL_DEPOSIT_ITEMS, width = 80 },
		{ name = GUILDCONTROL_UPDATE_TEXT, width = 80 },
		{ name = GUILDCONTROL_WITHDRAW_ITEMS, width = 150 },
	}

	for tab = 1, #permissions do
 		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{
			OnEnter = st_OnEnter,
			OnLeave = st_OnLeave,
			OnClick = st_OnClick,
			OnDoubleClick = st_OnClick,
		}
		self.vault_sts[tab] = ST
	end
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.
function addon:BuildWindow()
	local need_tabs
	if self.display then
		self.display:Hide()
	else
		self.display = AceGUI:Create("Frame")
		self.display:SetTitle("Which Rank Does What")
		self.display:SetLayout("Fill")
		self.display:EnableResize(false)
		self.display:SetStatusTable{
			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
				self.perms = nil
				self.display = nil
				if sidetabs then for i,s in ipairs(sidetabs) do
					s:Hide()
					s:ClearAllPoints()
					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)
		need_tabs = true
	end

	if not self.perms then
		need_tabs = true
		self:BuildPerms()  -- creates self.perms and self.vault
		DisownChildren(self.display)
		-- Could be new rows, fewer rows, changed tickboxes... ugh, trying to
		-- update the scrolltable is a pain.  Throw it out and start over.
		if sidetabs then for i,s in ipairs(sidetabs) do
			s:Hide()
			s:ClearAllPoints()
			s:SetParent(nil)   -- Blizzard does this too.  Huh.
		end 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_sts = nil
		self.vault_sts = nil
	end
	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
			self.vault_sts[i] = AceGUI:Create("lib-st"):WrapST(st)
			self.vault_sts[i].head_offset = 20
		end
	end

	if need_tabs or incomplete then
		local maintab = make_sidetab(1, function (this, id)
			self:DoMainST(self.current_main_st)
		end)
		maintab.tooltip = [[Rank permissions]]
		maintab:SetChecked(true)
		self:BuildVaultTabs()
	end

	self.display:Show()
	return self.display
end

-- vim:noet