Files
2026-05-31 14:10:07 -04:00

4864 lines
137 KiB
Lua
Executable File

--[[
Name: Waterfall-1.0
Revision: $Revision: 78661 $
Author(s): Nargiddley (nargiddley@gmail.com)
Inspired By: Dewdrop by ckknight
Website: http://www.wowace.com/wiki/Waterfall-1.0
Documentation: http://www.wowace.com/wiki/Waterfall-1.0
SVN: http://svn.wowace.com/wowace/trunk/Waterfall-1.0
Description: Gui Configuration Library
License: LGPL 2.1
Dependencies: AceOO-2.0
]]
local MAJOR_VERSION = "Waterfall-1.0"
local MINOR_VERSION = "$Revision: 78663 $"
local CONTROL_LIMIT = 250
local _
local tinsert = table.insert
local tremove = table.remove
local table_setn = table.setn
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end
local AceOO = AceLibrary("AceOO-2.0")
local Waterfall = {}
local currentframe
local OPTIONS = "Options"
local ARROW = " -> "
local ARE_YOU_SURE = "Are you sure you want to %s?"
if GetLocale() == "zhCN" then
OPTIONS = "选项"
ARROW = " -> "
ARE_YOU_SURE = "你确定要 %s么?"
elseif GetLocale() == "zhTW" then
OPTIONS = "選項"
ARROW = " > "
ARE_YOU_SURE = "你確定要「%s」嗎?"
elseif GetLocale() == "koKR" then
OPTIONS = "설정"
ARE_YOU_SURE = "정말 당신은 `%s'|1을;를; 하시겠습니까?"
elseif GetLocale() == "ruRU" then
OPTIONS = "Опции"
ARE_YOU_SURE = "Вы уверены что вы хотите %s?"
end
local DEFAULT_CONTROL_WIDTH = 180
--[[
local print = Sea.io.print
local function printTable(table,rowname,level)
if ( level == nil ) then level = 1; end
if ( type(rowname) == "nil" ) then rowname = "ROOT";
elseif ( type(rowname) == "string" ) then
rowname = "\""..rowname.."\"";
elseif ( type(rowname) ~= "number" ) then
rowname = "*"..type(rowname).."*";
end
local msg = "";
if ( table == nil ) then
Sea.io.print(msg,"[",rowname,"] := nil "); return
end
if ( type(table) == "table" and level > 0 ) then
Sea.io.print (msg,rowname," { ");
for k,v in table do
if v == nil then Sea.io.print(msg,"[",rowname,"] := nil "); end
printTable(v,k,level-1);
end
Sea.io.print(msg,"}");
elseif (type(table) == "function" ) then
Sea.io.print(msg,"[",rowname,"] => {{FunctionPtr*}}");
elseif (type(table) == "userdata" ) then
Sea.io.print(msg,"[",rowname,"] => {{UserData}}");
elseif (type(table) == "boolean" ) then
local value = "true";
if ( not table ) then
value = "false";
end
Sea.io.print(msg,"[",rowname,"] => ",value);
else
Sea.io.print(msg,"[",rowname,"] => ",table);
end
end
]]
--[[
Passing an AceOO class will get an object of that class from the pool
You dont need to specify the class when releasing it
Passing a string will get a table from a named pool
the string must be passed when releasing tables like this
--]]
local getObj, releaseObj
do
local objPools = {}
function getObj(class,...)
if not objPools[class] then
objPools[class] = {}
end
local newObj = tremove(objPools[class])
if not newObj then
if type(class) ~= "string" and type(class.new) == "function" then
newObj = class:new(unpack(arg))
else
newObj = {}
end
end
return newObj
end
function releaseObj(obj,class)
if not class then
class = obj.class
end
if not class then error("You must supply a class to release non AceOO objects") end
if not objPools[class] then
objPools[class] = {}
end
if type(obj.CleanUp) == "function" then
obj:CleanUp()
end
tinsert(objPools[class],obj)
end
end
--[[
--borrowed from Dewdrop-2.0
local function new(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20)
local t = {}
if k1 then t[k1] = v1
if k2 then t[k2] = v2
if k3 then t[k3] = v3
if k4 then t[k4] = v4
if k5 then t[k5] = v5
if k6 then t[k6] = v6
if k7 then t[k7] = v7
if k8 then t[k8] = v8
if k9 then t[k9] = v9
if k10 then t[k10] = v10
if k11 then t[k11] = v11
if k12 then t[k12] = v12
if k13 then t[k13] = v13
if k14 then t[k14] = v14
if k15 then t[k15] = v15
if k16 then t[k16] = v16
if k17 then t[k17] = v17
if k18 then t[k18] = v18
if k19 then t[k19] = v19
if k20 then t[k20] = v20
end end end end end end end end end end end end end end end end end end end end
return t
end
local tmp
do
local t
function tmp(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20)
for k in pairs(t) do
t[k] = nil
end
if type(k1) == "table" then
for k,v in pairs(k1) do
t[k] = v
end
else
if k1 then t[k1] = v1
if k2 then t[k2] = v2
if k3 then t[k3] = v3
if k4 then t[k4] = v4
if k5 then t[k5] = v5
if k6 then t[k6] = v6
if k7 then t[k7] = v7
if k8 then t[k8] = v8
if k9 then t[k9] = v9
if k10 then t[k10] = v10
if k11 then t[k11] = v11
if k12 then t[k12] = v12
if k13 then t[k13] = v13
if k14 then t[k14] = v14
if k15 then t[k15] = v15
if k16 then t[k16] = v16
if k17 then t[k17] = v17
if k18 then t[k18] = v18
if k19 then t[k19] = v19
if k20 then t[k20] = v20
end end end end end end end end end end end end end end end end end end end end
end
return t
end
local x = tmp
function tmp(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20)
t = {}
tmp = x
x = nil
return tmp(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20)
end
end
local tmp2
do
local t
function tmp2(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20)
for k in pairs(t) do
t[k] = nil
end
if k1 then t[k1] = v1
if k2 then t[k2] = v2
if k3 then t[k3] = v3
if k4 then t[k4] = v4
if k5 then t[k5] = v5
if k6 then t[k6] = v6
if k7 then t[k7] = v7
if k8 then t[k8] = v8
if k9 then t[k9] = v9
if k10 then t[k10] = v10
if k11 then t[k11] = v11
if k12 then t[k12] = v12
if k13 then t[k13] = v13
if k14 then t[k14] = v14
if k15 then t[k15] = v15
if k16 then t[k16] = v16
if k17 then t[k17] = v17
if k18 then t[k18] = v18
if k19 then t[k19] = v19
if k20 then t[k20] = v20
end end end end end end end end end end end end end end end end end end end end
return t
end
local x = tmp2
function tmp2(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20)
t = {}
tmp2 = x
x = nil
return tmp2(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10, k11, v11, k12, v12, k13, v13, k14, v14, k15, v15, k16, v16, k17, v17, k18, v18, k19, v19, k20, v20)
end
end
]]
local function new(...)
local t = {}
for i = 1, table.getn(arg), 2 do
local k = arg[i]
if k then
t[k] = arg[i+1]
else
break
end
end
return t
end
local tmp
do
local t = {}
function tmp(...)
for k in pairs(t) do
t[k] = nil
end
table_setn(t,0)
for i = 1, table.getn(arg), 2 do
local k = arg[i]
if k then
t[k] = arg[i+1]
else
break
end
end
return t
end
end
local tmp2
do
local t = {}
function tmp2(...)
for k in pairs(t) do
t[k] = nil
end
table_setn(t,0)
for i = 1, table.getn(arg), 2 do
local k = arg[i]
if k then
t[k] = arg[i+1]
else
break
end
end
return t
end
end
local function getArgs(t, str, num, ...)
local x = t[str .. num]
if x == nil then
return unpack(arg)
else
return x, getArgs(t, str, num + 1, unpack(arg))
end
end
local function confirmPopup(message, func, ...)
if not StaticPopupDialogs["WATERFALL01_CONFIRM_DIALOG"] then
StaticPopupDialogs["WATERFALL01_CONFIRM_DIALOG"] = {}
end
local t = StaticPopupDialogs["WATERFALL01_CONFIRM_DIALOG"]
for k in pairs(t) do
t[k] = nil
end
table_setn(t,0)
t.text = message
t.button1 = ACCEPT
t.button2 = CANCEL
t.OnAccept = function()
func(unpack(t))
end
for i = 1, table.getn(arg) do
t[i] = arg[i]
end
t.timeout = 0
t.whileDead = 1
t.hideOnEscape = 1
StaticPopup_Show("WATERFALL01_CONFIRM_DIALOG")
end
local function showGameTooltip(this)
if this.tooltipTitle or this.tooltipText then
GameTooltip_SetDefaultAnchor(GameTooltip, this.frame or this)
if this.tooltipTitle then
GameTooltip:SetText(this.tooltipTitle, 1, 1, 1, 1)
if this.tooltipText then
GameTooltip:AddLine(this.tooltipText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
end
else
GameTooltip:SetText(this.tooltipText, 1, 1, 1, 1)
end
GameTooltip:Show()
end
end
--end of borrowing
local function parseList(list)
local token, rest = string.match(list,"([^%s]+)%s+(.+)")
if not rest then
return (tonumber(list) or list)
else
return (tonumber(token) or token), parseList(rest)
end
end
local function compareOptions(a,b)
if not a then
return true
end
if not b then
return false
end
local A, B = a.order or 100, b.order or 100
if A == B then
local NameA = a.guiName or a.name or ""
local NameB = b.guiName or b.name or ""
return string.upper(NameA) < string.upper(NameB)
end
if A < 0 then
if B > 0 then
return false
end
else
if B < 0 then
return true
end
end
return A < B
end
function Waterfall:Register(id,...)
local settings = new(unpack(arg))
if settings.aceOptions then
assert(type(settings.aceOptions) == "table","\"aceOptions\" must be a table")
else
assert(type(settings.tree) == "table","\"tree\" must be a table")
assert(type(settings.children) == "function","\"children\" must be a function")
end
if not settings.title then
settings.title = id
end
if settings.treeType == "SECTIONS" then
settings.hideTreeRoot = true
settings.treeLevels = 3
end
if self.registry[id] then
self:UnRegister(id)
end
self.registry[id] = settings
end
function Waterfall:UnRegister(id)
self.registry[id] = nil
end
function Waterfall:IsRegistered(id)
return not not self.registry[id]
end
local function releaseTree(tree)
for i, v in ipairs(tree) do
tree[i] = nil
releaseTree(v)
releaseObj(v,"table")
end
for k, v in pairs(tree) do
tree[k] = nil
end
table_setn(tree,0)
end
local function checkNegatable(attr,handler,param)
local ret
if type(attr) == "function" then
ret = attr(param)
elseif type(attr) == "string" and handler then
local neg = string.match(attr,"^~(.+)$")
if neg then
attr = neg
end
ret = handler[attr](handler,param)
if neg then
ret = not ret
end
else
ret = attr
end
return ret
end
local mysort = function(a, b)
local alpha, bravo = a, b
local alpha_order = alpha and alpha.order or 100
local bravo_order = bravo and bravo.order or 100
local alpha_name = alpha and (alpha.guiName or alpha.name)
local bravo_name = bravo and (bravo.guiName or bravo.name)
if alpha_order == bravo_order then
if not alpha_name then
return bravo_name
elseif not bravo_name then
return false
else
return string.upper(string.gsub(string.gsub(alpha_name,"|c%x%x%x%x%x%x%x%x", ""), "|r", "")) < string.upper(string.gsub(string.gsub(bravo_name,"|c%x%x%x%x%x%x%x%x", ""),"|r", ""))
end
else
if alpha_order < 0 then
if bravo_order > 0 then
return false
end
else
if bravo_order < 0 then
return true
end
end
return alpha_order < bravo_order
end
end
local function buildAceOptionsTree(tree, status, options, numLevels, path, rootHandler)
local settings = Waterfall.registry[currentframe.id]
local handler = options.handler or rootHandler
local bargs = options.args
assert(type(bargs) == "table",string.format("args must be a table: Current Path:%s",(path or ".")))
local root
if path then
tree.id = path
tree.text = options.guiName or options.name or (options.handler and options.handler.name) or path
tree.name = tree.text
tree.tooltipTitle = tree.text
tree.tooltipText = options.desc
tree.order = options.order
tree.disabled = checkNegatable(options.disabled, handler, options.passValue)
tree.handler = handler
tree.icon = options.icon
tree.hidden = checkNegatable(options.wfHidden or options.guiHidden or options.hidden,handler, options.passValue)
local hasOptions
for k, item in pairs(bargs) do
if item.type ~= "group" and item.type ~= "heading" then
if not checkNegatable(item.wfHidden or item.guiHidden or item.hidden,handler, item.passValue) then
hasOptions = true
end
end
end
tree.hasOptions = hasOptions
else
releaseTree(tree)
local hasOptions
for k, item in pairs(bargs) do
if item.type ~= "group" and item.type ~= "heading" then
hasOptions = true
end
end
if hasOptions then
root = getObj("table")
root.text = options.guiName or options.name or (options.handler and options.handler.name) or path
root.name = tree.text
root.tooltipTitle = tree.text
root.tooltipText = options.desc
root.order = options.order
root.disabled = checkNegatable(options.disabled, handler, options.passValue)
root.handler = handler
root.icon = options.icon
root.hidden = checkNegatable(options.wfHidden or options.guiHidden or options.hidden,handler, options.passValue)
root.id = "."
root.hasOptions = true
if status['.'] == nil then
status['.'] = true
end
tinsert(tree,root)
if not settings.hideTreeRoot then
tree = root
end
end
settings.treeRootShown = hasOptions and not settings.hideTreeRoot
end
if not numLevels or numLevels > 1 then
for k, item in pairs(bargs) do
if item.type == "group" then
local child = getObj("table")
local nextPath
if path then
nextPath = path.."."..k
else
nextPath = k
end
if numLevels then
buildAceOptionsTree(child, status, item,numLevels - 1,nextPath, handler)
else
buildAceOptionsTree(child, status, item,nil,nextPath, handler)
end
tinsert(tree,child)
end
end
end
table.sort(tree, mysort)
-- table.sort(tree,compareOptions)
end
local function checkAceOptionsPath(path, options, frame)
local t = options
local validpath
for k in string.gfind(path,"[^\.]+") do
if tonumber(k) and t.args[tonumber(k)] then
k = tonumber(k)
end
if t.args and t.args[k] then
t = t.args[k]
if validpath then
validpath = validpath..'.'..k
else
validpath = k
end
else
if frame then
frame:SetSelected(validpath, true)
end
break
end
end
return validpath or '.'
end
local function feedFromOptionsTree(paneid, options)
if not paneid then return end
local settings = Waterfall.registry[currentframe.id]
paneid = checkAceOptionsPath(paneid, options, settings.frame)
local curlevel = 1
local levels = 1
for x in string.gfind(paneid,"[^%.]+") do
curlevel = curlevel + 1
end
if settings.treeLevels == curlevel then
levels = nil
end
if paneid == "." then
Waterfall:FeedAceOptionsTable(options, nil, levels)
return options.name or (options.handler and options.handler.name) or OPTIONS
else
local crumbs
if settings.treeRootShown then
crumbs = options.name or (options.handler and options.handler.name) or OPTIONS
end
local t = options
Waterfall:FeedAceOptionsTable(options,paneid,levels)
for k in string.gfind(paneid,"[^\.]+") do
if tonumber(k) and t.args[tonumber(k)] then
k = tonumber(k)
end
if t.args and t.args[k] then
t = t.args[k]
if crumbs then
crumbs = crumbs..ARROW..(t.guiName or t.name or "")
else
crumbs = (t.guiName or t.name or "")
end
else
Waterfall:error("Invalid path \"%s\" for Aceoptions table",paneid)
end
end
return crumbs
end
end
local old_CloseSpecialWindows
function Waterfall:Open(id, pane)
if not old_CloseSpecialWindows then
old_CloseSpecialWindows = CloseSpecialWindows
CloseSpecialWindows = function()
local found = old_CloseSpecialWindows()
return self:CloseAll() or found
end
end
local info = self.registry[id]
if not info then
error("You cannot open a waterfall without registering it first")
end
--already open
if info.frame then
if pane then
info.frame:SetSelected(pane)
end
return
end
local frame = getObj(WaterfallFrame) --WaterfallFrame:new()
frame:SetID(id)
frame.lib = self
info.frame = frame
if info.title then
frame:SetTitle(info.title)
end
local r,g,b = info.colorR or 1, info.colorG or 0.6, info.colorB or 0
frame:SetColor(r,g,b)
if info.aceOptions then
if not info.tree then
info.tree = {}
end
if not info.treestatus then
info.treestatus = {}
end
currentframe = frame
frame:SetTree(info.tree, info.treestatus, buildAceOptionsTree, info.aceOptions, info.treeLevels)
currentframe = nil
frame:SetChildren(feedFromOptionsTree, info.aceOptions)
if pane then
frame.treeview:Collapse()
end
frame:SetSelected(pane or info.defaultPane or ".")
frame.treeview:SetType(info.treeType)
else
if not info.treestatus then
info.treestatus = {}
end
frame:SetTree(info.tree, info.treestatus)
frame:SetChildren(info.children)
if pane or info.defaultPane then
frame:SetSelected(pane or info.defaultPane)
end
frame.treeview:SetType(info.treeType)
end
if info.height then
frame:SetHeight(info.height)
end
if info.width then
frame:SetWidth(info.width)
end
frame:Refresh()
frame:Show()
end
function Waterfall:IsOpen(id)
return not not self.registry[id].frame
end
function Waterfall:Refresh(id)
local info = self.registry[id]
if not info then
error("You can't refresh a waterfall without registering it first")
end
if info.frame then
info.frame:Refresh()
end
end
function Waterfall:SetSize(id, width, height)
local info = self.registry[id]
if not info then
error("You refresh open a waterfall without registering it first")
end
if info.frame then
info.frame:SetWidth(width)
info.frame:SetHeight(height)
end
end
local function setCommonAttributes(control,info)
control.width = info.width
control.height = info.height
control.noNewLine = info.noNewLine
control.causesRefresh = info.causesRefresh
control.fullRefresh = info.fullRefresh
control.treeRefresh = info.treeRefresh
control.tooltipTitle = info.tooltipTitle
control.tooltipText = info.tooltipText
control:SetText(info.text or "")
end
function Waterfall:AddControl(...)
currentframe.controlcount = currentframe.controlcount + 1
if not currentframe then
error("AddControl must be called from within a children function")
end
local control
local info = self.registry[currentframe.id]
local limit = info.controlLimit or CONTROL_LIMIT
if currentframe.controlcount > limit then
if currentframe.controlcount == limit + 1 then
control = getObj(WaterfallLabel)
control.r = 1
control.g = 0
control.b = 0
control:SetText(("More than %s Controls in current pane....."):format(limit))
control:Refresh()
currentframe:AddControl(control)
end
return
end
local info = tmp2(unpack(arg))
if info.type == "label" then
control = getObj(WaterfallLabel)
setCommonAttributes(control,info)
control.justifyH = info.justifyH
control.r = info.r
control.g = info.g
control.b = info.b
control:Refresh()
elseif info.type == "dragLink" then
control = getObj(WaterfallDragLink)
setCommonAttributes(control,info)
control:SetFunc("set",info.setFunc,getArgs(info,"setArg",1))
control:SetFunc("get",info.getFunc,getArgs(info,"getArg",1))
if type(info.disabled) == "function" then
control:SetFunc("disabled",info.disabled,getArgs(info,"disabledArg",1))
control.inverseDisabled = info.inverseDisabled
else
control.disabled = info.disabled
end
control:Refresh()
elseif info.type == "linklabel" then
control = getObj(WaterfallLinklabel)
setCommonAttributes(control,info)
control.justifyH = info.justifyH
control.r = info.r
control.g = info.g
control.b = info.b
control:SetFunc("link",info.linkFunc,getArgs(info,"linkArg",1))
if type(info.disabled) == "function" then
control:SetFunc("disabled",info.disabled,getArgs(info,"disabledArg",1))
control.inverseDisabled = info.inverseDisabled
else
control.disabled = info.disabled
end
control.confirm = info.confirm
control:Refresh()
elseif info.type == "button" then
control = getObj(WaterfallButton)
setCommonAttributes(control,info)
control:SetFunc("exec",info.execFunc,getArgs(info,"execArg",1))
if type(info.disabled) == "function" then
control:SetFunc("disabled",info.disabled,getArgs(info,"disabledArg",1))
control.inverseDisabled = info.inverseDisabled
else
control.disabled = info.disabled
end
control.confirm = info.confirm
control.link = info.link
control:Refresh()
elseif info.type == "heading" then
control = getObj(WaterfallHeading)
control.justifyH = info.justifyH
setCommonAttributes(control,info)
control:Refresh()
elseif info.type == "textbox" then
control = getObj(WaterfallTextBox)
setCommonAttributes(control,info)
control:SetFunc("set",info.setFunc,getArgs(info,"setArg",1))
control:SetFunc("get",info.getFunc,getArgs(info,"getArg",1))
control:SetFunc("changed",info.changedFunc,getArgs(info,"changedArg",1))
if type(info.disabled) == "function" then
control:SetFunc("disabled",info.disabled,getArgs(info,"disabledArg",1))
control.inverseDisabled = info.inverseDisabled
else
control.disabled = info.disabled
end
control.toNumber = info.toNumber
control.parseList = info.parseList
control.setOnTextChanged = info.setOnTextChanged
control:SetFunc("validate",info.validateFunc,getArgs(info,"validateArg",1))
control.validateModifies = info.validateModifies
control:Refresh()
elseif info.type == "dropdown" then
control = getObj(WaterfallDropdown)
setCommonAttributes(control,info)
control:SetFunc("set",info.setFunc,getArgs(info,"setArg",1))
control:SetFunc("get",info.getFunc,getArgs(info,"getArg",1))
if type(info.disabled) == "function" then
control:SetFunc("disabled",info.disabled,getArgs(info,"disabledArg",1))
control.inverseDisabled = info.inverseDisabled
else
control.disabled = info.disabled
end
control.parseList = info.parseList
control.list = info.list
control.columns = info.columns
control.strict = info.strict
control:Refresh()
elseif info.type == "checkbox" then
control = getObj(WaterfallCheckBox)
setCommonAttributes(control,info)
control:SetChecked(info.checked)
control.isRadio = info.isRadio
control:SetFunc("set",info.setFunc,getArgs(info,"setArg",1))
control:SetFunc("get",info.getFunc,getArgs(info,"getArg",1))
if type(info.disabled) == "function" then
control:SetFunc("disabled",info.disabled,getArgs(info,"disabledArg",1))
control.inverseDisabled = info.inverseDisabled
else
control.disabled = info.disabled
end
control:Refresh()
elseif info.type == "slider" then
control = getObj(WaterfallSlider)
setCommonAttributes(control,info)
control:SetFunc("set",info.setFunc,getArgs(info,"setArg",1))
control:SetFunc("get",info.getFunc,getArgs(info,"getArg",1))
control.min = info.min
control.max = info.max
control.step = info.step
control.bigStep = info.bigStep or info.step
control.finalSetOnly = info.finalSetOnly
if type(info.disabled) == "function" then
control:SetFunc("disabled",info.disabled,getArgs(info,"disabledArg",1))
control.inverseDisabled = info.inverseDisabled
else
control.disabled = info.disabled
end
control:Refresh()
elseif info.type == "color" then
control = getObj(WaterfallColorSwatch)
setCommonAttributes(control,info)
control:SetFunc("set",info.setFunc,getArgs(info,"setArg",1))
control:SetFunc("get",info.getFunc,getArgs(info,"getArg",1))
if type(info.disabled) == "function" then
control:SetFunc("disabled",info.disabled,getArgs(info,"disabledArg",1))
control.inverseDisabled = info.inverseDisabled
else
control.disabled = info.disabled
end
control.hasOpacity = info.hasOpacity
control.r = info.r
control.g = info.g
control.b = info.b
control.opacity = info.opacity
control.hasOpacity = info.hasOpacity
control:Refresh()
elseif info.type == "keybind" then
control = getObj(WaterfallKeybinding)
control:SetText("Binding")
setCommonAttributes(control,info)
control:SetFunc("set",info.setFunc,getArgs(info,"setArg",1))
control:SetFunc("get",info.getFunc,getArgs(info,"getArg",1))
if type(info.disabled) == "function" then
control:SetFunc("disabled",info.disabled,getArgs(info,"disabledArg",1))
control.inverseDisabled = info.inverseDisabled
else
control.disabled = info.disabled
end
control.keybindingOnly = info.keybindingOnly
control.keybindingExcept = info.keybindingExcept
control:Refresh()
else
error("Invalid or missing type")
end
currentframe:AddControl(control)
end
local function addDisabled(t,disabled,handler,param)
if disabled then
if type(disabled) == "function" or type(disabled) == "boolean" then
tinsert(t,"disabled")
tinsert(t,disabled)
if param then
tinsert(t,"disabledArg1")
tinsert(t,param)
end
elseif type(disabled) == "string" then
local neg = string.match(disabled,"^~(.+)$")
if neg then
disabled = neg
end
if handler and handler[disabled] then
tinsert(t,"disabled")
tinsert(t,handler[disabled])
tinsert(t,"disabledArg1")
tinsert(t,handler)
if param then
tinsert(t,"disabledArg2")
tinsert(t,param)
end
end
if neg then
tinsert(t,"inverseDisabled")
tinsert(t,true)
end
end
end
end
local function appendArgs(t,name,start,...)
for k = 1 , table.getn(arg) do
tinsert(t,name.."Arg"..(start + k - 1))
tinsert(t,arg[k])
end
end
local function addFunction(t,name,func,handler,...)
if type(func) == "function" then
tinsert(t,name.."Func")
tinsert(t,func)
appendArgs(t,name,1,unpack(arg))
elseif type(func) == "string" and handler and handler[func] then
tinsert(t,name.."Func")
tinsert(t,handler[func])
tinsert(t,name.."Arg1")
tinsert(t,handler)
appendArgs(t,name,2,unpack(arg))
end
end
local function validateRange(min,max,step,value)
value = tonumber(value)
if step > 0 then
value = math.floor((value - min) / step + 0.5) * step + min
end
if value >= min and value <= max then
return value
else
return nil
end
end
--[[
Feeds an ace options table into the right pane, must be called within a "children" function
root is the root of your options table, this is important if you use any methods for resolving the handler
path is the path into the table seperated by "." e.g. "Items.Compress" to feed the table given by root.args.Items.args.Compress
maxLevels is how many sub groups to feed as well, 1 is only the current level 2 will feed sub groups etc. nil assumes no limit
]]
function Waterfall:FeedAceOptionsTable(root,path,maxLevels)
local feedtmp = getObj("table")
local feedkeys = getObj("table")
local tmpargs = getObj("table")
local t
local handler = root.handler
local groupDisabled = checkNegatable(root.disabled,root.handler,root.passValue)
local passSet
local passGet
if root.pass then
passSet = root.set
passGet = root.get
else
passSet = nil
passGet = nil
end
if path then
t = root
for k in string.gfind(path,"[^\.]+") do
if tonumber(k) and t.args[tonumber(k)] then
k = tonumber(k)
end
if t.args and t.args[k] then
t = t.args[k]
handler = t.handler or handler
groupDisabled = checkNegatable(t.disabled,handler,t.passValue) or groupDisabled
if t.pass then
passSet = t.set
passGet = t.get
else
passSet = nil
passGet = nil
end
else
self:error("Invalid path \"%s\" for Aceoptions table",path)
end
end
else
t = root
end
if t.type ~= "group" then
self:error("You must feed an ace options group")
end
for k, v in pairs(t.args) do
tinsert(feedtmp, v)
feedkeys[v] = k
end
table.sort(feedtmp, mysort)
local lastheader
for i, v in ipairs(feedtmp) do
--only add headers if they arent immediately followed by a group
if lastheader then
if v.type ~= "group" then
--self:AddControl("type","label","text","","width",80)
--self:AddControl("type","heading","text",lastheader,"width",DEFAULT_CONTROL_WIDTH,"justifyH","CENTER","noNewLine",true)
self:AddControl("type","heading","text",lastheader,"width",DEFAULT_CONTROL_WIDTH,"justifyH","CENTER")
end
lastheader = nil
end
local hidden
if v.guiHidden ~= nil then
hidden = v.guiHidden
elseif v.wfHidden ~= nil then
hidden = v.wfHidden
else
hidden = v.hidden
end
hidden = checkNegatable(hidden,v.handler or handler,v.passValue)
local name = v.guiName or v.name
if name and ( checkNegatable(v.disabled,v.handler or handler,v.passValue) or groupDisabled ) then
name = "|cFF808080"..name
end
if not hidden then
if v.type == "toggle" then
--self:AddControl("type","label","text","","width",80)
tinsert(tmpargs,"type")
tinsert(tmpargs,"checkbox")
--tinsert(tmpargs,"noNewLine")
--tinsert(tmpargs,true)
tinsert(tmpargs,"text")
tinsert(tmpargs,name)
tinsert(tmpargs,"tooltipTitle")
tinsert(tmpargs,name)
tinsert(tmpargs,"tooltipText")
tinsert(tmpargs,v.desc or false)
tinsert(tmpargs,"isRadio")
tinsert(tmpargs,not not v.isRadio)
if passGet and v.get == nil then
addFunction(tmpargs,"get",passGet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"get",v.get,v.handler or handler,v.passValue)
end
if passSet and v.set == nil then
addFunction(tmpargs,"set",passSet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"set",v.set,v.handler or handler,v.passValue)
end
addDisabled(tmpargs,groupDisabled or v.disabled,v.handler or handler,v.passValue)
tinsert(tmpargs,"fullRefresh")
tinsert(tmpargs,true)
self:AddControl(unpack(tmpargs))
elseif v.type == "dragLink" then
tinsert(tmpargs,"type")
tinsert(tmpargs,"dragLink")
tinsert(tmpargs,"text")
tinsert(tmpargs,name)
tinsert(tmpargs,"tooltipText")
tinsert(tmpargs,v.desc or false)
tinsert(tmpargs,"tooltipTitle")
local tooltipTitle = "" .. tostring(v.itemId)
tinsert(tmpargs,tooltipTitle)
tinsert(tmpargs,"linkInfo")
tinsert(tmpargs,v.linkInfo or {})
tinsert(tmpargs,"icon")
tinsert(tmpargs,v.icon or "")
tinsert(tmpargs,"iconWidth")
tinsert(tmpargs,v.iconWidth or WaterfallDragLink.defaultIconSize)
tinsert(tmpargs,"iconHeight")
tinsert(tmpargs,v.iconHeight or WaterfallDragLink.defaultIconSize)
if passGet and v.get == nil then
addFunction(tmpargs,"get",passGet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"get",v.get,v.handler or handler,v.passValue)
end
if passSet and v.set == nil then
addFunction(tmpargs,"set",passSet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"set",v.set,v.handler,v.passValue)
end
addDisabled(tmpargs,groupDisabled or v.disabled,v.handler or handler,v.passValue)
self:AddControl(unpack(tmpargs))
elseif v.type == "group" then
if not maxLevels or maxLevels > 1 then
--self:AddControl("type","label","text","","width",80)
if checkNegatable(v.disabled,v.handler or handler,v.passValue) or groupDisabled then
name = "|cFF808080"..name
end
--self:AddControl("type","heading","text",name,"width",DEFAULT_CONTROL_WIDTH,"justifyH","CENTER","noNewLine",true)
self:AddControl("type","heading","text",name,"width",DEFAULT_CONTROL_WIDTH,"justifyH","CENTER")
local nextPath
local nextMaxLevels
if path then
nextPath = path.."."..feedkeys[v]
else
nextPath = feedkeys[v]
end
if maxLevels then
nextMaxLevels = maxLevels - 1
end
self:FeedAceOptionsTable(root,nextPath,nextMaxLevels)
self:AddControl("type","heading")
end
elseif v.type == "text" then
if type(v.validate) == "table" then
if v.multiToggle then
self:AddControl("type","heading","text",name)
for key, value in pairs(v.validate) do
if type(key) == "number" then
key = value
end
self:AddControl("type","label","text","","width",12)
tinsert(tmpargs,"type")
tinsert(tmpargs,"checkbox")
tinsert(tmpargs,"text")
tinsert(tmpargs,value)
tinsert(tmpargs,"noNewLine")
tinsert(tmpargs,true)
tinsert(tmpargs,"tooltipTitle")
tinsert(tmpargs,name)
tinsert(tmpargs,"tooltipText")
tinsert(tmpargs,value)
if v.passValue then
if passGet and v.get == nil then
addFunction(tmpargs,"get",passGet,v.handler or handler,v.passValue or feedkeys[v],key)
else
addFunction(tmpargs,"get",v.get,v.handler or handler,v.passValue,key)
end
if passSet and v.set == nil then
addFunction(tmpargs,"set",passSet,v.handler or handler,v.passValue or feedkeys[v],key)
else
addFunction(tmpargs,"set",v.set,v.handler or handler,v.passValue,key)
end
else
if passGet and v.get == nil then
addFunction(tmpargs,"get",passGet,v.handler or handler,feedkeys[v],key)
else
addFunction(tmpargs,"get",v.get,v.handler or handler,key)
end
if passSet and v.set == nil then
addFunction(tmpargs,"set",passSet,v.handler or handler,feedkeys[v],key)
else
addFunction(tmpargs,"set",v.set,v.handler or handler,key)
end
end
addDisabled(tmpargs,groupDisabled or v.disabled,v.handler or handler,v.passValue,key)
tinsert(tmpargs,"fullRefresh")
tinsert(tmpargs,true)
self:AddControl(unpack(tmpargs))
for i = 0,table.getn(tmpargs) do
tmpargs[i] = nil
end
end
else
--self:AddControl("type","label","text",name,"width",80,"justifyH","RIGHT")
self:AddControl("type","label","text",name)
tinsert(tmpargs,"type")
tinsert(tmpargs,"dropdown")
tinsert(tmpargs,"strict")
tinsert(tmpargs,true)
--tinsert(tmpargs,"noNewLine")
--tinsert(tmpargs,true)
tinsert(tmpargs,"tooltipTitle")
tinsert(tmpargs,name)
tinsert(tmpargs,"tooltipText")
tinsert(tmpargs,v.desc or false)
if passGet and v.get == nil then
addFunction(tmpargs,"get",passGet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"get",v.get,v.handler or handler,v.passValue)
end
if passSet and v.set == nil then
addFunction(tmpargs,"set",passSet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"set",v.set,v.handler or handler,v.passValue)
end
addDisabled(tmpargs,groupDisabled or v.disabled,v.handler or handler,v.passValue)
tinsert(tmpargs,"list")
tinsert(tmpargs,v.validate)
tinsert(tmpargs,"columns")
tinsert(tmpargs,v.columns)
tinsert(tmpargs,"parseList")
tinsert(tmpargs, not not v.input)
tinsert(tmpargs,"fullRefresh")
tinsert(tmpargs,true)
self:AddControl(unpack(tmpargs))
end
elseif v.validate == "keybinding" then
--self:AddControl("type","label","text",name,"width",80,"justifyH","RIGHT")
self:AddControl("type","label","text",name)
tinsert(tmpargs,"type")
tinsert(tmpargs,"keybind")
--tinsert(tmpargs,"noNewLine")
--tinsert(tmpargs,true)
if passGet and v.get == nil then
addFunction(tmpargs,"get",passGet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"get",v.get,v.handler or handler,v.passValue)
end
if passSet and v.set == nil then
addFunction(tmpargs,"set",passSet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"set",v.set,v.handler or handler,v.passValue)
end
tinsert(tmpargs,"keybindingOnly")
tinsert(tmpargs,v.keybindingOnly or false)
tinsert(tmpargs,"keybindingExcept")
tinsert(tmpargs,v.keybindingExcept or false)
tinsert(tmpargs,"tooltipTitle")
tinsert(tmpargs,name)
tinsert(tmpargs,"tooltipText")
tinsert(tmpargs,v.desc or false)
tinsert(tmpargs,"fullRefresh")
tinsert(tmpargs,true)
self:AddControl(unpack(tmpargs))
else
--self:AddControl("type","label","text",name,"width",80,"justifyH","RIGHT")
self:AddControl("type","label","text",name)
tinsert(tmpargs,"type")
tinsert(tmpargs,"textbox")
--tinsert(tmpargs,"noNewLine")
--tinsert(tmpargs,true)
tinsert(tmpargs,"tooltipTitle")
tinsert(tmpargs,name)
tinsert(tmpargs,"tooltipText")
tinsert(tmpargs,v.desc or false)
if passGet and v.get == nil then
addFunction(tmpargs,"get",passGet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"get",v.get,v.handler or handler,v.passValue)
end
if passSet and v.set == nil then
addFunction(tmpargs,"set",passSet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"set",v.set,v.handler or handler,v.passValue)
end
addDisabled(tmpargs,groupDisabled or v.disabled,v.handler or handler,v.passValue)
tinsert(tmpargs,"parseList")
tinsert(tmpargs, not not v.input)
tinsert(tmpargs,"fullRefresh")
tinsert(tmpargs,true)
addFunction(tmpargs,"validate",v.validate,v.handler or handler)
self:AddControl(unpack(tmpargs))
end
elseif v.type == "execute" then
--self:AddControl("type","label","text","","width",80)
tinsert(tmpargs,"type")
tinsert(tmpargs,"button")
--tinsert(tmpargs,"noNewLine")
--tinsert(tmpargs,true)
tinsert(tmpargs,"text")
tinsert(tmpargs,name)
tinsert(tmpargs,"confirm")
tinsert(tmpargs, v.confirm or false)
tinsert(tmpargs,"tooltipTitle")
tinsert(tmpargs,name)
tinsert(tmpargs,"tooltipText")
tinsert(tmpargs,v.desc or false)
tinsert(tmpargs, "link")
tinsert(tmpargs,v.link or false)
addFunction(tmpargs,"exec",v.func,v.handler or handler,v.passValue)
addDisabled(tmpargs,groupDisabled or v.disabled,v.handler or handler,v.passValue)
tinsert(tmpargs,"fullRefresh")
tinsert(tmpargs,true)
self:AddControl(unpack(tmpargs))
elseif v.type == "header" then
if name and ( checkNegatable(v.disabled,v.handler or handler,v.passValue) or groupDisabled ) then
lastheader = "|cFF808080"..name
else
lastheader = name
end
elseif v.type == "range" then
--self:AddControl("type","label","text",name,"width",80,"justifyH","RIGHT")
self:AddControl("type","label","text",name)
tinsert(tmpargs,"type")
tinsert(tmpargs,"slider")
--tinsert(tmpargs,"noNewLine")
--tinsert(tmpargs,true)
local min,max,step
min = v.min or 0
max = v.max or 1
step = v.step or 0
tinsert(tmpargs,"min")
tinsert(tmpargs,v.min or 0)
tinsert(tmpargs,"max")
tinsert(tmpargs,v.max or 1)
tinsert(tmpargs,"step")
tinsert(tmpargs,v.step or 0)
tinsert(tmpargs,"bigStep")
tinsert(tmpargs,v.bigStep or v.step or 0)
tinsert(tmpargs,"finalSetOnly")
tinsert(tmpargs,v.finalSetOnly or false)
--if no step is given or there are more than 20 steps possible
--local complex = step == 0 or ((max - min) / step) > 20
local complex = true
tinsert(tmpargs,"text")
tinsert(tmpargs,"")
tinsert(tmpargs,"tooltipTitle")
tinsert(tmpargs,name)
tinsert(tmpargs,"tooltipText")
tinsert(tmpargs,v.desc or false)
if passGet and v.get == nil then
addFunction(tmpargs,"get",passGet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"get",v.get,v.handler or handler,v.passValue)
end
if passSet and v.set == nil then
addFunction(tmpargs,"set",passSet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"set",v.set,v.handler or handler,v.passValue)
end
addDisabled(tmpargs,groupDisabled or v.disabled,v.handler or handler,v.passValue)
tinsert(tmpargs,"fullRefresh")
tinsert(tmpargs,true)
self:AddControl(unpack(tmpargs))
if complex then
tinsert(tmpargs,"type")
tinsert(tmpargs,"textbox")
tinsert(tmpargs,"noNewLine")
tinsert(tmpargs,true)
tinsert(tmpargs,"toNumber")
tinsert(tmpargs,true)
tinsert(tmpargs,"validateModifies")
tinsert(tmpargs,true)
tinsert(tmpargs,"width")
tinsert(tmpargs,60)
tinsert(tmpargs,"tooltipTitle")
tinsert(tmpargs,name)
tinsert(tmpargs,"tooltipText")
tinsert(tmpargs,v.desc or false)
if passGet and v.get == nil then
addFunction(tmpargs,"get",passGet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"get",v.get,v.handler or handler,v.passValue)
end
if passSet and v.set == nil then
addFunction(tmpargs,"set",passSet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"set",v.set,v.handler or handler,v.passValue)
end
addFunction(tmpargs,"validate",validateRange,v.handler or handler,min,max,step)
addDisabled(tmpargs,groupDisabled or v.disabled,v.handler or handler,v.passValue)
tinsert(tmpargs,"fullRefresh")
tinsert(tmpargs,true)
self:AddControl(unpack(tmpargs))
end
elseif v.type == "color" then
--self:AddControl("type","label","text","","width",80)
tinsert(tmpargs,"type")
tinsert(tmpargs,"color")
--tinsert(tmpargs,"noNewLine")
--tinsert(tmpargs,true)
tinsert(tmpargs,"text")
tinsert(tmpargs,name)
if passGet and v.get == nil then
addFunction(tmpargs,"get",passGet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"get",v.get,v.handler or handler,v.passValue)
end
if passSet and v.set == nil then
addFunction(tmpargs,"set",passSet,v.handler or handler,v.passValue or feedkeys[v])
else
addFunction(tmpargs,"set",v.set,v.handler or handler,v.passValue)
end
addDisabled(tmpargs,groupDisabled or v.disabled,v.handler or handler,v.passValue)
tinsert(tmpargs,"tooltipTitle")
tinsert(tmpargs,name)
tinsert(tmpargs,"tooltipText")
tinsert(tmpargs,v.desc or false)
tinsert(tmpargs,"hasOpacity")
tinsert(tmpargs, not not v.hasAlpha)
self:AddControl(unpack(tmpargs))
end
for i = 0,table.getn(tmpargs) do
tmpargs[i] = nil
end
table_setn(tmpargs, 0)
end
end
for i = 0,table.getn(feedtmp) do
feedtmp[i] = nil
end
table_setn(feedtmp, 0)
for k in pairs(feedkeys) do
feedkeys[k] = nil
end
table_setn(feedkeys, 0)
releaseObj(feedtmp,"table")
releaseObj(feedkeys,"table")
releaseObj(tmpargs,"table")
end
function Waterfall:Close(id)
local info = self.registry[id]
if not info then
error("You cannot close a waterfall without registering it first")
end
local frame = info.frame
if frame then
local OnClose = info.OnClose
if type(OnClose) == "function" then
OnClose(id)
end
releaseObj(frame)
end
info.frame = nil
end
function Waterfall:CloseAll()
local closed
for id, v in pairs(self.registry) do
if v.frame then
self:Close(id)
closed = true
end
end
return closed
end
-----------------
-- Gui Classes --
-----------------
local FrameBackdrop = {
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true, tileSize = 16, edgeSize = 16,
insets = { left = 3, right = 3, top = 30, bottom = 3 }
}
local PaneBackdrop = {
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true, tileSize = 16, edgeSize = 16,
insets = { left = 3, right = 3, top = 23, bottom = 3 }
}
local ControlBackdrop = {
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true, tileSize = 16, edgeSize = 16,
insets = { left = 3, right = 3, top = 3, bottom = 3 }
}
-- virtual class to contain frame functions
local FramePassthrough = AceOO.Class()
FramePassthrough.virtual = true
function FramePassthrough.prototype:SetPoint(point,relativeTo,relativePoint,xOffset,yOffset)
self.frame:SetPoint(point,(relativeTo and relativeTo.frame) or relativeTo,relativePoint,xOffset,yOffset)
end
function FramePassthrough.prototype:SetAllPoints(frame)
self.frame:SetAllPoints(frame.frame or frame)
end
function FramePassthrough.prototype:SetWidth(...)
self.frame:SetWidth(unpack(arg))
end
function FramePassthrough.prototype:SetHeight(...)
self.frame:SetHeight(unpack(arg))
end
function FramePassthrough.prototype:SetMinResize(...)
self.frame:SetMinResize(unpack(arg))
end
function FramePassthrough.prototype:SetMaxResize(...)
self.frame:SetMaxResize(unpack(arg))
end
function FramePassthrough.prototype:ClearAllPoints()
self.frame:ClearAllPoints()
end
function FramePassthrough.prototype:Show()
self.frame:Show()
end
function FramePassthrough.prototype:Hide()
self.frame:Hide()
end
function FramePassthrough.prototype:GetHeight()
return self.frame:GetHeight()
end
function FramePassthrough.prototype:GetWidth()
return self.frame:GetWidth()
end
-- Base Class for Gui Controls
local WaterfallControl = AceOO.Class(FramePassthrough)
WaterfallControl.virtual = true
function WaterfallControl.prototype:init(frametype,inherits)
WaterfallControl.super.prototype.init(self)
local frame = CreateFrame(frametype or "Frame",nil,nil,inherits)
self.frame = frame
frame.obj = self
frame:SetFrameLevel(10)
frame:SetFrameStrata("DIALOG")
end
function WaterfallControl.prototype:SetParent(parent)
self.parent = parent
self.frame:SetParent(parent.scrollchild)
end
function WaterfallControl.prototype:Refresh()
end
--basic cleanup function, usually overridden
function WaterfallControl.prototype:CleanUp()
self.frame:ClearAllPoints()
self.frame:Hide()
self.width = nil
self.height = nil
self.noNewLine = nil
self.causesRefresh = nil
self.fullRefresh = nil
self.treeRefresh = nil
self.disabled = nil
self:SetFunc("disabled",nil)
end
function WaterfallControl.prototype:SetFunc(funcType,func,...)
self[funcType.."Func"] = func
local i = 1
while self[funcType.."Arg"..i] do
self[funcType.."Arg"..i] = nil
i = i + 1
end
for i = 1 , table.getn(arg) do
self[funcType.."Arg"..i] = arg[i]
end
end
local function Control_OnEnter()
showGameTooltip(this.obj)
end
local function Control_OnLeave()
GameTooltip:Hide()
end
--the main waterfall frame
WaterfallFrame = AceOO.Class(FramePassthrough)
--the right side pane with gui components in it
WaterfallPane = AceOO.Class(FramePassthrough)
--gui components to be placed on the pane
WaterfallLabel = AceOO.Class(WaterfallControl)
WaterfallLinklabel = AceOO.Class(WaterfallControl)
WaterfallCheckBox = AceOO.Class(WaterfallControl)
WaterfallDragLink = AceOO.Class(WaterfallControl)
WaterfallButton = AceOO.Class(WaterfallControl)
WaterfallHeading = AceOO.Class(WaterfallControl)
WaterfallTextBox = AceOO.Class(WaterfallControl)
WaterfallSlider = AceOO.Class(WaterfallControl)
WaterfallColorSwatch = AceOO.Class(WaterfallControl)
WaterfallDropdown = AceOO.Class(WaterfallControl)
WaterfallKeybinding = AceOO.Class(WaterfallControl)
--the left side treeview pane
WaterfallTreeView = AceOO.Class(FramePassthrough)
WaterfallTreeLine = AceOO.Class(FramePassthrough)
WaterfallTreeSection = AceOO.Class(FramePassthrough)
---------------------------
-- Waterfall Frame Class --
---------------------------
local function frameOnClose()
this.obj.lib:Close(this.obj.id)
end
local function closeOnClick()
this.obj:Hide()
end
local function frameOnMouseDown()
this:GetParent():StartMoving()
end
local function frameOnMouseUp()
this:GetParent():StopMovingOrSizing()
end
local function sizerseOnMouseDown()
this:GetParent():StartSizing("BOTTOMRIGHT")
end
local function sizersOnMouseDown()
this:GetParent():StartSizing("BOTTOM")
end
local function sizereOnMouseDown()
this:GetParent():StartSizing("RIGHT")
end
local function sizerOnMouseUp()
this:GetParent():StopMovingOrSizing()
end
function WaterfallFrame.prototype:init()
WaterfallFrame.super.prototype.init(self)
local frame = CreateFrame("Frame",nil,UIParent)
self.frame = frame
frame.obj = self
frame:SetWidth(550)
frame:SetHeight(500)
frame:SetPoint("CENTER",UIParent,"CENTER",0,0)
frame:EnableMouse()
frame:SetMovable(true)
frame:SetResizable(true)
frame:SetMinResize(500,300)
frame:SetFrameLevel(1)
frame:SetFrameStrata("DIALOG")
frame:SetBackdrop(FrameBackdrop)
frame:SetBackdropColor(0,0,0)
frame:SetScript("OnHide",frameOnClose)
local titlebar = frame:CreateTexture(nil,"BACKGROUND")
self.titlebar = titlebar
local titlebar2 = frame:CreateTexture(nil,"BACKGROUND")
self.titlebar2 = titlebar2
local r,g,b = 1, 0.6, 0
self.colorR = r
self.colorG = g
self.colorB = b
titlebar:SetPoint("TOPLEFT",frame,"TOPLEFT",3,-4)
titlebar:SetPoint("TOPRIGHT",frame,"TOPRIGHT",-3,-4)
titlebar:SetHeight(13)
titlebar2:SetPoint("TOPLEFT",titlebar,"BOTTOMLEFT",0,0)
titlebar2:SetPoint("TOPRIGHT",titlebar,"BOTTOMRIGHT",0,0)
titlebar2:SetHeight(13)
titlebar:SetGradientAlpha("VERTICAL",r*0.6,g*0.6,b*0.6,1,r,g,b,1)
titlebar:SetTexture(r,g,b,1)
titlebar2:SetGradientAlpha("VERTICAL",r*0.9,g*0.9,b*0.9,1,r*0.6,g*0.6,b*0.6,1)
titlebar2:SetTexture(r,g,b,1)
local closebutton = CreateFrame("Button",nil,frame,"UIPanelCloseButton")
closebutton:SetScript("OnClick", closeOnClick)
closebutton:SetPoint("TOPRIGHT",frame,"TOPRIGHT",-2,-2)
self.closebutton = closebutton
closebutton.obj = self
local title = CreateFrame("Frame",nil,frame)
self.title = title
title:EnableMouse()
title:SetScript("OnMouseDown",frameOnMouseDown)
title:SetScript("OnMouseUp", frameOnMouseUp)
title:SetPoint("TOPLEFT",titlebar,"TOPLEFT",0,0)
title:SetPoint("BOTTOMRIGHT",titlebar2,"BOTTOMRIGHT",0,0)
local titletext = title:CreateFontString(nil,"OVERLAY","QuestTitleFont")
titletext:SetPoint("TOPLEFT",title,"TOPLEFT",0,0)
titletext:SetPoint("TOPRIGHT",title,"TOPRIGHT",0,0)
titletext:SetHeight(26)
titletext:SetShadowColor(0,0,0)
titletext:SetShadowOffset(1,-1)
titletext:SetTextColor(1,1,1)
self.titletext = titletext
local sizer_se = CreateFrame("Frame",nil,frame)
sizer_se:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,0)
sizer_se:SetWidth(25)
sizer_se:SetHeight(25)
sizer_se:EnableMouse()
sizer_se:SetScript("OnMouseDown",sizerseOnMouseDown)
sizer_se:SetScript("OnMouseUp", sizerOnMouseUp)
self.sizer_se = sizer_se
local sizer_s = CreateFrame("Frame",nil,frame)
sizer_s:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-25,0)
sizer_s:SetPoint("BOTTOMLEFT",frame,"BOTTOMLEFT",0,0)
sizer_s:SetHeight(25)
sizer_s:EnableMouse()
sizer_s:SetScript("OnMouseDown",sizersOnMouseDown)
sizer_s:SetScript("OnMouseUp", sizerOnMouseUp)
self.sizer_s = sizer_s
local sizer_e = CreateFrame("Frame",nil,frame)
sizer_e:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,25)
sizer_e:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
sizer_e:SetWidth(25)
sizer_e:EnableMouse()
sizer_e:SetScript("OnMouseDown",sizereOnMouseDown)
sizer_e:SetScript("OnMouseUp", sizerOnMouseUp)
self.sizer_e = sizer_e
local treeview = WaterfallTreeView:new(self)
self.treeview = treeview
treeview:SetPoint("TOPLEFT",frame,"TOPLEFT",11,-32)
treeview:SetPoint("BOTTOMLEFT",frame,"BOTTOMLEFT",11,10)
treeview:SetWidth(200)
treeview:SetMinResize(200,0)
treeview:SetMaxResize(400,10000)
local mainpane = WaterfallPane:new(self)
mainpane:SetPoint("TOPLEFT",treeview.frame,"TOPRIGHT",-3,0)
mainpane:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-10,10)
self.mainpane = mainpane
end
function WaterfallFrame.prototype:SetColor(r,g,b)
self.colorR, self.colorG, self.colorB = r,g,b
local titlebar = self.titlebar
local titlebar2 = self.titlebar2
titlebar:SetGradientAlpha("VERTICAL",r*0.6,g*0.6,b*0.6,1,r,g,b,1)
titlebar:SetTexture(r,g,b,1)
titlebar2:SetGradientAlpha("VERTICAL",r*0.9,g*0.9,b*0.9,1,r*0.6,g*0.6,b*0.6,1)
titlebar2:SetTexture(r,g,b,1)
self.mainpane:SetColor(r,g,b)
end
function WaterfallFrame.prototype:GetColor()
return self.colorR, self.colorG, self.colorB
end
function WaterfallFrame.prototype:Hide()
self.frame:Hide()
end
function WaterfallFrame.prototype:Show()
self.frame:Show()
end
function WaterfallFrame.prototype:SetID(id)
self.id = id
end
function WaterfallFrame.prototype:ChangePane(newpane)
self.mainpane:Clear(newpane)
self.controlcount = 0
currentframe = self
if self.children then
local title = self.children(newpane, self.childrenArg)
self.mainpane.titletext:SetText(title)
end
currentframe = nil
self.mainpane:DoLayout()
self.mainpane.paneid = newpane
end
function WaterfallFrame.prototype:SetSelected(id, noupdate)
self.treeview:SetSelected(id, noupdate)
end
function WaterfallFrame.prototype:SetTitle(title)
self.titletext:SetText(title)
end
function WaterfallFrame.prototype:SetChildren(children, arg)
self.children = children
self.childrenArg = arg
end
function WaterfallFrame.prototype:SetTree(tree, treestatus, func, ...)
self.treeview:SetContent(tree, treestatus, func, unpack(arg))
end
function WaterfallFrame.prototype:AddControl(control)
self.mainpane:AddControl(control)
end
function WaterfallFrame.prototype:Refresh()
self.treeview:Refresh()
self:ChangePane(self.treeview:GetSelected())
end
function WaterfallFrame.prototype:CleanUp()
self.children = nil
self.tree = nil
self.treeview:CleanUp()
self:ChangePane()
self:Hide()
end
function WaterfallFrame.prototype:ReAnchorTree()
self.treeview:SetPoint("TOPLEFT",self.frame,"TOPLEFT",11,-32)
self.treeview:SetPoint("BOTTOMLEFT",self.frame,"BOTTOMLEFT",11,10)
end
-------------------------
-- WaterfallPane Class --
-------------------------
local function paneOnSizeChanged()
this.obj:SizeChanged()
end
local function paneOnMouseWheel()
this.obj:MoveScroll(arg1)
end
local function paneOnSizeChanged()
this.obj:DoLayout()
end
local function paneOnScrollValueChanged(self,value)
this.obj:SetScroll(arg1)
end
local numpanes = 0
function WaterfallPane.prototype:init(parent)
WaterfallPane.super.prototype.init(self)
numpanes = numpanes + 1
self.parent = parent
local name = "WaterfallPane"..numpanes
local frame = CreateFrame("Frame",name,parent.frame)
frame:SetBackdrop(PaneBackdrop)
frame:SetBackdropBorderColor(0.6, 0.6, 0.6)
frame:SetBackdropColor(0.1, 0.1, 0.1)
frame:SetFrameLevel(2)
frame:SetFrameStrata("DIALOG")
self.frame = frame
frame.obj = self
frame:SetScript("OnSizeChanged",paneOnSizeChanged)
--local title = CreateFrame("Frame",nil,frame)
--title:SetPoint("TOPLEFT",frame,"TOPLEFT",4,-4)
--title:SetPoint("TOPRIGHT",frame,"TOPRIGHT",-4,-4)
--title:SetHeight(24)
--title:SetBackdrop(PaneBackdrop)
--title:SetBackdropColor(0,0,0,0.2)
--self.title = title
local scrollframe = CreateFrame("ScrollFrame",name.."ScrollFrame",frame)
local scrollchild = CreateFrame("Frame",name.."ChildFrame",scrollframe)
local scrollbar = CreateFrame("Slider",name.."ScrollBar",scrollframe,"UIPanelScrollBarTemplate")
self.scrollframe = scrollframe
self.scrollchild = scrollchild
self.scrollbar = scrollbar
scrollframe:SetScrollChild(scrollchild)
scrollframe:SetPoint("TOPLEFT",frame,"TOPLEFT",9,-29)
scrollframe:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-28,12)
scrollframe:EnableMouseWheel(true)
scrollframe:SetScript("OnMouseWheel", paneOnMouseWheel)
scrollframe:SetScript("OnSizeChanged", paneOnSizeChanged)
scrollframe.obj = self
--scrollchild:SetPoint("TOPLEFT",scrollframe,"TOPLEFT",0,0)
--scrollchild:SetPoint("BOTTOMRIGHT",scrollframe,"BOTTOMRIGHT",0,0)
scrollchild:ClearAllPoints()
scrollchild:SetPoint("TOPLEFT",scrollframe,"TOPLEFT",0,0)
scrollchild:SetWidth(400)
scrollbar:SetPoint("TOPLEFT",scrollframe,"TOPRIGHT",0,-16)
scrollbar:SetPoint("BOTTOMLEFT",scrollframe,"BOTTOMRIGHT",0,16)
scrollbar:SetMinMaxValues(0,1000)
scrollbar:SetValueStep(1)
scrollbar:SetValue(0)
scrollbar:SetWidth(16)
scrollbar:SetScript("OnValueChanged", paneOnScrollValueChanged)
scrollbar.obj = self
self.scrollvalue = 0
local titletext = frame:CreateFontString(nil,"OVERLAY","GameFontNormal")
titletext:SetPoint("TOPLEFT",frame,"TOPLEFT",8,-5)
titletext:SetPoint("TOPRIGHT",frame,"TOPRIGHT",-8,-5)
titletext:SetHeight(16)
titletext:SetText("")
titletext:SetTextColor(1,1,1)
local r,g,b = 1, 0.6, 0
self.colorR = r
self.colorG = g
self.colorB = b
local titlebar = frame:CreateTexture(nil,"BACKGROUND")
self.titlebar = titlebar
local titlebar2 = frame:CreateTexture(nil,"BACKGROUND")
self.titlebar2 = titlebar2
titlebar:SetPoint("TOPLEFT",frame,"TOPLEFT",4,-4)
titlebar:SetPoint("TOPRIGHT",frame,"TOPRIGHT",-4,-4)
titlebar:SetHeight(10)
titlebar2:SetPoint("TOPLEFT",titlebar,"BOTTOMLEFT",0,0)
titlebar2:SetPoint("TOPRIGHT",titlebar,"BOTTOMRIGHT",0,0)
titlebar2:SetHeight(10)
titlebar:SetGradientAlpha("VERTICAL",r*0.6,g*0.6,b*0.6,1,r,g,b,1)
titlebar:SetTexture(r,g,b,1)
titlebar2:SetGradientAlpha("VERTICAL",r*0.9,g*0.9,b*0.9,1,r*0.6,g*0.6,b*0.6,1)
titlebar2:SetTexture(r,g,b,1)
--titletext:SetTextColor(1,1,1)
self.titletext = titletext
self.controls = {}
end
function WaterfallPane.prototype:GetID()
return self.parent.id
end
function WaterfallPane.prototype:SetScroll(value)
local frame, child = self.scrollframe, self.scrollchild
local viewheight = frame:GetHeight()
local height = child:GetHeight()
local width, viewwidth = frame:GetWidth(), child:GetWidth()
local offset
local xOffset = max(0, (width-viewwidth)/2 )
if viewheight > height then
offset = 0
else
offset = floor((height - viewheight) / 1000.0 * (value or 0))
end
child:ClearAllPoints()
child:SetPoint("TOPLEFT",frame,"TOPLEFT",xOffset,offset)
child.offset = offset
self.scrollvalue = value
end
--[[
horiz scrolling version
function WaterfallPane.prototype:SetScroll(value)
local frame, child = self.scrollframe, self.scrollchild
local viewheight = frame:GetWidth()
local height = child:GetWidth()
local offset
if viewheight > height then
offset = 0
else
offset = floor((height - viewheight) / 1000.0 * value)
end
child:ClearAllPoints()
child:SetPoint("TOPLEFT",frame,"TOPLEFT",-offset,0)
child:SetPoint("BOTTOMLEFT",frame,"BOTTOMLEFT",-offset,0)
child.offset = offset
self.scrollvalue = value
end
]]
function WaterfallPane.prototype:MoveScroll(value)
local frame, child = self.scrollframe, self.scrollchild
local height, viewheight = frame:GetHeight(), child:GetHeight()
if height > viewheight then
self.scrollbar:Hide()
else
self.scrollbar:Show()
local diff = height - viewheight
local delta = 1
if value < 0 then
delta = -1
end
self.scrollbar:SetValue(min(max(self.scrollvalue + delta*(1000/(diff/45)),0), 1000))
end
end
function WaterfallPane.prototype:SetColor(r,g,b)
self.colorR, self.colorG, self.colorB = r,g,b
local titlebar = self.titlebar
local titlebar2 = self.titlebar2
titlebar:SetGradientAlpha("VERTICAL",r*0.6,g*0.6,b*0.6,1,r,g,b,1)
titlebar:SetTexture(r,g,b,1)
titlebar2:SetGradientAlpha("VERTICAL",r*0.9,g*0.9,b*0.9,1,r*0.6,g*0.6,b*0.6,1)
titlebar2:SetTexture(r,g,b,1)
end
function WaterfallPane.prototype:Clear(newpane)
for i = 1, table.getn(self.controls) do
releaseObj(self.controls[i])
self.controls[i] = nil
end
table_setn(self.controls,0)
if self.paneid ~= newpane then
self:SetScroll(0)
end
end
function WaterfallPane.prototype:ClearFocus()
for i, v in ipairs(self.controls) do
if v.class == WaterfallTextBox then
v.frame:ClearFocus()
end
end
end
function WaterfallPane.prototype:AddControl(control)
tinsert(self.controls, control)
control:SetParent(self)
end
--simple one under the other layout for now
function WaterfallPane.prototype:DoLayout()
local usedheight = 0
local maxwidth = 0
local rowwidth = 1
local rowheight = 1
for i, control in ipairs(self.controls) do
control:ClearAllPoints()
if i == 1 then
control:SetPoint("TOPLEFT",self.scrollchild,"TOPLEFT",10,0)
rowheight = control:GetHeight()
rowwidth = control:GetWidth() + 10
else
if control.noNewLine then
control:SetPoint("TOPLEFT",self.controls[i-1],"TOPRIGHT",0,0)
rowheight = max(rowheight,control:GetHeight())
rowwidth = rowwidth + control:GetWidth()
else
usedheight = usedheight + rowheight
maxwidth = max(rowwidth,maxwidth)
control:SetPoint("TOPLEFT",self.scrollchild,"TOPLEFT",10,-usedheight)
rowheight = control:GetHeight()
rowwidth = control:GetWidth()
end
end
control:Show()
end
maxwidth = max(rowwidth,maxwidth)
self.scrollchild:SetHeight(usedheight+rowheight)
self.scrollchild:SetWidth(maxwidth+5)
self:FixScroll()
end
--[[
function WaterfallPane.prototype:DoLayout()
local colheight = 0
local sectionheight = 0
local sectionwidth = 0
local colwidth = 0
local usedwidth = 0
local frameheight = self.scrollchild:GetHeight()
for i, control in ipairs(self.controls) do
colheight = colheight + control:GetHeight()
colwidth = max(colwidth, control:GetWidth())
control:ClearAllPoints()
if colheight <= (frameheight - 10) then
if i == 1 then
control:SetPoint("TOPLEFT",self.scrollchild,"TOPLEFT",4,0)
else
control:SetPoint("TOPLEFT",self.controls[i-1],"BOTTOMLEFT",0,0)
end
else
usedwidth = usedwidth + colwidth + 6
colwidth = 0
colheight = 0
control:SetPoint("TOPLEFT",self.scrollchild,"TOPLEFT",4+usedwidth,0)
end
control:Show()
end
usedwidth = usedwidth + colwidth
self.scrollchild:SetWidth(usedwidth)
self:FixScroll()
end
]]
function WaterfallPane.prototype:SizeChanged()
self:FixScroll()
end
function WaterfallPane.prototype:FixScroll()
local frame, child = self.scrollframe, self.scrollchild
local height, viewheight = frame:GetHeight(), child:GetHeight()
local width, viewwidth = frame:GetWidth(), child:GetWidth()
local offset = self.scrollchild.offset
if not offset then
offset = 0
end
local curvalue = self.scrollbar:GetValue()
local xOffset = max(0, (width-viewwidth)/2 )
if viewheight < height then
self.scrollbar:Hide()
--self.scrollbar:SetValue(0)
child:ClearAllPoints()
child:SetPoint("TOPLEFT",frame,"TOPLEFT",xOffset,0)
child.offset = 0
else
self.scrollbar:Show()
local value = (offset / (viewheight - height) * 1000)
if value > 1000 then value = 1000 end
self.scrollbar:SetValue(value)
self:SetScroll(value)
if value < 1000 then
child:ClearAllPoints()
child:SetPoint("TOPLEFT",frame,"TOPLEFT",xOffset,offset)
child.offset = offset
end
end
end
--[[
horiz scrolling version
function WaterfallPane.prototype:FixScroll()
local frame, child = self.scrollframe, self.scrollchild
local height, viewheight = frame:GetWidth(), child:GetWidth()
local offset = self.scrollchild.offset
if not offset then
offset = 0
end
local curvalue = self.scrollbar:GetValue()
if viewheight < height then
self.scrollbar:EnableMouse(false)
self.scrollbar:SetValue(0)
else
self.scrollbar:EnableMouse(true)
local value = (offset / (viewheight - height) * 1000)
if value > 1000 then value = 1000 end
self.scrollbar:SetValue(value)
self:SetScroll(value)
if value < 1000 then
child:ClearAllPoints()
child:SetPoint("TOPLEFT",frame,"TOPLEFT",-offset,0)
child:SetPoint("BOTTOMLEFT",frame,"BOTTOMLEFT",-offset,0)
child.offset = offset
end
end
end
]]
function WaterfallPane.prototype:Refresh(fullRefresh)
if fullRefresh then
self.parent:Refresh()
else
for i, control in ipairs(self.controls) do
control:Refresh()
end
end
self:FixScroll()
end
-----------------
-- Label Class --
-----------------
function WaterfallLabel.prototype:init()
WaterfallLabel.super.prototype.init(self)
local frame = self.frame
local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
self.text = text
frame.text = text
text:SetText("Waterfalllabel")
text:SetJustifyH("LEFT")
text:SetTextColor(1,1,1)
frame:SetHeight(24)
frame:SetWidth(DEFAULT_CONTROL_WIDTH)
text:SetHeight(16)
text:SetPoint("LEFT",frame,"LEFT")
end
--fontstrings dont return the correct width untill they have been drawn, wait a frame to set the width
local function labelFixWidth()
if not this.obj.width then
this:SetWidth(this.text:GetWidth()+3)
end
this:SetScript("OnUpdate",nil)
end
function WaterfallLabel.prototype:SetText(text)
self.text:SetText(text)
self:Refresh()
end
function WaterfallLabel.prototype:CleanUp()
self.frame:ClearAllPoints()
self.frame:Hide()
self.width = nil
self.height = nil
self.noNewLine = nil
self.causesRefresh = nil
self.fullRefresh = nil
self.treeRefresh = nil
self:SetText("")
end
function WaterfallLabel.prototype:Refresh()
self.frame:SetHeight(self.height or 16)
if self.width then
self.text:ClearAllPoints()
self.text:SetPoint("LEFT",self.frame,"LEFT")
self.text:SetPoint("RIGHT",self.frame,"RIGHT")
self:SetWidth(self.width)
else
self.text:ClearAllPoints()
self.text:SetPoint("LEFT",self.frame,"LEFT")
self.frame:SetScript("OnUpdate", labelFixWidth)
end
self.text:SetJustifyH(self.justifyH or "LEFT")
self.text:SetTextColor(self.r or 1, self.g or 1, self.b or 1)
end
-----------------
-- Linklabel Class --
-----------------
local function Linklabel_OnEnter()
local self = this.obj
if not self.disabled then
self.highlight:Show()
showGameTooltip(self)
end
end
local function Linklabel_OnLeave()
this.obj.highlight:Hide()
GameTooltip:Hide()
end
local function linkConfirmFunc(self, refresh, full, func, ...)
func(unpack(arg))
if refresh or full then
self.parent:Refresh(full)
end
end
local function Linklabel_OnClick()
local self = this.obj
local func = self.linkFunc
local confirm = this.obj.confirm
if func then
if confirm then
if type(confirm) == "string" then
confirmPopup(confirm,linkConfirmFunc,self,self.causesRefresh,self.fullRefresh,func,getArgs(this.obj,"linkArg",1))
else
confirmPopup((ARE_YOU_SURE):format(this.obj.text:GetText()),linkConfirmFunc,
self,self.causesRefresh,self.fullRefresh,func,getArgs(this.obj,"linkArg",1))
end
else
func(getArgs(this.obj,"linkArg",1))
end
if self.causesRefresh or self.fullRefresh then
self.parent:Refresh(self.fullRefresh)
end
end
end
function WaterfallLinklabel.prototype:init()
WaterfallLinklabel.super.prototype.init(self, "Button")
local frame = self.frame
local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
self.text = text
frame.text = text
frame:SetScript("OnClick", Linklabel_OnClick)
frame:SetScript("OnEnter", Linklabel_OnEnter)
frame:SetScript("OnLeave", Linklabel_OnLeave)
text:SetText("WaterfallLinklabel")
text:SetJustifyH("LEFT")
text:SetTextColor(1,1,1)
frame:SetHeight(24)
frame:SetWidth(DEFAULT_CONTROL_WIDTH)
text:SetHeight(16)
text:SetPoint("LEFT",frame,"LEFT")
local highlight = frame:CreateTexture(nil, "BACKGROUND")
self.highlight = highlight
highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
highlight:SetBlendMode("ADD")
highlight:SetAllPoints(frame)
highlight:Hide()
frame:EnableMouse()
end
function WaterfallLinklabel.prototype:SetText(text)
self.text:SetText(text)
self:Refresh()
end
function WaterfallLinklabel.prototype:CleanUp()
self.frame:ClearAllPoints()
self.frame:Hide()
self.width = nil
self.height = nil
self.noNewLine = nil
self.causesRefresh = nil
self.fullRefresh = nil
self.treeRefresh = nil
self:SetText("")
end
function WaterfallLinklabel.prototype:Refresh()
self.frame:SetHeight(self.height or 16)
if self.width then
self.text:ClearAllPoints()
self.text:SetPoint("LEFT",self.frame,"LEFT")
self.text:SetPoint("RIGHT",self.frame,"RIGHT")
self:SetWidth(self.width)
else
self.text:ClearAllPoints()
self.text:SetPoint("LEFT")
self.frame:SetScript("OnUpdate", labelFixWidth)
end
self.text:SetJustifyH(self.justifyH or "LEFT")
self.text:SetTextColor(self.r or 1, self.g or 1, self.b or 1)
end
function WaterfallLinklabel.prototype:SetColor(r,g,b)
self.r = r
self.g = g
self.b = b
self:Refresh()
end
-----------------
-- ColorSwatch Class --
-----------------
local tmpt = setmetatable({}, {mode='v'})
local function ColorSwatch_OnClick()
local self = this.obj
if not self.disabled then
local func = self.setFunc
local hasOpacity = self.hasOpacity
for k in pairs(tmpt) do
tmpt[k] = nil
end
for i = 1, 1000 do
local x = self['setArg'..i]
if x == nil then
break
else
tmpt[i] = x
end
end
ColorPickerFrame.func = function()
if func then
local r,g,b = ColorPickerFrame:GetColorRGB()
local a = hasOpacity and 1 - OpacitySliderFrame:GetValue() or nil
local n = table.getn(tmpt)
tmpt[n+1] = r
tmpt[n+2] = g
tmpt[n+3] = b
tmpt[n+4] = a
func(unpack(tmpt))
self:SetColor(r,g,b,a)
tmpt[n+1] = nil
tmpt[n+2] = nil
tmpt[n+3] = nil
tmpt[n+4] = nil
if self.causesRefresh or self.fullRefresh then
self.parent:Refresh(self.fullRefresh)
end
end
end
ColorPickerFrame.hasOpacity = self.hasOpacity
ColorPickerFrame.opacityFunc = ColorPickerFrame.func
ColorPickerFrame.opacity = 1 - (self.opacity or 0)
ColorPickerFrame:SetColorRGB(self.r, self.g, self.b)
local r, g, b, a = self.r, self.g, self.b, self.opacity
ColorPickerFrame.cancelFunc = function()
if func then
local n = table.getn(tmpt)
tmpt[n+1] = r
tmpt[n+2] = g
tmpt[n+3] = b
tmpt[n+4] = a
func(unpack(tmpt))
self:SetColor(r,g,b,a)
for i = 1, n+4 do
tmpt[i] = nil
end
end
end
ColorPickerFrame:SetFrameStrata(self.frame:GetFrameStrata())
ColorPickerFrame:SetFrameLevel(self.frame:GetParent():GetFrameLevel()+1)
for i, child in ipairs({ColorPickerFrame:GetChildren()}) do
-- child:SetFrameStrata(self.frame:GetFrameStrata())
child:SetFrameLevel(self.frame:GetParent():GetFrameLevel()+2)
end
ShowUIPanel(ColorPickerFrame)
end
end
local function ColorSwatch_OnEnter()
local self = this.obj
if not self.disabled then
self.highlight:Show()
showGameTooltip(self)
end
end
local function ColorSwatch_OnLeave()
this.obj.highlight:Hide()
GameTooltip:Hide()
end
function WaterfallColorSwatch.prototype:init()
WaterfallColorSwatch.super.prototype.init(self,"Button")
local frame = self.frame
local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
self.text = text
text:SetJustifyH("LEFT")
text:SetTextColor(1,1,1)
frame:SetHeight(24)
frame:SetWidth(DEFAULT_CONTROL_WIDTH)
text:SetHeight(24)
frame:SetScript("OnClick", ColorSwatch_OnClick)
frame:SetScript("OnEnter",ColorSwatch_OnEnter)
frame:SetScript("OnLeave",ColorSwatch_OnLeave)
local colorSwatch = frame:CreateTexture(nil, "OVERLAY")
self.colorSwatch = colorSwatch
colorSwatch:SetWidth(24)
colorSwatch:SetHeight(24)
colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
local texture = frame:CreateTexture(nil, "OVERLAY")
colorSwatch.texture = texture
texture:SetTexture(1, 1, 1)
texture:SetWidth(13.8)
texture:SetHeight(13.8)
texture:Show()
local highlight = frame:CreateTexture(nil, "BACKGROUND")
self.highlight = highlight
highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
highlight:SetBlendMode("ADD")
highlight:SetAllPoints(frame)
highlight:Hide()
texture:SetPoint("CENTER", colorSwatch, "CENTER")
colorSwatch:SetPoint("LEFT", frame, "LEFT", 0, 0)
text:SetPoint("LEFT",colorSwatch,"RIGHT",2,0)
text:SetPoint("RIGHT",frame,"RIGHT")
end
function WaterfallColorSwatch.prototype:SetText(text)
self.text:SetText(text)
end
function WaterfallColorSwatch.prototype:SetColor(r,g,b,a)
self.r = r
self.g = g
self.b = b
self.opacity = a
self:Refresh()
end
function WaterfallColorSwatch.prototype:Refresh()
if self.getFunc then
self.r, self.g, self.b, self.opacity = self.getFunc(getArgs(self,"getArg",1))
end
if self.disabledFunc then
self.disabled = self.disabledFunc(getArgs(self,"disabledArg",1))
if self.inverseDisabled then
self.disabled = not self.disabled
end
end
self.colorSwatch.texture:SetTexture(self.r,self.g,self.b)
if self.disabled then
self.text:SetTextColor(0.5,0.5,0.5)
else
self.text:SetTextColor(1,1,1)
end
if self.width then
self:SetWidth(self.width)
else
self:SetWidth(DEFAULT_CONTROL_WIDTH)
end
end
function WaterfallColorSwatch.prototype:CleanUp()
self.frame:ClearAllPoints()
self.frame:Hide()
self.width = nil
self.height = nil
self.noNewLine = nil
self.causesRefresh = nil
self.fullRefresh = nil
self.treeRefresh = nil
self:SetText("")
self:SetFunc("color",nil)
self.r = nil
self.g = nil
self.b = nil
self.hasOpacity = nil
self.opacity = nil
self.disabled = nil
self:SetFunc("disabled",nil)
end
-----------------
-- Heading Class --
-----------------
function WaterfallHeading.prototype:init()
WaterfallHeading.super.prototype.init(self)
local frame = self.frame
local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormal")
self.text = text
frame.text = text
text:SetJustifyH("LEFT")
frame:SetHeight(24)
frame:SetWidth(DEFAULT_CONTROL_WIDTH)
text:SetHeight(24)
text:SetPoint("LEFT",frame,"LEFT")
end
function WaterfallHeading.prototype:SetText(text)
self.text:SetText(text)
self.frame:SetScript("OnUpdate", labelFixWidth)
end
function WaterfallHeading.prototype:CleanUp()
self.frame:ClearAllPoints()
self.frame:Hide()
self.width = nil
self.height = nil
self.noNewLine = nil
self.causesRefresh = nil
self.fullRefresh = nil
self.treeRefresh = nil
self:SetText("")
end
function WaterfallHeading.prototype:Refresh()
self.frame:SetHeight(self.height or 16)
if self.width then
self.text:ClearAllPoints()
self.text:SetPoint("LEFT",self.frame,"LEFT")
self.text:SetPoint("RIGHT",self.frame,"RIGHT")
self:SetWidth(self.width)
else
self.text:ClearAllPoints()
self.text:SetPoint("LEFT",self.frame,"LEFT")
self.frame:SetScript("OnUpdate", labelFixWidth)
end
self.text:SetJustifyH(self.justifyH or "LEFT")
end
-----------------
-- CheckBox Class --
-----------------
local function CheckBox_OnEnter()
local self = this.obj
if not self.disabled then
self.highlight:Show()
showGameTooltip(self)
end
end
local function CheckBox_OnLeave()
local self = this.obj
if not self.down then
self.highlight:Hide()
end
GameTooltip:Hide()
end
local function CheckBox_OnMouseUp()
local self = this.obj
if not self.disabled then
self:ToggleChecked()
self.text:SetPoint("LEFT",self.check,"RIGHT",0,0)
end
self.down = nil
end
local function CheckBox_OnMouseDown()
local self = this.obj
if not self.disabled then
self.text:SetPoint("LEFT",self.check,"RIGHT",1,-1)
self.down = true
end
end
function WaterfallCheckBox.prototype:init()
WaterfallCheckBox.super.prototype.init(self,"Button")
local frame = self.frame
local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
self.text = text
frame:SetScript("OnEnter",CheckBox_OnEnter)
frame:SetScript("OnLeave",CheckBox_OnLeave)
frame:SetScript("OnMouseUp",CheckBox_OnMouseUp)
frame:SetScript("OnMouseDown",CheckBox_OnMouseDown)
frame:EnableMouse()
local checkbg = frame:CreateTexture(nil,"ARTWORK")
self.checkbg = checkbg
checkbg:SetWidth(20)
checkbg:SetHeight(20)
checkbg:SetPoint("LEFT",frame,"LEFT",0,0)
checkbg:SetTexture("Interface\\Buttons\\UI-CheckBox-Up")
local check = frame:CreateTexture(nil,"OVERLAY")
self.check = check
check:SetWidth(20)
check:SetHeight(20)
check:SetPoint("LEFT",frame,"LEFT",0,0)
check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
self.checked = false
self:UpdateCheck()
local highlight = frame:CreateTexture(nil, "BACKGROUND")
self.highlight = highlight
highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
highlight:SetBlendMode("ADD")
highlight:SetAllPoints(frame)
highlight:Hide()
text:SetJustifyH("LEFT")
text:SetTextColor(1,1,1)
frame:SetHeight(24)
frame:SetWidth(DEFAULT_CONTROL_WIDTH)
text:SetHeight(24)
text:SetPoint("LEFT",check,"RIGHT",0,0)
end
function WaterfallCheckBox.prototype:UpdateTexture()
local checkbg = self.checkbg
local check = self.check
local highlight = self.highlight
if self.isRadio then
checkbg:SetTexture("Interface\\Buttons\\UI-RadioButton")
checkbg:SetTexCoord(0,0.25,0,1)
check:SetTexture("Interface\\Buttons\\UI-RadioButton")
check:SetTexCoord(0.5,0.75,0,1)
check:SetBlendMode("ADD")
else
checkbg:SetTexture("Interface\\Buttons\\UI-CheckBox-Up")
checkbg:SetTexCoord(0,1,0,1)
check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
check:SetTexCoord(0,1,0,1)
check:SetBlendMode("BLEND")
end
end
function WaterfallCheckBox.prototype:SetText(text)
self.text:SetText(text)
end
function WaterfallCheckBox.prototype:UpdateCheck()
if self.checked then
self.check:Show()
else
self.check:Hide()
end
end
function WaterfallCheckBox.prototype:ToggleChecked()
self.checked = not self.checked
self:UpdateCheck()
if self.setFunc then
self.setFunc(getArgs(self,"setArg",1,self.checked))
end
if self.causesRefresh or self.fullRefresh then
self.parent:Refresh(self.fullRefresh)
else
self:Refresh()
end
end
function WaterfallCheckBox.prototype:SetChecked(value)
self.checked = value
self:UpdateCheck()
end
function WaterfallCheckBox.prototype:GetChecked()
return self.checked
end
function WaterfallCheckBox.prototype:CleanUp()
self.frame:ClearAllPoints()
self.frame:Hide()
self.highlight:Hide()
self.width = nil
self.height = nil
self.noNewLine = nil
self.causesRefresh = nil
self.fullRefresh = nil
self.treeRefresh = nil
self:SetText("")
self:SetChecked(false)
self:SetFunc("disabled",nil)
self:SetFunc("get",nil)
self:SetFunc("set",nil)
self.isRadio = nil
end
function WaterfallCheckBox.prototype:Refresh()
if self.getFunc then
local checked = self.getFunc(getArgs(self,"getArg",1))
self:SetChecked(checked)
end
if self.disabledFunc then
self.disabled = self.disabledFunc(getArgs(self,"disabledArg",1))
if self.inverseDisabled then
self.disabled = not self.disabled
end
end
if self.disabled then
self.text:SetTextColor(0.5,0.5,0.5)
SetDesaturation(self.check, true)
else
self.text:SetTextColor(1,1,1)
SetDesaturation(self.check, false)
end
if self.width then
self:SetWidth(self.width)
else
self:SetWidth(DEFAULT_CONTROL_WIDTH)
end
self:UpdateTexture()
end
-----------------
-- DragLink Class --
-----------------
-- Provides an icon and description of a link based on on its linkInfo.itemType, itemId, itemInfo
-- Dragging onto the linkIcon sets linkInfo.itemType, linkInfo.itemId, linkInfo.itemInfo
-- If linkInfo.itemType == "spell" then linkInfo.spellName, linkInfo.spellRank, linkInfo.spellClass (current player class) are also set
-- Dragging between two DragLink objects will swap their contents
function Waterfall:GetDraggingObject()
return Waterfall.fromObject
end
function Waterfall:SetDraggingObject(fromObject)
Waterfall.fromObject = fromObject
end
local function DragLinkOnDragStart()
local fromObject = this.obj
Waterfall:SetDraggingObject(fromObject)
end
local function DragLinkOnReceiveDrag()
local self = this.obj
local toObject = this.obj
local fromObject = Waterfall:GetDraggingObject()
local refreshNeeded = false
if (fromObject and fromObject ~= toObject) then
--DEFAULT_CHAT_FRAME:AddMessage("DragLinkOnReceiveDrag toObject " .. tostring(toObject))
fromObject.itemType, toObject.itemType = toObject.itemType, fromObject.itemType
fromObject.itemId, toObject.itemId = toObject.itemId, fromObject.itemId
fromObject.itemInfo, toObject.itemInfo = toObject.itemInfo, fromObject.itemInfo
fromObject.spellName, toObject.spellName = toObject.spellName, fromObject.spellName
fromObject.spellRank, toObject.spellRank = toObject.spellRank, fromObject.spellRank
fromObject.spellClass, toObject.spellClass = toObject.spellClass, fromObject.spellClass
if fromObject.causesRefresh or fromObject.fullRefresh then
fromObject.parent:Refresh(fromObject.fullRefresh)
end
refreshNeeded = true
else
local itemType, itemId, itemInfo = GetCursorInfo()
--DEFAULT_CHAT_FRAME:AddMessage("DragLinkOnReceiveDrag itemType " .. tostring(itemType) .. " itemId " .. tostring(itemId) .. " itemInfo " .. tostring(itemInfo))
if (itemType == "item" or itemType == "spell" or itemType == "macro") then
local linkInfo = self.linkInfo
linkInfo.itemType = itemType
linkInfo.itemId = itemId
linkInfo.itemInfo = itemInfo
if (itemType == "spell") then
local spellName, spellRank = GetSpellName(itemId, itemInfo)
linkInfo.spellName = spellName
linkInfo.spellRank = spellRank
linkInfo.spellClass = WaterfallDragLink.CLASS
else
linkInfo.spellName = nil
linkInfo.spellRank = nil
linkInfo.spellClass = nil
end
--DEFAULT_CHAT_FRAME:AddMessage("DragLinkOnReceiveDrag itemType " .. tostring(itemType) .. " itemId " .. tostring(itemId) .. " itemInfo " .. tostring(itemInfo))
--DEFAULT_CHAT_FRAME:AddMessage("DragLinkOnReceiveDrag self.setFunc " .. tostring(self.setFunc) .. " self.disabled " .. tostring(self.disabled))
if (self.setFunc and not self.disabled) then
self.setFunc(getArgs(self,"setArg",1,linkInfo))
end
refreshNeeded = true
ClearCursor()
end
end
if (refreshNeeded) then
if self.causesRefresh or self.fullRefresh then
self.parent:Refresh(self.fullRefresh)
else
self:Refresh()
end
end
Waterfall:SetDraggingObject(nil)
end
local function DragLinkOnClick()
DragLinkOnReceiveDrag() --??
end
local function DragLinkOnEnter()
local self = this.obj
local linkInfo = self.linkInfo
if (linkInfo) then
if (linkInfo.itemType == "item") then
GameTooltip:SetOwner(this, "ANCHOR_PRESERVE")
if (linkInfo.itemId) then
GameTooltip:SetHyperlink("item:" .. linkInfo.itemId .. ":0:0:0:0:0:0:0")
else
GameTooltip:SetHyperlink(tostring(linkInfo.itemInfo))
end
elseif (linkInfo.itemType == "spell") then
if (linkInfo.spellName) then
-- Cannot set this without preserving spell book & spell id. Even then may be from different class. So lame. Awaiting a Blizzard API that doesnt suck.
-- GameTooltip:SetSpell(linkInfo.spellId, linkInfo.spellTab)
GameTooltip:SetOwner(this, "ANCHOR_PRESERVE")
GameTooltip:AddLine(linkInfo.spellName, 1, 1, 1)
local name, rank, icon, cost, isFunnel, powerType, castTime, minRange, maxRange = GetSpellInfo(linkInfo.spellName)
if (name) then
if (powerType == 0) then
cost = tostring(cost) .. " " .. MANA
elseif (powerType == 1) then
cost = tostring(cost) .. " " .. RAGE
elseif (powerType == 2) then
cost = tostring(cost) .. " " .. FOCUS
elseif (powerType == 3) then
cost = tostring(cost) .. " " .. ENERGY
elseif (powerType == 4) then
cost = tostring(cost) .. " " .. HAPPINESS
end
local range = ""
if (maxRange) then
range = SPELL_RANGE:format(maxRange)
end
GameTooltip:AddDoubleLine(cost, range, 1, 1, 1, 1, 1, 1)
if (castTime and castTime > 0) then
GameTooltip:AddLine(SPELL_CAST_TIME_SEC:format(castTime), 1, 1, 1)
else
GameTooltip:AddLine(SPELL_CAST_TIME_INSTANT, 1, 1, 1)
end
if (rank) then
GameTooltip:AddLine(tostring(rank))
end
GameTooltip:Show()
end
end
elseif (linkInfo.itemType == "macro") then
if (linkInfo.itemId) then
local name, icon, body = GetMacroInfo(linkInfo.itemId)
if (name) then
GameTooltip:SetOwner(this, "ANCHOR_PRESERVE")
GameTooltip:AddLine(tostring(name), 0.2, 0.8, 0.8, 1)
GameTooltip:AddTexture(icon)
GameTooltip:AddLine(tostring(body), 1, 1, 1, 1)
GameTooltip:Show()
end
end
end
end
end
local function DragLinkOnLeave()
GameTooltip:Hide()
end
local function DragLinkGetTexture(self)
local linkInfo = self.linkInfo
local texture
if (linkInfo) then
if (linkInfo.itemType == "item") then
if (linkInfo.itemId and tonumber(linkInfo.itemId)) then
_,_,_,_,_,_,_,_,_,texture = GetItemInfo(tonumber(linkInfo.itemId))
if (texture) then
return texture
end
end
elseif (linkInfo.itemType == "spell") then
if (linkInfo.spellName) then
_, _, texture = GetSpellInfo(linkInfo.spellName)
if (texture) then
return texture
end
end
elseif (linkInfo.itemType == "macro") then
if (linkInfo.itemId) then
_, texture = GetMacroInfo(linkInfo.itemId)
if (texture) then
return texture
end
end
end
end
return "Interface\\Icons\\INV_Misc_Gift_01"
end
WaterfallDragLink.defaultIconSize = 36
_, WaterfallDragLink.CLASS = UnitClass("player") -- Use the capitalized english class name
function WaterfallDragLink.prototype:init()
WaterfallDragLink.super.prototype.init(self, "Button")
local frame = self.frame
local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
self.text = text
frame:SetScript("OnDragStart", DragLinkOnDragStart)
frame:SetScript("OnReceiveDrag", DragLinkOnReceiveDrag)
frame:SetScript("OnClick", DragLinkOnClick)
frame:SetScript("OnEnter", DragLinkOnEnter)
frame:SetScript("OnLeave", DragLinkOnLeave)
frame:EnableMouse()
frame:RegisterForDrag("LeftButton")
frame:RegisterForClicks("LeftButtonUp", "RightButtonUp")
local linkIcon = frame:CreateTexture(nil, "OVERLAY")
linkIcon:SetWidth(self.iconWidth or WaterfallDragLink.defaultIconSize)
linkIcon:SetHeight(self.iconHeight or WaterfallDragLink.defaultIconSize)
linkIcon:SetPoint("LEFT",frame,"LEFT",0,0)
linkIcon:SetTexture(DragLinkGetTexture(self))
linkIcon:SetTexCoord(0,1,0,1)
linkIcon:Show()
self.linkIcon = linkIcon
text:SetJustifyH("LEFT")
text:SetTextColor(1,1,1)
frame:SetHeight(self.iconHeight or WaterfallDragLink.defaultIconSize + 4)
frame:SetWidth(DEFAULT_CONTROL_WIDTH)
text:SetHeight(self.iconHeight or WaterfallDragLink.defaultIconSize + 4)
text:SetPoint("LEFT",check,"RIGHT",0,0)
end
function WaterfallDragLink.prototype:SetText(text)
self.text:SetText(text)
end
function WaterfallDragLink.prototype:CleanUp()
self.frame:ClearAllPoints()
self.frame:Hide()
self.width = nil
self.height = nil
self.noNewLine = nil
self.causesRefresh = nil
self.fullRefresh = nil
self.treeRefresh = nil
self:SetText("")
self:SetFunc("disabled", nil)
self.linkIcon:Hide()
end
function WaterfallDragLink.prototype:Refresh()
if self.disabledFunc then
self.disabled = self.disabledFunc(getArgs(self,"disabledArg",1))
if self.inverseDisabled then
self.disabled = not self.disabled
end
end
if self.disabled then
self.frame:Disable()
else
self.frame:Enable()
end
if self.width then
self:SetWidth(self.width)
else
self:SetWidth(DEFAULT_CONTROL_WIDTH)
end
if (not self.linkIcon) then
local linkIcon = self.frame:CreateTexture(nil, "OVERLAY")
linkIcon:SetWidth(self.iconWidth or WaterfallDragLink.defaultIconSize)
linkIcon:SetHeight(self.iconHeight or WaterfallDragLink.defaultIconSize)
linkIcon:SetPoint("TOP", self.frame, "TOP", 0, 0)
linkIcon:SetTexCoord(0,1,0,1)
linkIcon:Show()
self.linkIcon = linkIcon
end
if self.getFunc then
self.linkInfo = self.getFunc(getArgs(self,"getArg",1))
else
self:assert(self.linkInfo, "wth?")
end
self.linkIcon:SetTexture(DragLinkGetTexture(self))
self.linkIcon:Show()
if (self.linkInfo.itemId) then
self:SetText((self.linkInfo.itemInfo or "") .. " (" .. tostring(self.linkInfo.itemId) .. ")")
else
self:SetText("")
end
--DEFAULT_CHAT_FRAME:AddMessage("WaterfallDragLink.prototype:Refresh texture " .. tostring(DragLinkGetTexture(self)) .. " self.linkInfo.itemId " .. tostring(self.linkInfo.itemId) .. " self.linkInfo.itemInfo " .. tostring(self.linkInfo.itemInfo))
end
-----------------
-- Button Class --
-----------------
local function buttonConfirmFunc(self, refresh, full, func, ...)
func(unpack(arg))
if refresh or full then
self.parent:Refresh(full)
end
end
local function Button_OnClick()
local self = this.obj
local func = self.execFunc
local confirm = this.obj.confirm
if func then
if confirm then
if type(confirm) == "string" then
confirmPopup(confirm,buttonConfirmFunc,self,self.causesRefresh,self.fullRefresh,func,getArgs(this.obj,"execArg",1))
else
confirmPopup((ARE_YOU_SURE):format(this.obj.frame:GetText()),buttonConfirmFunc,
self,self.causesRefresh,self.fullRefresh,func,getArgs(this.obj,"execArg",1))
end
else
func(getArgs(this.obj,"execArg",1))
end
if self.causesRefresh or self.fullRefresh then
self.parent:Refresh(self.fullRefresh)
end
end
end
local function Control_OnEnter()
if this.obj.link then
GameTooltip:SetOwner(this, "ANCHOR_PRESERVE")
GameTooltip:SetHyperlink(this.obj.link)
else
showGameTooltip(this.obj)
end
end
local function Control_OnLeave()
GameTooltip:Hide()
end
function WaterfallButton.prototype:init()
WaterfallButton.super.prototype.init(self,"Button","UIPanelButtonTemplate")
local frame = self.frame
--local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
local text = frame:GetFontString()
text:SetPoint("LEFT",frame,"LEFT",7,0)
text:SetPoint("RIGHT",frame,"RIGHT",-7,0)
frame:SetScript("OnClick",Button_OnClick)
frame:SetScript("OnEnter",Control_OnEnter)
frame:SetScript("OnLeave",Control_OnLeave)
frame:EnableMouse()
frame:SetHeight(24)
frame:SetWidth(DEFAULT_CONTROL_WIDTH)
end
function WaterfallButton.prototype:SetText(text)
self.frame:SetText(text)
end
function WaterfallButton.prototype:CleanUp()
self.frame:ClearAllPoints()
self.frame:Hide()
self.width = nil
self.height = nil
self.noNewLine = nil
self.causesRefresh = nil
self.fullRefresh = nil
self.treeRefresh = nil
self:SetText("")
self:SetFunc("disabled",nil)
self:SetFunc("exec",nil)
end
function WaterfallButton.prototype:Refresh()
if self.disabledFunc then
self.disabled = self.disabledFunc(getArgs(self,"disabledArg",1))
if self.inverseDisabled then
self.disabled = not self.disabled
end
end
if self.disabled then
self.frame:Disable()
else
self.frame:Enable()
end
if self.width then
self:SetWidth(self.width)
else
self:SetWidth(DEFAULT_CONTROL_WIDTH)
end
end
-----------------
-- Keybinding Class --
-----------------
local function Keybinding_OnClick( button)
local self = this.obj
if button == "LeftButton" or button == "RightButton" then
if self.waitingForKey then
this:EnableKeyboard(false)
self.msgframe:Hide()
this:UnlockHighlight()
self.waitingForKey = nil
else
this:EnableKeyboard(true)
self.parent:ClearFocus()
self.msgframe:Show()
this:LockHighlight()
self.waitingForKey = true
end
end
end
local function Keybinding_OnKeyDown( key)
local self = this.obj
if self.waitingForKey then
local keyPressed = key;
if keyPressed == "ESCAPE" then
keyPressed = ""
else
if ( keyPressed == "BUTTON1" or keyPressed == "BUTTON2" ) then
return;
end
if ( keyPressed == "UNKNOWN" ) then
return;
end
if ( keyPressed == "SHIFT" or keyPressed == "CTRL" or keyPressed == "ALT") then
return;
end
if ( keyPressed == "LSHIFT" or keyPressed == "LCTRL" or keyPressed == "LALT") then
return;
end
if ( keyPressed == "RSHIFT" or keyPressed == "RCTRL" or keyPressed == "RALT") then
return;
end
if ( IsShiftKeyDown() ) then
keyPressed = "SHIFT-"..keyPressed;
end
if ( IsControlKeyDown() ) then
keyPressed = "CTRL-"..keyPressed;
end
if ( IsAltKeyDown() ) then
keyPressed = "ALT-"..keyPressed;
end
end
if self.setFunc and not self.disabled then
local validated = true
if keyPressed == "" then
keyPressed = nil
else
if self.keybindingOnly and not self.keybindingOnly[keyPressed] then
validated = false
end
if self.keybindingExcept and self.keybindingExcept[keyPressed] then
validated = false
end
end
if validated then
self.setFunc(getArgs(self,"setArg",1,keyPressed))
end
if self.causesRefresh or self.fullRefresh then
self.parent:Refresh(self.fullRefresh)
end
end
self:Refresh()
this:EnableKeyboard(false)
self.msgframe:Hide()
this:UnlockHighlight()
self.waitingForKey = nil
end
end
local function Keybinding_OnMouseDown( button)
if ( button == "LeftButton" or button == "RightButton" ) then
return
elseif ( button == "MiddleButton" ) then
button = "BUTTON3";
elseif ( button == "Button4" ) then
button = "BUTTON4"
elseif ( button == "Button5" ) then
button = "BUTTON5"
end
Keybinding_OnKeyDown( button)
end
local function keybindingMsgFixWidth()
this:SetWidth(this.msg:GetWidth()+10)
this:SetScript("OnUpdate",nil)
end
function WaterfallKeybinding.prototype:init()
WaterfallKeybinding.super.prototype.init(self,"Button","UIPanelButtonTemplate")
local frame = self.frame
--local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
local text = frame:GetFontString()
text:SetPoint("LEFT",frame,"LEFT",7,0)
text:SetPoint("RIGHT",frame,"RIGHT",-7,0)
frame:SetScript("OnClick",Keybinding_OnClick)
frame:SetScript("OnKeyDown",Keybinding_OnKeyDown)
frame:SetScript("OnEnter",Control_OnEnter)
frame:SetScript("OnLeave",Control_OnLeave)
frame:SetScript("OnMouseDown",Keybinding_OnMouseDown)
frame:RegisterForClicks("AnyDown")
frame:EnableMouse()
frame:SetHeight(24)
frame:SetWidth(DEFAULT_CONTROL_WIDTH)
local msgframe = CreateFrame("Frame",nil,UIParent)
msgframe:SetHeight(30)
msgframe:SetBackdrop(ControlBackdrop)
msgframe:SetBackdropColor(0,0,0)
msgframe:SetFrameStrata("DIALOG")
msgframe:SetFrameLevel(20)
self.msgframe = msgframe
local msg = msgframe:CreateFontString(nil,"OVERLAY","GameFontNormal")
msg:SetText("Press a key to bind, ESC to clear the binding or click the button again to cancel")
msgframe.msg = msg
msg:SetPoint("TOPLEFT",msgframe,"TOPLEFT",5,-5)
msgframe:SetScript("OnUpdate", keybindingMsgFixWidth)
msgframe:SetPoint("TOP",frame,"BOTTOM",0,-2)
msgframe:Hide()
end
function WaterfallKeybinding.prototype:SetText(text)
self.frame:SetText(text)
end
function WaterfallKeybinding.prototype:CleanUp()
self.frame:ClearAllPoints()
self.frame:Hide()
self.width = nil
self.height = nil
self.noNewLine = nil
self.causesRefresh = nil
self.fullRefresh = nil
self.treeRefresh = nil
self:SetText("")
self:SetFunc("disabled",nil)
self:SetFunc("exec",nil)
self.waitingForKey = nil
self.msgframe:Hide()
end
function WaterfallKeybinding.prototype:Refresh()
if self.getFunc then
local text = self.getFunc(getArgs(self,"getArg",1))
self:SetText(text or "")
end
if self.disabledFunc then
self.disabled = self.disabledFunc(getArgs(self,"disabledArg",1))
if self.inverseDisabled then
self.disabled = not self.disabled
end
end
if self.disabled then
self.frame:Disable()
else
self.frame:Enable()
end
if self.width then
self:SetWidth(self.width)
else
self:SetWidth(DEFAULT_CONTROL_WIDTH)
end
end
-----------------
-- Slider Class --
-----------------
local function Slider_OnValueChanged()
local self = this.obj
if not this.setup then
local func = self.setFunc
local newvalue
newvalue = this:GetValue()
if newvalue ~= self.value and not self.disabled then
if self.bigStep > 0 then
self.value = math.floor((newvalue - self.min) / self.bigStep + 0.5) * self.bigStep + self.min
else
self.value = newvalue
end
if func and not self.isInit then
if (self.finalSetOnly) then
self.finalSetValue = self.value
else
func(getArgs(this.obj,"setArg",1,self.value))
end
end
end
if self.value then
this.obj.valuetext:SetText(math.floor(self.value*10)/10)
end
end
end
local function Slider_OnMouseUp()
local self = this.obj
if (self.finalSetValue) then
local func = self.setFunc
if func then
func(getArgs(this.obj,"setArg",1,self.finalSetValue))
end
end
if self.causesRefresh or self.fullRefresh then
self.parent:Refresh(self.fullRefresh)
end
end
local SliderBackdrop = {
bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
tile = true, tileSize = 8, edgeSize = 8,
insets = { left = 3, right = 3, top = 6, bottom = 6 }
}
function WaterfallSlider.prototype:init()
WaterfallSlider.super.prototype.init(self,"Frame")
local frame = self.frame
self.slider = CreateFrame("Slider",nil,frame)
local slider = self.slider
slider:SetScript("OnEnter",Control_OnEnter)
slider:SetScript("OnLeave",Control_OnLeave)
slider:SetScript("OnMouseUp", Slider_OnMouseUp)
slider.obj = self
slider:SetOrientation("HORIZONTAL")
frame:SetWidth(DEFAULT_CONTROL_WIDTH)
slider:SetHeight(17)
slider:SetHitRectInsets(0,0,-10,-10)
slider:SetBackdrop(SliderBackdrop)
self.text = slider:CreateFontString(nil,"ARTWORK","GameFontNormalSmall")
self.text:SetPoint("TOP",frame,"TOP",0,-2)
self.lowtext = slider:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall")
self.lowtext:SetPoint("TOPLEFT",slider,"BOTTOMLEFT",2,3)
self.hightext = slider:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall")
self.hightext:SetPoint("TOPRIGHT",slider,"BOTTOMRIGHT",-2,3)
self.valuetext = slider:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall")
self.valuetext:SetPoint("TOP",slider,"BOTTOM",0,3)
slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Horizontal")
frame:SetWidth(DEFAULT_CONTROL_WIDTH)
frame:SetHeight(40)
slider:SetPoint("TOP",self.text,"BOTTOM",0,0)
slider:SetPoint("LEFT",frame,"LEFT",0,0)
slider:SetPoint("RIGHT",frame,"RIGHT",0,0)
if self.getFunc then
self.isInit = true
self.value = self.getFunc(getArgs(self,"getArg",1))
self.isInit = nil
end
slider:SetValue(self.value or 0)
slider:SetScript("OnValueChanged",Slider_OnValueChanged)
end
function WaterfallSlider.prototype:CleanUp()
self.frame:ClearAllPoints()
self.frame:Hide()
self.width = nil
self.height = nil
self.noNewLine = nil
self.causesRefresh = nil
self.fullRefresh = nil
self.treeRefresh = nil
self:SetText("")
self:SetFunc("disabled",nil)
self:SetFunc("get",nil)
self:SetFunc("set",nil)
self.min = nil
self.max = nil
self.step = nil
self.value = nil
self.parent = nil
self.disabled = nil
end
function WaterfallSlider.prototype:SetText(text)
self.text:SetText(text)
end
function WaterfallSlider.prototype:Refresh()
local frame = self.slider
frame.setup = true
frame:SetMinMaxValues(self.min or 0,self.max or 100)
self.lowtext:SetText(self.min or 0)
self.hightext:SetText(self.max or 100)
frame:SetValueStep(self.step or 1)
frame.setup = nil
if self.getFunc then
local newvalue
newvalue = self.getFunc(getArgs(self,"getArg",1))
if newvalue ~= self.value then
self.isInit = true
frame:SetValue(newvalue)
self.isInit = nil
end
end
if self.disabledFunc then
self.disabled = self.disabledFunc(getArgs(self,"disabledArg",1))
if self.inverseDisabled then
self.disabled = not self.disabled
end
end
if self.disabled then
self.slider:EnableMouse(false)
self.text:SetTextColor(.5,.5,.5)
self.hightext:SetTextColor(.5,.5,.5)
self.lowtext:SetTextColor(.5,.5,.5)
self.valuetext:SetTextColor(.5,.5,.5)
else
self.slider:EnableMouse(true)
self.text:SetTextColor(1,1,1)
self.hightext:SetTextColor(1,1,1)
self.lowtext:SetTextColor(1,1,1)
self.valuetext:SetTextColor(1,1,1)
end
if self.width then
self:SetWidth(self.width)
else
self:SetWidth(DEFAULT_CONTROL_WIDTH)
end
end
-------------------
-- TextBox Class --
-------------------
local function TextBox_OnEscapePressed()
this:ClearFocus()
end
local function TextBox_OnEnterPressed()
local self = this.obj
local value = this:GetText()
if self.toNumber then
value = tonumber(value)
--TODO: same message as a failed validation
if not value then return end
end
if self.setFunc and not self.disabled then
local validated = true
if type(self.validateFunc) == "function" then
validated = self.validateFunc(getArgs(self,"validateArg",1,value))
if validated and self.validateModifies then
value = validated
local setOnTextChanged = self.setOnTextChanged
self.setOnTextChanged = nil
this:SetText(value)
self.setOnTextChanged = setOnTextChanged
end
elseif type(self.validateFunc) == "table" then
validated = self.validateFunc[value]
end
--TODO: message for failed validation
if validated then
if self.parseList then
self.setFunc(getArgs(self,"setArg",1,parseList(value)))
else
self.setFunc(getArgs(self,"setArg",1,value))
end
end
if self.getFunc == false then
self:SetText("")
end
if self.causesRefresh or self.fullRefresh then
self.parent:Refresh(self.fullRefresh)
end
end
end
local function TextBox_OnTextChanged()
local self = this.obj
local value = this:GetText()
if self.setOnTextChanged then
TextBox_OnEnterPressed()
end
if self.changedFunc and not self.disabled then
if self.parseList then
self.changedFunc(getArgs(self,"changedArg",1,parseList(value)))
else
self.changedFunc(getArgs(self,"changedArg",1,value))
end
end
end
function WaterfallTextBox.prototype:init()
WaterfallTextBox.super.prototype.init(self,"EditBox")
local frame = self.frame
--local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
--self.text = text
frame:SetScript("OnEnter",Control_OnEnter)
frame:SetScript("OnLeave",Control_OnLeave)
frame:SetFontObject(ChatFontNormal)
frame:SetScript("OnEscapePressed",TextBox_OnEscapePressed)
frame:SetScript("OnEnterPressed",TextBox_OnEnterPressed)
frame:SetScript("OnTextChanged",TextBox_OnTextChanged)
frame:SetTextInsets(5,5,3,3)
frame:SetMaxLetters(256)
frame:SetAutoFocus(false)
frame:SetHeight(26)
frame:SetWidth(DEFAULT_CONTROL_WIDTH)
frame:SetBackdrop(ControlBackdrop)
frame:SetBackdropColor(0,0,0)
end
local function UglyScrollLeft()
this:HighlightText(0,1);
this:Insert(" "..strsub(this:GetText(),1,1));
this:HighlightText(0,1);
this:Insert("");
this:SetScript("OnUpdate", nil);
end
function WaterfallTextBox.prototype:SetText(text)
self.frame:SetText(text)
self.frame:SetScript("OnUpdate", UglyScrollLeft);
end
function WaterfallTextBox.prototype:CleanUp()
self.frame:ClearAllPoints()
self.frame:Hide()
self.width = nil
self.height = nil
self.noNewLine = nil
self.causesRefresh = nil
self.fullRefresh = nil
self.treeRefresh = nil
self.setOnTextChanged = nil
self:SetText("")
self:SetFunc("disabled",nil)
self:SetFunc("get",nil)
self:SetFunc("set",nil)
self:SetFunc("changed",nil)
end
function WaterfallTextBox.prototype:Refresh()
if self.getFunc then
local text = self.getFunc(getArgs(self,"getArg",1))
if text then
self:SetText(text)
end
end
if self.disabledFunc then
self.disabled = self.disabledFunc(getArgs(self,"disabledArg",1))
if self.inverseDisabled then
self.disabled = not self.disabled
end
end
if self.disabled then
self.frame:EnableMouse(false)
self.frame:ClearFocus()
self.frame:SetTextColor(0.5,0.5,0.5)
else
self.frame:EnableMouse(true)
self.frame:SetTextColor(1,1,1)
end
if self.width then
self:SetWidth(self.width)
else
self:SetWidth(DEFAULT_CONTROL_WIDTH)
end
end
--------------------
-- DropDown Class --
--------------------
local function Dropdown_OnEnterPressed()
local self = this.obj
if self.setFunc and not self.disabled then
local ret
if self.strict and this.value then
ret = this.value
else
ret = this:GetText()
end
if self.parseList then
self.setFunc(getArgs(self,"setArg",1,parseList(ret)))
else
self.setFunc(getArgs(self,"setArg",1,ret))
end
if self.causesRefresh or self.fullRefresh then
self.parent:Refresh(self.fullRefresh)
end
end
end
local function Dropdown_TogglePullout()
local self = this.obj
if self.open then
self.open = nil
self.pullout:Hide()
else
self.open = true
self:BuildPullout()
if self.lines[1] and self.lines[1]:IsShown() then
self.pullout:Show()
end
end
end
local function Dropdown_OnHide()
this.obj.pullout:Hide()
end
local function Dropdown_LineClicked()
local self = this.obj
self.open = false
self.pullout:Hide()
self.editbox:SetText(this.text:GetText())
self.editbox.value = this.value
Dropdown_OnEnterPressed(self.editbox)
end
local function Dropdown_LineEnter()
this.highlight:Show()
end
local function Dropdown_LineLeave()
this.highlight:Hide()
end
function WaterfallDropdown.prototype:init()
WaterfallDropdown.super.prototype.init(self,"Frame")
local frame = self.frame
frame.obj = self
--local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
--self.text = text
local editbox = CreateFrame("EditBox",nil,frame)
self.editbox = editbox
editbox.obj = self
editbox:SetFontObject(ChatFontNormal)
editbox:SetScript("OnEscapePressed",TextBox_OnEscapePressed)
editbox:SetScript("OnEnterPressed",Dropdown_OnEnterPressed)
frame:SetScript("OnEnter",Control_OnEnter)
frame:SetScript("OnLeave",Control_OnLeave)
editbox:SetScript("OnEnter",Control_OnEnter)
editbox:SetScript("OnLeave",Control_OnLeave)
editbox:SetTextInsets(5,5,3,3)
editbox:SetMaxLetters(256)
editbox:SetAutoFocus(false)
editbox:SetBackdrop(ControlBackdrop)
editbox:SetBackdropColor(0,0,0)
editbox:SetPoint("TOPLEFT",frame,"TOPLEFT",0,0)
editbox:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-20,0)
local button = CreateFrame("Button",nil,frame)
self.button = button
button.obj = self
button:SetWidth(24)
button:SetHeight(24)
button:SetScript("OnEnter",Control_OnEnter)
button:SetScript("OnLeave",Control_OnLeave)
button:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up")
button:GetNormalTexture():SetTexCoord(.09,.91,.09,.91)
button:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Down")
button:GetPushedTexture():SetTexCoord(.09,.91,.09,.91)
button:SetDisabledTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Disabled")
button:GetDisabledTexture():SetTexCoord(.09,.91,.09,.91)
button:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight", "ADD")
button:GetHighlightTexture():SetTexCoord(.09,.91,.09,.91)
button:SetPoint("RIGHT",frame,"RIGHT",0,0)
button:SetScript("OnClick",Dropdown_TogglePullout)
frame:SetHeight(26)
frame:SetWidth(DEFAULT_CONTROL_WIDTH)
frame:SetScript("OnHide",Dropdown_OnHide)
local pullout = CreateFrame("Frame",nil,UIParent)
self.pullout = pullout
frame:EnableMouse()
pullout:SetBackdrop(ControlBackdrop)
pullout:SetBackdropColor(0,0,0)
pullout:SetFrameStrata("DIALOG")
pullout:SetFrameLevel(20)
pullout:SetPoint("TOPLEFT",frame,"BOTTOMLEFT",0,0)
pullout:SetPoint("TOPRIGHT",frame,"BOTTOMRIGHT",-24,0)
pullout:SetClampedToScreen(true)
pullout:Hide()
self.lines = {}
end
function WaterfallDropdown.prototype:SetText(text)
self.editbox:SetText(text)
end
function WaterfallDropdown.prototype:CleanUp()
self.frame:ClearAllPoints()
self.frame:Hide()
self.width = nil
self.height = nil
self.noNewLine = nil
self.causesRefresh = nil
self.fullRefresh = nil
self.treeRefresh = nil
self:SetText("")
self:SetFunc("disabled",nil)
self:SetFunc("get",nil)
self:SetFunc("set",nil)
self.editbox.value = nil
self.columns = nil
end
function WaterfallDropdown.prototype:Refresh()
local list = self.list
if self.getFunc then
local newval = self.getFunc(getArgs(self,"getArg",1))
if newval then
if self.strict then
if type(list) == "table" then
local value
for k, text in pairs(list) do
if type(k) == "string" then
value = k
else
value = text
end
if newval == value then
self:SetText(text)
self.editbox.value = value
break
end
end
elseif type(list) == "function" then
for i, text, value in list() do
if newval == value then
self:SetText(text)
self.editbox.value = value
break
end
end
end
else
self.editbox:SetText(newval)
self.editbox.value = newval
end
else
self.editbox:SetText("")
self.editbox.value = newval
end
end
if self.disabledFunc then
self.disabled = self.disabledFunc(getArgs(self,"disabledArg",1))
if self.inverseDisabled then
self.disabled = not self.disabled
end
end
if self.disabled then
self.editbox:EnableMouse(false)
self.editbox:ClearFocus()
self.editbox:SetTextColor(0.5,0.5,0.5)
self.button:Disable()
else
self.button:Enable()
if self.strict then
self.editbox:EnableMouse(false)
self.editbox:ClearFocus()
self.editbox:SetTextColor(1,1,1)
else
self.editbox:EnableMouse(true)
self.editbox:SetTextColor(1,1,1)
end
end
if self.width then
self:SetWidth(self.width)
else
self:SetWidth(DEFAULT_CONTROL_WIDTH)
end
end
local function div(a,b)
return a - math.floor(a/b)*b
end
local ddsort = {}
function WaterfallDropdown.prototype:BuildPullout()
local list = self.list
local lines = self.lines
local totalheight = 10
self:ClearPullout()
if type(list) == "table" then
for k, v in pairs(list) do
tinsert(ddsort,k)
end
table.sort(ddsort)
local columns = tonumber(self.columns)
local columnHeight, columnWidth
local columnCount = 0
self.pullout:ClearAllPoints()
if (columns) then
columnHeight = math.floor((table.getn(ddsort)) / columns) + 2
columnWidth = self.pullout:GetWidth()
self.pullout:SetPoint("TOPLEFT",self.frame,"BOTTOMRIGHT", -1 * DEFAULT_CONTROL_WIDTH * columns - 24,0)
self.pullout:SetPoint("TOPRIGHT",self.frame,"BOTTOMRIGHT",-24,0)
else
self.pullout:SetPoint("TOPLEFT",self.frame,"BOTTOMRIGHT", -1 * DEFAULT_CONTROL_WIDTH - 24,0)
self.pullout:SetPoint("TOPRIGHT",self.frame,"BOTTOMRIGHT",-24,0)
columnHeight = table.getn(ddsort) + 1
end
for i, value in pairs(ddsort) do
local text = list[value]
if (div((i - 1), (columnHeight - 1)) == 0) then
columnCount = columnCount + 1
end
if (lines[i]) then
self:UpdateLine(lines[i], math.mod(i-1, (columnHeight-1)), columnCount)
else
lines[i] = self:CreateLine(math.mod(i-1, (columnHeight-1)), columnCount)
end
if i == 1 then
lines[i]:SetPoint("TOP",self.pullout,"TOP",0,-5)
else
if (columns and (div((i - 1), columnHeight) == 0)) then
lines[i]:SetPoint("TOP",self.pullout,"TOP",0,-5)
else
lines[i]:SetPoint("TOP",lines[i-1],"BOTTOM",0,0)
end
end
lines[i].text:SetText(text)
if type(value) == "string" then
lines[i].value = value
else
lines[i].value = text
end
if lines[i].value == self.editbox.value and self.getFunc then
lines[i].check:Show()
else
lines[i].check:Hide()
end
lines[i]:Show()
end
totalheight = totalheight + 17 * (columnHeight-1)
for k in pairs(ddsort) do
ddsort[k] = nil
end
table_setn(ddsort,0)
elseif type(list) == "function" then
for i, text, value in list() do
if not lines[i] then
lines[i] = self:CreateLine()
if i == 1 then
lines[i]:SetPoint("TOP",self.pullout,"TOP",0,-5)
else
lines[i]:SetPoint("TOP",lines[i-1],"BOTTOM",0,0)
end
end
lines[i].text:SetText(text)
lines[i].value = value
lines[i]:Show()
totalheight = totalheight + 17
end
end
self.pullout:SetHeight(totalheight)
end
function WaterfallDropdown.prototype:ClearPullout()
if self.lines then
for i, line in ipairs(self.lines) do
line.text:SetText("")
line:Hide()
end
end
self.pullout:SetHeight(10)
self.pullout:SetWidth(DEFAULT_CONTROL_WIDTH)
end
-- For large list, if specified, 0 based row, 1 based column gives a grid.
function WaterfallDropdown.prototype:CreateLine(row, column)
local frame = CreateFrame("Button",nil,self.pullout)
frame.obj = self
frame.text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
frame.text:SetTextColor(1,1,1)
frame.text:SetJustifyH("LEFT")
frame:SetFrameLevel(25)
frame:SetFrameStrata("DIALOG")
local highlight = frame:CreateTexture(nil, "OVERLAY")
frame.highlight = highlight
highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
highlight:SetBlendMode("ADD")
local check = frame:CreateTexture("OVERLAY")
frame.check = check
check:SetWidth(16)
check:SetHeight(16)
check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
frame:SetScript("OnClick",Dropdown_LineClicked)
frame:SetScript("OnEnter",Dropdown_LineEnter)
frame:SetScript("OnLeave",Dropdown_LineLeave)
return self:UpdateLine(frame, row, column)
end
function WaterfallDropdown.prototype:UpdateLine(frame, row, column)
if (column) then
frame:SetPoint("TOPLEFT",self.pullout,"TOPLEFT",6 + (column - 1) * DEFAULT_CONTROL_WIDTH,-5 - row*17)
frame:SetPoint("BOTTOMRIGHT",self.pullout,"TOPLEFT",-6 + column * DEFAULT_CONTROL_WIDTH,-5 - (row+1)*17)
else
frame:SetPoint("LEFT",self.pullout,"LEFT",6,0)
frame:SetPoint("RIGHT",self.pullout,"RIGHT",-6,0)
end
frame.text:SetPoint("TOPLEFT",frame,"TOPLEFT",16,0)
frame.text:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,0)
frame.highlight:SetAllPoints(frame)
frame.highlight:Hide()
frame.check:SetPoint("LEFT",frame,"LEFT",0,0)
return frame
end
-----------------------------
-- WaterfallTreeView Class --
-----------------------------
local function treeviewOnSizeChanged()
this.obj:SizeChanged()
end
local function treeviewOnMouseWheel()
this.obj:MoveScroll(arg1)
end
local function treeviewOnScrollValueChanged()
this.obj:SetScroll(arg1)
end
local function treeviewSizerOnMouseUp()
this:GetParent():StopMovingOrSizing() this.obj.parent:ReAnchorTree()
end
function WaterfallTreeView.prototype:init(parent)
WaterfallTreeView.super.prototype.init(self)
--Parent WaterfallFrame Object
self.parent = parent
local frame = CreateFrame("Frame",nil,parent.frame)
frame.obj = self
local scrollframe = CreateFrame("ScrollFrame",nil,frame)
local scrollchild = CreateFrame("Frame",nil,scrollframe)
local scrollbar = CreateFrame("Slider",nil,scrollframe,"UIPanelScrollBarTemplate")
frame:SetBackdrop(ControlBackdrop)
frame:SetBackdropBorderColor(0.6, 0.6, 0.6)
frame:SetBackdropColor(0.1, 0.1, 0.1)
frame:SetScript("OnSizeChanged", treeviewOnSizeChanged)
frame:SetFrameLevel(2)
frame:SetFrameStrata("DIALOG")
frame:SetResizable(true)
self.scrollframe = scrollframe
self.scrollchild = scrollchild
self.frame = frame
self.scrollbar = scrollbar
scrollframe:SetScrollChild(scrollchild)
scrollframe:SetPoint("TOPLEFT",frame,"TOPLEFT",8,-12)
scrollframe:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-28,12)
scrollframe:EnableMouseWheel(true)
scrollframe:SetScript("OnMouseWheel", treeviewOnMouseWheel)
scrollframe.obj = self
scrollchild:SetPoint("TOPLEFT",scrollframe,"TOPLEFT",0,0)
scrollchild:SetPoint("TOPRIGHT",scrollframe,"TOPRIGHT",0,0)
scrollchild:SetHeight(400)
scrollbar:SetPoint("TOPLEFT",scrollframe,"TOPRIGHT",0,-16)
scrollbar:SetPoint("BOTTOMLEFT",scrollframe,"BOTTOMRIGHT",0,16)
scrollbar:SetMinMaxValues(0,1000)
scrollbar:SetValueStep(1)
scrollbar:SetValue(0)
scrollbar:SetWidth(16)
scrollbar:SetScript("OnValueChanged", treeviewOnScrollValueChanged)
self.scrollvalue = 0
scrollchild.lines = {}
self.linetables = {}
self.sections = {}
scrollbar.obj = self
local sizer = CreateFrame("Frame",nil,frame)
sizer:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
sizer:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,0)
sizer:SetWidth(7)
sizer:EnableMouse()
sizer:SetScript("OnMouseDown",sizereOnMouseDown)
sizer:SetScript("OnMouseUp", treeviewSizerOnMouseUp)
self.sizer = sizer
sizer.obj = self
self:Refresh()
end
function WaterfallTreeView.prototype:SetScroll(value)
local frame, child = self.scrollframe, self.scrollchild
local viewheight = frame:GetHeight()
local height = child:GetHeight()
local offset
if viewheight > height then
offset = 0
else
offset = floor((height - viewheight) / 1000.0 * value)
end
child:ClearAllPoints()
child:SetPoint("TOPLEFT",frame,"TOPLEFT",0,offset)
child:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,offset)
child.offset = offset
self.scrollvalue = value
end
function WaterfallTreeView.prototype:SizeChanged()
self:FixScroll()
self.parent:ReAnchorTree()
end
function WaterfallTreeView.prototype:MoveScroll(value)
local frame, child = self.scrollframe, self.scrollchild
local height, viewheight = frame:GetHeight(), child:GetHeight()
if height > viewheight then
self.scrollbar:Hide()
else
self.scrollbar:Show()
local diff = height - viewheight
local delta = 1
if value < 0 then
delta = -1
end
self.scrollbar:SetValue(math.min(math.max(self.scrollvalue + delta*(1000/(diff/45)),0), 1000))
end
end
function WaterfallTreeView.prototype:FixScroll()
if self.noFixScroll then return end
local frame, child = self.scrollframe, self.scrollchild
local height, viewheight = frame:GetHeight(), child:GetHeight()
local offset = self.scrollchild.offset
if not offset then
offset = 0
end
local curvalue = self.scrollbar:GetValue()
if viewheight < height then
self.scrollbar:Hide()
self.scrollbar:SetValue(0)
else
self.scrollbar:Show()
local value = (offset / (viewheight - height) * 1000)
if value > 1000 then value = 1000 end
self.scrollbar:SetValue(value)
self:SetScroll(value)
if value < 1000 then
child:ClearAllPoints()
child:SetPoint("TOPLEFT",frame,"TOPLEFT",0,offset)
child:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,offset)
child.offset = offset
end
end
end
function WaterfallTreeView.prototype:ToggleExpand(id)
self.status[id] = not self.status[id]
self:Refresh()
end
function WaterfallTreeView.prototype:Refresh(noupdate)
self.noFixScroll = true
self:Clear()
if not self.contents then return end
if self.contentsFunc and not noupdate then
self.parent.controlcount = 0
currentframe = self.parent
self.contentsFunc(self.contents, self.status, getArgs(self, "contentsArg", 1))
currentframe = nil
end
if self.type == "SECTIONS" then
for i, section in ipairs(self.contents) do
if not section.hidden then
self:AddSection(i,section)
end
end
local height = 0
for i, section in ipairs(self.sections) do
height = height + section:GetHeight()
end
self.scrollchild:SetHeight(height+3)
else
local level = 0
local index = 1
for i, line in ipairs(self.contents) do
if not line.hidden then
index = self:AddLine(index,line,level)
end
end
self.scrollchild:SetHeight(index*16)
end
self.noFixScroll = nil
self:FixScroll()
end
local function isSectionSelected(section, selected)
if not selected then return end
if section.id == selected then
return true
end
for i,v in ipairs(section.lines) do
if i <= section.numlines then
if v.id == selected then
return true
end
end
end
end
function WaterfallTreeView.prototype:Collapse()
for k in pairs(self.status) do
self.status[k] = false
end
end
function WaterfallTreeView.prototype:AddSection(index,line)
local sections = self.sections
local id = line.id
if not sections[index] then
sections[index] = getObj(WaterfallTreeSection,self)
local section = sections[index]
section:SetParent(self)
if index == 1 then
section:SetPoint("TOPLEFT",self.scrollchild,"TOPLEFT",0,0)
section:SetPoint("TOPRIGHT",self.scrollchild,"TOPRIGHT",0,0)
else
section:SetPoint("TOPLEFT",sections[index-1],"BOTTOMLEFT",0,0)
section:SetPoint("TOPRIGHT",sections[index-1],"BOTTOMRIGHT",0,0)
end
end
local section = sections[index]
section:SetText(line.text)
section:SetID(line.id)
section:SetTooltipText(line.tooltipTitle,line.tooltipText)
if self.status[id] == nil then
self.status[id] = not not line.isOpen
end
local handler = line.handler
local disabled = checkNegatable(line.disabled,handler)
section.disabled = disabled
section:SetColor(self.parent:GetColor())
if line.hasOptions then
section:AddLine(line.text,line.id,line.id == self.selected,disabled,line.tooltipTitle,line.tooltipText)
end
local firstid
for i, item in ipairs(line) do
if not item.hidden then
if not firstid then
firstid = item.id
end
local itemdisabled = checkNegatable(item.disabled,handler)
section:AddLine(item.text,item.id,item.id == self.selected,itemdisabled or disabled,item.tooltipTitle,item.tooltipText)
end
end
if self.selected == section.id and not line.hasOptions then
self:SetSelected(firstid)
return
end
if isSectionSelected(section, self.selected) then
self.status[section.id] = true
end
section:SetExpanded(self.status[line.id] and not disabled)
section:Show()
end
function WaterfallTreeView.prototype:Clear()
for i, frame in ipairs(self.scrollchild.lines) do
releaseObj(frame)
self.scrollchild.lines[i] = nil
end
for k in pairs(self.linetables) do
self.linetables[k] = nil
end
for i, section in ipairs(self.sections) do
releaseObj(section)
self.sections[i] = nil
end
self.numlines = 0
self.scrollchild:SetHeight(1)
self:FixScroll()
end
function WaterfallTreeView.prototype:ClearSelection()
self.selected = nil
end
function WaterfallTreeView.prototype:GetSelected()
return self.selected
end
function WaterfallTreeView.prototype:SetSelected(lineid, noupdate)
self.selected = lineid
self:Refresh(noupdate)
if not noupdate then
self.parent:ChangePane(lineid)
end
end
function WaterfallTreeView.prototype:AddLine(index,line,level,disabled)
local lines = self.scrollchild.lines
local text, hasChildren, isSelected, isOpen
text = line.text or ""
hasChildren = table.getn(line) > 0
local id = line.id
if self.status[id] == nil then
self.status[id] = not not line.isOpen
end
isOpen = self.status[id] and not disabled
isSelected = self.selected == id
if not lines[index] then
lines[index] = getObj(WaterfallTreeLine)
lines[index]:SetParent(self)
end
local disabled
if type(line.disabled) == "function" then
disabled = line.disabled()
else
disabled = line.disabled
end
lines[index]:Setup(index,id,text,level,hasChildren,isSelected,isOpen,disabled)
lines[index]:SetTooltipText(line.tooltipTitle,line.tooltipText)
lines[index]:SetIcon(line.icon)
self.linetables[index] = line
index = index + 1
if isOpen then
for i, childline in ipairs(line) do
if not childline.hidden then
index = self:AddLine(index,childline,level+1)
end
end
end
return index
end
function WaterfallTreeView.prototype:SetType(type)
if not type then
self.type = "TREE"
else
self.type = type
end
end
function WaterfallTreeView.prototype:SetContent(contents, status, func, ...)
self.contents = contents
self.status = status
self.contentsFunc = func
local i = 1
while self["contentsArg"..i] do
self["contentsArg"..i] = nil
i = i + 1
end
for i = 1 , table.getn(arg) do
self["contentsArg"..i] = arg[i]
end
self:Refresh()
self:FixScroll()
end
function WaterfallTreeView.prototype:CleanUp()
self.contents = nil
self.selected = nil
self.contentsFunc = nil
local i = 1
while self["contentsArg"..i] do
self["contentsArg"..i] = nil
i = i + 1
end
self.selected = nil
self:Refresh()
end
--------------------
-- WaterfallTreeLine Class --
--------------------
local function TreeLine_OnEnter()
if not this.obj.disabled then
this.highlight:SetAlpha(1)
this.highlight:Show()
showGameTooltip(this.obj)
end
end
local function TreeLine_OnLeave()
if not this.obj.isSelected then
this.highlight:Hide()
else
this.highlight:SetAlpha(0.7)
end
GameTooltip:Hide()
end
local function TreeLine_OnClick()
if not this.obj.disabled then
this.obj.parent:SetSelected(this.obj.id)
end
end
local function TreeLine_OnExpandClick()
if not this.obj.disabled then
this.obj.parent:ToggleExpand(this.obj.id)
end
end
function WaterfallTreeLine.prototype:init()
WaterfallTreeLine.super.prototype.init(self)
local frame = CreateFrame("Button",nil,nil)
self.frame = frame
local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormal")
text:SetJustifyH("LEFT")
text:SetTextColor(1,1,1)
frame:SetHeight(16)
frame:EnableMouse(true)
frame:SetScript("OnEnter",TreeLine_OnEnter)
frame:SetScript("OnLeave",TreeLine_OnLeave)
frame:SetScript("OnClick",TreeLine_OnClick)
frame:SetFrameLevel(10)
frame:SetFrameStrata("DIALOG")
local highlight = frame:CreateTexture(nil, "BACKGROUND")
highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
highlight:SetBlendMode("ADD")
highlight:SetAllPoints(frame)
highlight:Hide()
local expand = CreateFrame("Button",nil,frame)
expand.obj = self
expand:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up")
expand:SetPushedTexture("Interface\\Buttons\\UI-PlusButton-Down")
expand:SetDisabledTexture("Interface\\Buttons\\UI-PlusButton-Disabled")
expand:SetHighlightTexture("Interface\\Buttons\\UI-PlusButton-Hilight")
expand:SetScript("OnClick",TreeLine_OnExpandClick)
expand:SetFrameLevel(21)
expand:SetWidth(16)
expand:SetHeight(16)
local icon = frame:CreateTexture(nil,"OVERLAY")
icon:SetWidth(16)
icon:SetHeight(16)
icon:SetPoint("LEFT",expand,"RIGHT",1,0)
self.icon = icon
expand:SetPoint("LEFT",frame,"LEFT",0,0)
text:SetPoint("LEFT",icon,"RIGHT",2,0)
text:SetPoint("RIGHT",frame,"RIGHT",0,0)
frame.obj = self
frame.text = text
frame.highlight = highlight
frame.expand = expand
self.expand = expand
self.highlight = highlight
self.text = text
end
function WaterfallTreeLine.prototype:UpdateExpandButton()
local expand = self.expand
if self.hasChildren then
if self.isOpen then
expand:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up")
expand:SetPushedTexture("Interface\\Buttons\\UI-MinusButton-Down")
expand:SetDisabledTexture("Interface\\Buttons\\UI-MinusButton-Disabled")
expand:Enable()
expand:SetWidth(16)
else
if self.disabled then
expand:Disable()
else
expand:Enable()
end
expand:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up")
expand:SetPushedTexture("Interface\\Buttons\\UI-PlusButton-Down")
expand:SetDisabledTexture("Interface\\Buttons\\UI-PlusButton-Disabled")
expand:SetWidth(16)
end
else
expand:SetNormalTexture(nil)
expand:SetPushedTexture(nil)
expand:SetDisabledTexture(nil)
expand:Disable()
expand:SetWidth(16)
end
end
function WaterfallTreeLine.prototype:CleanUp()
self:ClearAllPoints()
self:Hide()
self:SetText("")
self.disabled = nil
self.handler = nil
self.name = nil
end
function WaterfallTreeLine.prototype:Setup(index, id, text, level, hasChildren, isSelected, isOpen, disabled)
self.level = level
self.hasChildren = hasChildren
self.isSelected = isSelected
self.isOpen = isOpen and not disabled
self.index = index
self.id = id
self.disabled = disabled
self:UpdateExpandButton()
self.expand:SetPoint("LEFT",self.frame,"LEFT",level*8,0)
self:SetText(text)
if disabled then
self.text:SetTextColor(0.5,0.5,0.5)
else
self.text:SetTextColor(1,1,1)
end
self.frame:SetPoint("TOPLEFT",self.parent.scrollchild,"TOPLEFT",0,-(index-1)*16)
self.frame:SetPoint("TOPRIGHT",self.parent.scrollchild,"TOPRIGHT",0,-(index-1)*16)
if self.isSelected then
self.highlight:Show()
self.highlight:SetAlpha(0.7)
else
self.highlight:Hide()
end
self.frame:Show()
end
function WaterfallTreeLine.prototype:SetIcon(iconpath)
local icon = self.icon
if iconpath then
icon:SetTexture(iconpath)
icon:SetWidth(16)
else
icon:SetTexture(nil)
icon:SetWidth(1)
end
end
function WaterfallTreeLine.prototype:SetText(text)
self.text:SetText(text)
end
function WaterfallTreeLine.prototype:SetTooltipText(title,text)
self.tooltipTitle = title
self.tooltipText = text
end
function WaterfallTreeLine.prototype:SetParent(parent)
self.parent = parent
self.frame.parent = parent
self.frame:SetParent(parent.scrollchild)
end
-----------------------
-- TreeSection Class --
-----------------------
local function SectionTitle_OnClick()
local self = this.obj
local parent = self.parent
if not self.disabled then
local selected = self.parent.selected
local lines = self.lines
if self.expanded then
--search before changing pane, since it will release and reinit this section
local found
for i = 1, self.numlines do
if lines[i].id == selected then
found = true
end
end
--if expanded close
-- if one of our children is selected then clear the pane
if found then
parent.selected = nil
parent:ToggleExpand(self.id)
parent:SetSelected(nil)
else
parent:ToggleExpand(self.id)
end
else
--save before changing pane, since it will release and reinit this section
local newid
if lines[1] then
newid = lines[1].id
end
parent:ToggleExpand(self.id)
if newid and not parent.selected then
parent:SetSelected(newid)
end
end
end
end
local function SectionTitle_OnEnter()
local self = this.obj
if not self.disabled then
self.hover = true
self:UpdateColor()
end
showGameTooltip(self)
end
local function SectionTitle_OnLeave()
local self = this.obj
self.hover = false
self:UpdateColor()
GameTooltip:Hide()
end
local function SectionItem_OnEnter()
if not this.disabled then
this.highlight:SetAlpha(1)
this.highlight:Show()
showGameTooltip()
end
end
local function SectionItem_OnClick()
if not this.disabled then
this.obj.parent:SetSelected(this.id)
end
end
local function SectionItem_OnLeave()
if not this.isSelected then
this.highlight:Hide()
else
this.highlight:SetAlpha(0.7)
end
GameTooltip:Hide()
end
function WaterfallTreeSection.prototype:init(parent)
WaterfallTreeSection.super.prototype.init(self)
self.parent = parent
local frame = CreateFrame("Frame",nil,parent.scrollchild)
frame.obj = self
self.frame = frame
frame:SetBackdrop(PaneBackdrop)
frame:SetBackdropBorderColor(0.6, 0.6, 0.6)
frame:SetBackdropColor(0.1, 0.1, 0.1)
frame:SetFrameLevel(10)
frame:SetFrameStrata("DIALOG")
local titletext = frame:CreateFontString(nil,"OVERLAY","GameFontNormal")
self.titletext = titletext
titletext:SetPoint("TOPLEFT",frame,"TOPLEFT",0,-5)
titletext:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,-5)
titletext:SetHeight(16)
titletext:SetText("Section")
titletext:SetTextColor(1,1,1)
local arrow = frame:CreateTexture(nil,"OVERLAY")
self.arrow = arrow
arrow:SetPoint("TOPRIGHT",frame,"TOPRIGHT",-6,-4)
arrow:SetWidth(20)
arrow:SetHeight(20)
arrow:SetTexture("Interface\\MiniMap\\ROTATING-MINIMAPARROW")
local r,g,b = 1, 0.6, 0
self.colorR = r
self.colorG = g
self.colorB = b
local titlebar = frame:CreateTexture(nil,"BACKGROUND")
self.titlebar = titlebar
local titlebar2 = frame:CreateTexture(nil,"BACKGROUND")
self.titlebar2 = titlebar2
titlebar:SetPoint("TOPLEFT",frame,"TOPLEFT",4,-4)
titlebar:SetPoint("TOPRIGHT",frame,"TOPRIGHT",-4,-4)
titlebar:SetHeight(10)
titlebar2:SetPoint("TOPLEFT",titlebar,"BOTTOMLEFT",0,0)
titlebar2:SetPoint("TOPRIGHT",titlebar,"BOTTOMRIGHT",0,0)
titlebar2:SetHeight(10)
titlebar:SetGradientAlpha("VERTICAL",r*0.6,g*0.6,b*0.6,1,r,g,b,1)
titlebar:SetTexture(r,g,b,1)
titlebar2:SetGradientAlpha("VERTICAL",r*0.9,g*0.9,b*0.9,1,r*0.6,g*0.6,b*0.6,1)
titlebar2:SetTexture(r,g,b,1)
local title = CreateFrame("Button",nil,frame)
self.title = title
title:EnableMouse()
title.obj = self
title:SetScript("OnClick", SectionTitle_OnClick)
title:SetScript("OnEnter", SectionTitle_OnEnter)
title:SetScript("OnLeave", SectionTitle_OnLeave)
title:SetPoint("TOPLEFT",titlebar,"TOPLEFT",0,0)
title:SetPoint("BOTTOMRIGHT",titlebar2,"BOTTOMRIGHT",0,0)
self.lines = {}
self.numlines = 0
frame:SetWidth(100)
frame:SetHeight(100)
self.expanded = true
frame:SetPoint("CENTER",UIParent,"CENTER")
end
function WaterfallTreeSection.prototype:SetParent(parent)
self.parent = parent
self.frame:SetParent(parent.scrollchild)
end
function WaterfallTreeSection.prototype:UpdateColor()
local r,g,b
self.arrow:Show()
if self.disabled then
r,g,b = 0.5,0.5,0.5
self.arrow:Hide()
elseif self.hover then
r,g,b = self.colorR+((1-self.colorR)/2), self.colorG+((1-self.colorG)/2), self.colorB+((1-self.colorB)/2)
else
r,g,b = self.colorR, self.colorG, self.colorB
end
local titlebar = self.titlebar
local titlebar2 = self.titlebar2
titlebar:SetGradientAlpha("VERTICAL",r*0.6,g*0.6,b*0.6,1,r,g,b,1)
titlebar:SetTexture(r,g,b,1)
titlebar2:SetGradientAlpha("VERTICAL",r*0.9,g*0.9,b*0.9,1,r*0.6,g*0.6,b*0.6,1)
titlebar2:SetTexture(r,g,b,1)
end
function WaterfallTreeSection.prototype:SetColor(r,g,b)
if r and g and b then
self.colorR, self.colorG, self.colorB = r,g,b
end
self:UpdateColor()
end
function WaterfallTreeSection.prototype:ToggleExpand()
self:SetExpanded(not self.expanded)
end
function WaterfallTreeSection.prototype:SetText(text)
self.titletext:SetText(text)
end
function WaterfallTreeSection.prototype:SetTooltipText(title,text)
self.tooltipTitle = title
self.tooltipText = text
end
function WaterfallTreeSection.prototype:SetID(id)
self.id = id
end
function WaterfallTreeSection.prototype:AddLine(text,id,selected,disabled,tooltipTitle,tooltipText)
local numlines = self.numlines + 1
self.numlines = numlines
local lines = self.lines
if not lines[numlines] then
self:CreateLine(numlines)
end
local line = lines[numlines]
line.text:SetText(text)
line.id = id
line.disabled = disabled
line.isSelected = selected
line.tooltipTitle = tooltipTitle
line.tooltipText = tooltipText
if selected then
line.highlight:SetAlpha(0.7)
line.highlight:Show()
else
line.highlight:Hide()
end
if disabled then
line.text:SetTextColor(0.5,0.5,0.5)
else
line.text:SetTextColor(1,1,1)
end
line:Show()
self:FixHeight()
end
function WaterfallTreeSection.prototype:SetExpanded(expanded)
self.expanded = expanded
local lines = self.lines
if self.expanded then
for i = 1, self.numlines do
lines[i]:Show()
end
self.arrow:SetTexCoord(.18,.85,.15,.82)
else
for i = 1, table.getn(lines) do
lines[i]:Hide()
end
self.arrow:SetTexCoord(.85,.18,.82,.15)
end
self:FixHeight()
end
function WaterfallTreeSection.prototype:FixHeight()
if self.expanded then
self.frame:SetHeight(33 + self.numlines * 18)
else
self.frame:SetHeight(28)
end
end
function WaterfallTreeSection.prototype:CreateLine(index)
local frame = self.frame
self.lines[index] = CreateFrame("Button",nil,frame)
local line = self.lines[index]
line.obj = self
line:SetScript("OnEnter",SectionItem_OnEnter)
line:SetScript("OnLeave",SectionItem_OnLeave)
line:SetScript("OnClick",SectionItem_OnClick)
line:SetPoint("LEFT",frame,"LEFT",5,0)
line:SetPoint("RIGHT",frame,"RIGHT",-5,0)
line:SetHeight(16)
if index == 1 then
line:SetPoint("TOP",frame,"TOP",0,-28)
else
line:SetPoint("TOP",self.lines[index-1],"BOTTOM",0,-2)
end
local text = line:CreateFontString(nil,"OVERLAY","GameFontNormal")
line.text = text
text:SetAllPoints(line)
text:SetTextColor(1,1,1)
local highlight = line:CreateTexture(nil, "BACKGROUND")
line.highlight = highlight
highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
highlight:SetBlendMode("ADD")
highlight:SetAllPoints(line)
highlight:Hide()
end
function WaterfallTreeSection.prototype:CleanUp()
for i = 1, table.getn(self.lines) do
self.lines[i]:Hide()
end
self.numlines = 0
self.frame:Hide()
self.frame:ClearAllPoints()
self.id = nil
self.disabled = nil
self.colorR = 1
self.colorG = 0.6
self.colorB = 0
end
local function activate(self, oldLib, oldDeactivate)
if oldLib and oldLib.registry then
self.registry = oldLib.registry
else
self.registry = {}
end
if oldDeactivate then
oldDeactivate(oldLib)
end
end
AceLibrary:Register(Waterfall, MAJOR_VERSION, MINOR_VERSION, activate)
Waterfall = AceLibrary("Waterfall-1.0")