view SelectorList.lua @ 64:f0450883c283

Slightly more tasteful anchoring. Only slightly.
author John@Yosemite-PC
date Mon, 26 Mar 2012 23:46:17 -0400
parents 9b1588bd4398
children dcbe1f04bb31
line wrap: on
line source
local Type, Version = "SelectorList", 34
local AceGUI = LibStub and LibStub("AceGUI-3.0",true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end

local con = LibStub("AceConsole-3.0",true)
local next, pairs, ipairs, assert, type = next, pairs, ipairs, assert, type
local math_min, math_max, floor = math.min, math.max, floor
local select, tremove, unpack, tconcat = select, table.remove, unpack, table.concat

local CreateFrame, UIParent = CreateFrame, UIParent

local new, del
do
	local pool = setmetatable({},{__mode='k'})
	function new()
		local t = next(pool)
		if t then
			pool[t] = nil
			return t
		else
			return {}
		end
	end
	function del(t)
		for k in pairs(t) do
			t[k] = nil
		end	
		pool[t] = true
	end
end

local DEFAULT_SL_WIDTH = 175
--local DEFAULT_TREE_SIZABLE = true

local function SL_OnMouseWheel(frame, delta)
	local self = frame.obj
	if self.showscroll then
		local scrollbar = self.scrollbar
		local min, max = scrollbar:GetMinMaxValues()
		local value = scrollbar:GetValue()
		local newvalue = math_min(max,math_max(min,value - delta))
		if value ~= newvalue then
			scrollbar:SetValue(newvalue)
		end
	end
end

local function OnScrollValueChanged(frame, value)
	if frame.obj.noupdate then return end
	local self = frame.obj
	local status = self.status or self.localstatus
	status.scrollvalue = value
	self:Refresh()
	AceGUI:ClearFocus()
end

local function Button_OnClick(frame)
	local self = frame.obj
	local status = self.status or self.localstatus
	if status.selected == frame.value then
	    status.selected = nil
        self:Fire("OnSelectionCleared")
	else
	    status.selected = frame.value
        self:Fire("OnSelection", frame.line)
	end
	self:Refresh()
	AceGUI:ClearFocus()
end

local function Button_OnEnter(frame)
	local self = frame.obj
	--self:Fire("OnButtonEnter", frame.uniquevalue, frame)

	if self.localstatus.enabletooltips then
		GameTooltip:SetOwner(frame, "ANCHOR_NONE")
		GameTooltip:SetPoint("BOTTOMLEFT",frame,"RIGHT")
		if frame.link then
		    GameTooltip:SetHyperlink(frame.link)
		else
		    GameTooltip:SetText(frame.text:GetText() or "", 1, .82, 0, 1)
		end

		GameTooltip:Show()
	end
end

local function Button_OnLeave(frame)
	local self = frame.obj
	--self:Fire("OnButtonLeave", frame.uniquevalue, frame)

	if self.localstatus.enabletooltips then
		GameTooltip:Hide()
	end
end

local function Layout(self)
    self:SetHeight(self.numlines * 18 + 20)

end

local function CreateButton(widget)
	local num = AceGUI:GetNextWidgetNum("TreeGroupButton")
	local button = CreateFrame("Button", ("AceGUI30TreeButton%d"):format(num), widget.slframe, "OptionsListButtonTemplate")
	button.obj = widget

	local icon = button:CreateTexture(nil, "OVERLAY")
	icon:SetWidth(14)
	icon:SetHeight(14)
	button.icon = icon

	button:SetScript("OnClick",Button_OnClick)
	button:SetScript("OnDoubleClick", Button_OnDoubleClick)
	button:SetScript("OnEnter",Button_OnEnter)
	button:SetScript("OnLeave",Button_OnLeave)

	return button
end

local function UpdateButton(button, line, selected)
	local self = button.obj
	local frame = self.frame
	local text = line.text or ""
	local icon = line.icon
	local iconCoords = line.iconCoords
	local level = line.level or 1
	local value = line.value
	local link = line.link
	local uniquevalue = line.uniquevalue
	local disabled = line.disabled
	local status = self.localstatus
	
	button.line = line
	button.value = value
	button.link = link
	button.uniquevalue = uniquevalue
	if selected and status.enableInteractive then
		button:LockHighlight()
		button.selected = true
	else
		button:UnlockHighlight()
		button.selected = false
	end
	if status.enableInteractive then
	    button:Enable()
	else
	    button:Disable()
	end
	local normalTexture = button:GetNormalTexture()
	local line = button.line
	button.level = level
	if ( level == 1 ) then
		button:SetNormalFontObject("GameFontNormal")
		button:SetHighlightFontObject("GameFontHighlight")
		button.text:SetPoint("LEFT", (icon and 16 or 0) + 8, 2)
	else
		button:SetNormalFontObject("GameFontHighlightSmall")
		button:SetHighlightFontObject("GameFontHighlightSmall")
		button.text:SetPoint("LEFT", (icon and 16 or 0) + 8 * level, 2)
	end
	
	if disabled then
		button:EnableMouse(false)
		local newText = text
		newText = newText:gsub("\124c[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F](.*)"..FONT_COLOR_CODE_CLOSE,"%1")
		button.text:SetText("|cff808080"..newText..FONT_COLOR_CODE_CLOSE)
	else
		button.text:SetText(text)
		button:EnableMouse(true)
	end
	
	if icon then
		button.icon:SetTexture(icon)
		button.icon:SetPoint("LEFT", 8 * level, (level == 1) and 0 or 1)
	else
		button.icon:SetTexture(nil)
	end
	
	if iconCoords then
		button.icon:SetTexCoord(unpack(iconCoords))
	else
		button.icon:SetTexCoord(0, 1, 0, 1)
	end
end



local methods = {

	["OnAcquire"] = function(self)
		self:SetWidth(DEFAULT_SL_WIDTH)
		self:SetNumLines()
		self:EnableButtonTooltips(false)
		self:SetInteractive(true)
	end,

	["SetNumLines"] = function(self,value)
	    if not value or value < 4 then
	        value = 4
	    end
	    self.numlines = value
	    Layout(self)
	end,

	["EnableButtonTooltips"] = function(self, enable)
		self.localstatus.enabletooltips = enable
	end,

	["SetList"] = function(self, list)
	    self.lines = {}
        for i,v in ipairs(list) do
            self.lines[i] = v
        end
		local status = self.status or self.localstatus
		status.selected = nil
		status.scrollvalue = 0
        self:Refresh()
	end,

	["SetInteractive"] = function(self, value)
	    self.localstatus.enableInteractive = value
	end,

	["ShowScroll"] = function(self, show) -- todo: not a user function. hide.
		self.showscroll = show
		if show then
			self.scrollbar:Show()
			if self.buttons[1] then
				self.buttons[1]:SetPoint("TOPRIGHT", self.slframe,"TOPRIGHT",-22,-10)
			end
		else
			self.scrollbar:Hide()
			if self.buttons[1] then
				self.buttons[1]:SetPoint("TOPRIGHT", self.slframe,"TOPRIGHT",0,-10)
			end
		end
	end,

	["Refresh"] = function(self)
	    local f = self.slframe
	    local buttons = self.buttons
	    local lines = self.lines
		local status = self.status or self.localstatus

		for i, v in ipairs(buttons) do
			v:Hide()
		end
		local numlines = #lines
		local maxlines = self.numlines

		if numlines <= maxlines then
		    status.scrollvalue = 0
		    self:ShowScroll(false)
			first, last = 1, numlines
		else
		    self:ShowScroll(true)
		    self.noupdate = true
		    self.scrollbar:SetMinMaxValues(0, numlines - maxlines)
			if numlines - status.scrollvalue < maxlines then
				status.scrollvalue = numlines - maxlines
			end
			self.noupdate = nil
			first, last = status.scrollvalue+1, status.scrollvalue + maxlines

			if self.scrollbar:GetValue() ~= status.scrollvalue then
				self.scrollbar:SetValue(status.scrollvalue)
			end
		end
        
        local bnum = 1
        for i= first, last do
            local l = lines[i]
            local b = buttons[bnum]
            if not b then
                b = CreateButton(self)
                buttons[bnum] = b
                b:SetParent(f)
                b:SetFrameLevel(f:GetFrameLevel()+1)
                b:ClearAllPoints()
                if bnum == 1 then
                    if self.showscroll then
                        b:SetPoint("TOPRIGHT",-22,-10)
                    else
                        b:SetPoint("TOPRIGHT",0,-10)
                    end
                    b:SetPoint("TOPLEFT",0,-10) 
                else
                    b:SetPoint("TOPRIGHT", buttons[bnum-1], "BOTTOMRIGHT", 0, 0)
                    b:SetPoint("TOPLEFT", buttons[bnum-1], "BOTTOMLEFT", 0, 0)
                end
            end
            UpdateButton(b, l, status.selected == l.value)
            b:Show()
            bnum = bnum + 1
        end
	end,
}









local PaneBackdrop  = {
	bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
	edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
	tile = true, tileSize = 16, edgeSize = 16,
	insets = { left = 3, right = 3, top = 5, bottom = 3 }
}

local function Constructor()
	local num = AceGUI:GetNextWidgetNum(Type)
	local frame = CreateFrame("Frame", nil, UIParent)

	local slframe = CreateFrame("Frame", nil, frame)
	slframe:SetAllPoints()
	slframe:EnableMouseWheel(true)
	slframe:SetBackdrop(PaneBackdrop)
	slframe:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
	slframe:SetBackdropBorderColor(0.4, 0.4, 0.4)
	--slframe:SetResizable(true)
	--slframe:SetMinResize(100, 1)
	--slframe:SetMaxResize(400, 1600)
	--slframe:SetScript("OnUpdate", FirstFrameUpdate)
	--slframe:SetScript("OnSizeChanged", Tree_OnSizeChanged)
	slframe:SetScript("OnMouseWheel", SL_OnMouseWheel)

	local scrollbar = CreateFrame("Slider", ("SelectorList%dScrollBar"):format(num), slframe, "UIPanelScrollBarTemplate")
	scrollbar:SetScript("OnValueChanged", nil)
	scrollbar:SetPoint("TOPRIGHT", -10, -26)
	scrollbar:SetPoint("BOTTOMRIGHT", -10, 26)
	scrollbar:SetMinMaxValues(0,0)
	scrollbar:SetValueStep(1)
	scrollbar:SetValue(0)
	scrollbar:SetWidth(16)
	scrollbar:SetScript("OnValueChanged", OnScrollValueChanged)

	local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND")
	scrollbg:SetAllPoints(scrollbar)
	scrollbg:SetTexture(0,0,0,0.4)

	local widget = {
		frame        = frame,
		lines        = {},
		buttons      = {},
		localstatus  = { 
			--groups = {}, 
		    enabletooltips= false,
		    scrollvalue = 0,
		},
		slframe      = slframe,
		scrollbar    = scrollbar,
		type         = Type
	}
	if methods then
	    for method, func in pairs(methods) do
		    widget[method] = func
	    end
    end
    slframe.obj = widget
    scrollbar.obj = widget

	return AceGUI:RegisterAsWidget(widget)
end

AceGUI:RegisterWidgetType(Type, Constructor, Version)