vanilla-wow-addons – Rev 1
?pathlinks?
--[[
Name: Dewdrop-2.0
Revision: $Rev: 7265 $
Author(s): ckknight (ckknight@gmail.com)
Website: http://ckknight.wowinterface.com/
Documentation: http://wiki.wowace.com/index.php/Dewdrop-2.0
SVN: http://svn.wowace.com/root/trunk/DewdropLib/Dewdrop-2.0
Description: A library to provide a clean dropdown menu interface.
Dependencies: AceLibrary
]]
local MAJOR_VERSION = "Dewdrop-2.0"
local MINOR_VERSION = "$Revision: 7265 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
local Dewdrop = {}
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 levels
local buttons
local function GetScaledCursorPosition()
local x, y = GetCursorPosition()
local scale = UIParent:GetEffectiveScale()
return x / scale, y / scale
end
local function StartCounting(self, levelNum)
for i = levelNum, table.getn(levels) do
if levels[i] then
levels[i].count = 3
end
end
end
local function StopCounting(self, level)
for i = level, 1, -1 do
if levels[i] then
levels[i].count = nil
end
end
end
local function OnUpdate(self, arg1)
for _,level in ipairs(levels) do
if level.count then
level.count = level.count - arg1
if level.count < 0 then
level.count = nil
self:Close(level.num)
end
end
end
end
local function CheckDualMonitor(self, frame)
local ratio = GetScreenWidth() / GetScreenHeight()
if ratio >= 2.4 and frame:GetRight() > GetScreenWidth() / 2 and frame:GetLeft() < GetScreenWidth() / 2 then
local offsetx
if GetCursorPosition() / GetScreenHeight() * 768 < GetScreenWidth() / 2 then
offsetx = GetScreenWidth() / 2 - frame:GetRight()
else
offsetx = GetScreenWidth() / 2 - frame:GetLeft()
end
local point, parent, relativePoint, x, y = frame:GetPoint(1)
frame:SetPoint(point, parent, relativePoint, (x or 0) + offsetx, y or 0)
end
end
local function CheckSize(self, level)
if not level.buttons then
return
end
local height = 20
for _, button in ipairs(level.buttons) do
height = height + button:GetHeight()
end
level:SetHeight(height)
local width = 160
for _, button in ipairs(level.buttons) do
local extra = 1
if button.hasArrow or button.hasColorSwatch then
extra = extra + 16
end
if not button.notCheckable then
extra = extra + 24
end
button.text:SetFont(STANDARD_TEXT_FONT, button.textHeight)
if button.text:GetWidth() + extra > width then
width = button.text:GetWidth() + extra
end
end
level:SetWidth(width + 20)
if level:GetLeft() and level:GetRight() and level:GetTop() and level:GetBottom() and (level:GetLeft() < 0 or level:GetRight() > GetScreenWidth() or level:GetTop() > GetScreenHeight() or level:GetBottom() < 0) then
level:ClearAllPoints()
if level.lastDirection == "RIGHT" then
if level.lastVDirection == "DOWN" then
level:SetPoint("TOPLEFT", level.parent or level:GetParent(), "TOPRIGHT", 5, 10)
else
level:SetPoint("BOTTOMLEFT", level.parent or level:GetParent(), "BOTTOMRIGHT", 5, -10)
end
else
if level.lastVDirection == "DOWN" then
level:SetPoint("TOPRIGHT", level.parent or level:GetParent(), "TOPLEFT", -5, 10)
else
level:SetPoint("BOTTOMRIGHT", level.parent or level:GetParent(), "BOTTOMLEFT", -5, -10)
end
end
end
local dirty = false
if not level:GetRight() then
self:Close()
return
end
if level:GetRight() > GetScreenWidth() and level.lastDirection == "RIGHT" then
level.lastDirection = "LEFT"
dirty = true
elseif level:GetLeft() < 0 and level.lastDirection == "LEFT" then
level.lastDirection = "RIGHT"
dirty = true
end
if level:GetTop() > GetScreenHeight() and level.lastVDirection == "UP" then
level.lastVDirection = "DOWN"
dirty = true
elseif level:GetBottom() < 0 and level.lastVDirection == "DOWN" then
level.lastVDirection = "UP"
dirty = true
end
if dirty then
level:ClearAllPoints()
if level.lastDirection == "RIGHT" then
if level.lastVDirection == "DOWN" then
level:SetPoint("TOPLEFT", level.parent or level:GetParent(), "TOPRIGHT", 5, 10)
else
level:SetPoint("BOTTOMLEFT", level.parent or level:GetParent(), "BOTTOMRIGHT", 5, -10)
end
else
if level.lastVDirection == "DOWN" then
level:SetPoint("TOPRIGHT", level.parent or level:GetParent(), "TOPLEFT", -5, 10)
else
level:SetPoint("BOTTOMRIGHT", level.parent or level:GetParent(), "BOTTOMLEFT", -5, -10)
end
end
end
if level:GetTop() > GetScreenHeight() then
local top = level:GetTop()
local point, parent, relativePoint, x, y = level:GetPoint(1)
level:ClearAllPoints()
level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) + GetScreenHeight() - top)
elseif level:GetBottom() < 0 then
local bottom = level:GetBottom()
local point, parent, relativePoint, x, y = level:GetPoint(1)
level:ClearAllPoints()
level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) - bottom)
end
CheckDualMonitor(self, level)
if mod(level.num, 5) == 0 then
local left, bottom = level:GetLeft(), level:GetBottom()
level:ClearAllPoints()
level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
end
end
local Open
local OpenSlider
local OpenEditBox
local Refresh
local Clear
local function ReleaseButton(self, level, index)
if not level.buttons then
return
end
if not level.buttons[index] then
return
end
local button = level.buttons[index]
button:Hide()
if button.highlight then
button.highlight:Hide()
end
table.remove(level.buttons, index)
table.insert(buttons, button)
for k in pairs(button) do
if k ~= 0 and k ~= "text" and k ~= "check" and k ~= "arrow" and k ~= "colorSwatch" and k ~= "highlight" and k ~= "radioHighlight" then
button[k] = nil
end
end
return true
end
local function Scroll(self, level, down)
if down then
if level:GetBottom() < 0 then
local point, parent, relativePoint, x, y = level:GetPoint(1)
level:SetPoint(point, parent, relativePoint, x, y + 50)
if level:GetBottom() > 0 then
level:SetPoint(point, parent, relativePoint, x, y + 50 - level:GetBottom())
end
end
else
if level:GetTop() > GetScreenHeight() then
local point, parent, relativePoint, x, y = level:GetPoint(1)
level:SetPoint(point, parent, relativePoint, x, y - 50)
if level:GetTop() < GetScreenHeight() then
level:SetPoint(point, parent, relativePoint, x, y - 50 + GetScreenHeight() - level:GetTop())
end
end
end
end
local sliderFrame
local editBoxFrame
local function AcquireButton(self, level)
if not levels[level] then
return
end
level = levels[level]
if not level.buttons then
level.buttons = {}
end
local button
if table.getn(buttons) == 0 then
button = CreateFrame("Button")
button:SetFrameStrata("FULLSCREEN_DIALOG")
button:SetHeight(16)
local highlight = button:CreateTexture(nil, "BACKGROUND")
highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
button.highlight = highlight
highlight:SetBlendMode("ADD")
highlight:SetAllPoints(button)
highlight:Hide()
local check = button:CreateTexture(nil, "ARTWORK")
button.check = check
check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
check:SetPoint("CENTER", button, "LEFT", 12, 0)
check:SetWidth(24)
check:SetHeight(24)
local radioHighlight = button:CreateTexture(nil, "ARTWORK")
button.radioHighlight = radioHighlight
radioHighlight:SetTexture("Interface\\Buttons\\UI-RadioButton")
radioHighlight:SetAllPoints(check)
radioHighlight:SetBlendMode("ADD")
radioHighlight:SetTexCoord(0.5, 0.75, 0, 1)
radioHighlight:Hide()
button:SetScript("OnEnter", function()
if (sliderFrame and sliderFrame:IsShown() and sliderFrame.mouseDown and sliderFrame.level == this.level.num + 1) or (editBoxFrame and editBoxFrame:IsShown() and editBoxFrame.mouseDown and editBoxFrame.level == this.level.num + 1) then
for i = 1, this.level.num do
Refresh(self, levels[i])
end
return
end
self:Close(this.level.num + 1)
if not this.disabled then
if this.hasSlider then
OpenSlider(self, this)
elseif this.hasEditBox then
OpenEditBox(self, this)
elseif this.hasArrow then
Open(self, this, nil, this.level.num + 1, this.value)
end
end
if not this.level then -- button reclaimed
return
end
StopCounting(self, this.level.num + 1)
if not this.disabled then
highlight:Show()
if this.isRadio then
button.radioHighlight:Show()
end
end
if this.tooltipTitle or this.tooltipText then
GameTooltip_SetDefaultAnchor(GameTooltip, this)
local disabled = this.disabled
if this.tooltipTitle then
if disabled then
GameTooltip:SetText(this.tooltipTitle, 0.5, 0.5, 0.5, 1)
else
GameTooltip:SetText(this.tooltipTitle, 1, 1, 1, 1)
end
if this.tooltipText then
if disabled then
GameTooltip:AddLine(this.tooltipText, (NORMAL_FONT_COLOR.r + 0.5) / 2, (NORMAL_FONT_COLOR.g + 0.5) / 2, (NORMAL_FONT_COLOR.b + 0.5) / 2, 1)
else
GameTooltip:AddLine(this.tooltipText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
end
end
else
if disabled then
GameTooltip:SetText(this.tooltipText, 0.5, 0.5, 0.5, 1)
else
GameTooltip:SetText(this.tooltipText, 1, 1, 1, 1)
end
end
GameTooltip:Show()
end
if this.tooltipFunc then
GameTooltip:SetOwner(this, "ANCHOR_NONE")
GameTooltip:SetPoint("TOPLEFT", this, "TOPRIGHT", 5, 0)
this.tooltipFunc(this.tooltipArg1, this.tooltipArg2, this.tooltipArg3, this.tooltipArg4)
GameTooltip:Show()
end
end)
button:SetScript("OnLeave", function()
highlight:Hide()
button.radioHighlight:Hide()
if this.level then
StartCounting(self, this.level.num)
end
GameTooltip:Hide()
end)
button:SetScript("OnClick", function()
if not this.disabled then
if this.hasColorSwatch then
local func = button.colorFunc
local a1,a2,a3,a4 = button.colorArg1, button.colorArg2, button.colorArg3, button.colorArg4
local hasOpacity = this.hasOpacity
ColorPickerFrame.func = function()
if func then
local r,g,b = ColorPickerFrame:GetColorRGB()
local a = hasOpacity and 1 - OpacitySliderFrame:GetValue() or nil
if a1 == nil then
func(r, g, b, a)
elseif a2 == nil then
func(a1, r, g, b, a)
elseif a3 == nil then
func(a1, a2, r, g, b, a)
elseif a4 == nil then
func(a1, a2, a3, r, g, b, a)
else
func(a1, a2, a3, a4, r, g, b, a)
end
end
end
ColorPickerFrame.hasOpacity = this.hasOpacity
ColorPickerFrame.opacityFunc = ColorPickerFrame.func
ColorPickerFrame.opacity = 1 - this.opacity
ColorPickerFrame:SetColorRGB(this.r, this.g, this.b)
local r, g, b, a = this.r, this.g, this.b, this.opacity
ColorPickerFrame.cancelFunc = function()
if a1 == nil then
func(r, g, b, a)
elseif a2 == nil then
func(a1, r, g, b, a)
elseif a3 == nil then
func(a1, a2, r, g, b, a)
else
func(a1, a2, a3, r, g, b, a)
end
end
self:Close(1)
ShowUIPanel(ColorPickerFrame)
elseif this.func then
local level = button.level
if type(this.func) == "string" then
self:assert(type(this.arg1[this.func]) == "function", "Cannot call method " .. this.func)
this.arg1[this.func](this.arg1, this.arg2, this.arg3, this.arg4)
else
this.func(this.arg1, this.arg2, this.arg3, this.arg4)
end
if this.closeWhenClicked then
self:Close()
elseif level:IsShown() then
for i = 1, level.num do
Refresh(self, levels[i])
end
end
elseif this.closeWhenClicked then
self:Close()
end
end
end)
local text = button:CreateFontString(nil, "ARTWORK")
button.text = text
text:SetFontObject(GameFontHighlightSmall)
button.text:SetFont(STANDARD_TEXT_FONT, UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT)
button:SetScript("OnMouseDown", function()
if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then
text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 1 or 25, -1)
end
end)
button:SetScript("OnMouseUp", function()
if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then
text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 0 or 24, 0)
end
end)
local arrow = button:CreateTexture(nil, "ARTWORK")
button.arrow = arrow
arrow:SetPoint("RIGHT", button, "RIGHT", 0, 0)
arrow:SetWidth(16)
arrow:SetHeight(16)
arrow:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow")
local colorSwatch = button:CreateTexture(nil, "OVERLAY")
button.colorSwatch = colorSwatch
colorSwatch:SetWidth(20)
colorSwatch:SetHeight(20)
colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
local texture = button:CreateTexture(nil, "OVERLAY")
colorSwatch.texture = texture
texture:SetTexture(1, 1, 1)
texture:SetWidth(11.5)
texture:SetHeight(11.5)
texture:Show()
texture:SetPoint("CENTER", colorSwatch, "CENTER")
colorSwatch:SetPoint("RIGHT", button, "RIGHT", 0, 0)
else
button = buttons[table.getn(buttons)]
table.remove(buttons, table.getn(buttons))
end
button:ClearAllPoints()
button:SetParent(level)
button:SetFrameStrata(level:GetFrameStrata())
button:SetFrameLevel(level:GetFrameLevel() + 1)
button:SetPoint("LEFT", level, "LEFT", 10, 0)
button:SetPoint("RIGHT", level, "RIGHT", -10, 0)
if table.getn(level.buttons) == 0 then
button:SetPoint("TOP", level, "TOP", 0, -10)
else
button:SetPoint("TOP", level.buttons[table.getn(level.buttons)], "BOTTOM", 0, 0)
end
button.text:SetPoint("LEFT", button, "LEFT", 24, 0)
button:Show()
button.level = level
table.insert(level.buttons, button)
if not level.parented then
level.parented = true
level:ClearAllPoints()
if level.num == 1 then
if level.parent ~= UIParent then
level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT")
else
level:SetPoint("CENTER", level.parent, "CENTER")
end
else
if level.lastDirection == "RIGHT" then
if level.lastVDirection == "DOWN" then
level:SetPoint("TOPLEFT", level.parent, "TOPRIGHT", 5, 10)
else
level:SetPoint("BOTTOMLEFT", level.parent, "BOTTOMRIGHT", 5, -10)
end
else
if level.lastVDirection == "DOWN" then
level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT", -5, 10)
else
level:SetPoint("BOTTOMRIGHT", level.parent, "BOTTOMLEFT", -5, -10)
end
end
end
level:SetFrameStrata("FULLSCREEN_DIALOG")
end
return button
end
local function AcquireLevel(self, level)
if not levels[level] then
for i = table.getn(levels) + 1, level, -1 do
local i = i
local frame = CreateFrame("Button")
if i == 1 then
local old_CloseWindows = CloseWindows
function CloseWindows(ignoreCenter)
local found = old_CloseWindows(ignoreCenter)
if levels[1]:IsShown() then
self:Close()
return 1
end
return found
end
end
levels[i] = frame
frame.num = i
frame:SetParent(UIParent)
frame:SetFrameStrata("FULLSCREEN_DIALOG")
frame:Hide()
frame:SetWidth(180)
frame:SetHeight(10)
frame:SetFrameLevel(i * 3)
frame:SetScript("OnHide", function()
self:Close(level + 1)
end)
frame:SetFrameStrata("FULLSCREEN_DIALOG")
if frame.SetTopLevel then
frame:SetTopLevel(true)
end
frame:EnableMouse(true)
frame:EnableMouseWheel(true)
local backdrop = CreateFrame("Frame", nil, frame)
backdrop:SetAllPoints(frame)
backdrop:SetBackdrop(tmp(
'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
'tile', true,
'insets', tmp2(
'left', 5,
'right', 5,
'top', 5,
'bottom', 5
),
'tileSize', 16,
'edgeSize', 16
))
backdrop:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
backdrop:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
frame:SetScript("OnClick", function()
self:Close(i)
end)
frame:SetScript("OnEnter", function()
StopCounting(self, i)
end)
frame:SetScript("OnLeave", function()
StartCounting(self, i)
end)
frame:SetScript("OnMouseWheel", function()
Scroll(self, frame, arg1 < 0)
end)
if i == 1 then
frame:SetScript("OnUpdate", function()
OnUpdate(self, arg1)
end)
levels[1].lastDirection = "RIGHT"
levels[1].lastVDirection = "DOWN"
else
levels[i].lastDirection = levels[i - 1].lastDirection
levels[i].lastVDirection = levels[i - 1].lastVDirection
end
end
end
return levels[level]
end
local function checkValidate(validateFunc, func, arg1, arg2, arg3)
local text
if arg3 ~= nil then
text = arg3
elseif arg2 ~= nil then
text = arg2
else
text = arg1
end
if not validateFunc(text) then
DEFAULT_CHAT_FRAME:AddMessage("|cffffff7fValidation error: [|r" .. tostring(text) .. "|cffffff7f]|r")
else
func(arg1, arg2, arg3)
end
end
local function validateOptions(options, position, baseOptions, fromPass)
if not baseOptions then
baseOptions = options
end
if type(options) ~= "table" then
return "Options must be a table.", position
end
local kind = options.type
if type(kind) ~= "string" then
return '"type" must be a string.', position
elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "header" then
return '"type" must either be "range", "text", "group", "toggle", "execute", "color", or "header".', position
end
if options.aliases then
if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then
return '"alias" must be a table or string', position
end
end
if not fromPass then
if kind == "execute" then
if type(options.func) ~= "string" and type(options.func) ~= "function" then
return '"func" must be a string or function', position
end
elseif kind == "range" or kind == "text" or kind == "toggle" then
if type(options.set) ~= "string" and type(options.set) ~= "function" then
return '"set" must be a string or function', position
end
if kind == "text" and options.get == false then
elseif type(options.get) ~= "string" and type(options.get) ~= "function" then
return '"get" must be a string or function', position
end
elseif kind == "group" and options.pass then
if options.pass ~= true then
return '"pass" must be either nil, true, or false', position
end
if not options.func then
if type(options.set) ~= "string" and type(options.set) ~= "function" then
return '"set" must be a string or function', position
end
if type(options.get) ~= "string" and type(options.get) ~= "function" then
return '"get" must be a string or function', position
end
elseif type(options.func) ~= "string" and type(options.func) ~= "function" then
return '"func" must be a string or function', position
end
end
else
if kind == "group" then
return 'cannot have "type" = "group" as a subgroup of a passing group', position
end
end
if options ~= baseOptions then
if kind == "header" then
elseif type(options.desc) ~= "string" then
return '"desc" must be a string', position
elseif string.len(options.desc) == 0 then
return '"desc" cannot be a 0-length string', position
end
end
if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then
if options.type == "header" and not options.cmdName and not options.name then
elseif options.cmdName then
if type(options.cmdName) ~= "string" then
return '"cmdName" must be a string or nil', position
elseif string.len(options.cmdName) == 0 then
return '"cmdName" cannot be a 0-length string', position
end
if type(options.guiName) ~= "string" then
if not options.guiNameIsMap then
return '"guiName" must be a string or nil', position
end
elseif string.len(options.guiName) == 0 then
return '"guiName" cannot be a 0-length string', position
end
else
if type(options.name) ~= "string" then
return '"name" must be a string', position
elseif string.len(options.name) == 0 then
return '"name" cannot be a 0-length string', position
end
end
end
if options.guiNameIsMap then
if type(options.guiNameIsMap) ~= "boolean" then
return '"guiNameIsMap" must be a boolean or nil', position
elseif options.type ~= "toggle" then
return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position
elseif type(options.map) ~= "table" then
return '"map" must be a table', position
end
end
if options.message and type(options.message) ~= "string" then
return '"message" must be a string or nil', position
end
if options.error and type(options.error) ~= "string" then
return '"error" must be a string or nil', position
end
if options.current and type(options.current) ~= "string" then
return '"current" must be a string or nil', position
end
if options.order then
if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then
return '"order" must be a non-zero number or nil', position
end
end
if options.disabled then
if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then
return '"disabled" must be a function, string, or boolean', position
end
end
if options.cmdHidden then
if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then
return '"cmdHidden" must be a function, string, or boolean', position
end
end
if options.guiHidden then
if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then
return '"guiHidden" must be a function, string, or boolean', position
end
end
if options.hidden then
if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then
return '"hidden" must be a function, string, or boolean', position
end
end
if kind == "text" then
if type(options.validate) == "table" then
local t = options.validate
local iTable = nil
for k,v in pairs(t) do
if type(k) == "number" then
if iTable == nil then
iTable = true
elseif not iTable then
return '"validate" must either have all keys be indexed numbers or strings', position
elseif k < 1 or k > table.getn(t) then
return '"validate" numeric keys must be indexed properly. >= 1 and <= table.getn', position
end
else
if iTable == nil then
iTable = false
elseif iTable then
return '"validate" must either have all keys be indexed numbers or strings', position
end
end
if type(v) ~= "string" then
return '"validate" values must all be strings', position
end
end
else
if type(options.usage) ~= "string" then
return '"usage" must be a string', position
elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then
return '"validate" must be a string, function, or table', position
end
end
elseif kind == "range" then
if options.min or options.max then
if type(options.min) ~= "number" then
return '"min" must be a number', position
elseif type(options.max) ~= "number" then
return '"max" must be a number', position
elseif options.min >= options.max then
return '"min" must be less than "max"', position
end
end
if options.step then
if type(options.step) ~= "number" then
return '"step" must be a number', position
elseif options.step < 0 then
return '"step" must be nonnegative', position
end
end
if options.isPercent and options.isPercent ~= true then
return '"isPercent" must either be nil, true, or false', position
end
elseif kind == "toggle" then
if options.map then
if type(options.map) ~= "table" then
return '"map" must be a table', position
elseif type(options.map[true]) ~= "string" then
return '"map[true]" must be a string', position
elseif type(options.map[false]) ~= "string" then
return '"map[false]" must be a string', position
end
end
elseif kind == "color" then
if options.hasAlpha and options.hasAlpha ~= true then
return '"hasAlpha" must be nil, true, or false', position
end
elseif kind == "group" then
if options.pass and options.pass ~= true then
return '"pass" must be nil, true, or false', position
end
if type(options.args) ~= "table" then
return '"args" must be a table', position
end
for k,v in pairs(options.args) do
if type(k) ~= "string" then
return '"args" keys must be strings', position
elseif string.find(k, "%s") then
return string.format('"args" keys must not include spaces. %q is not appropriate.', k), position
elseif string.len(k) == 0 then
return '"args" keys must not be 0-length strings.', position
end
if type(v) ~= "table" then
return '"args" values must be tables', position and position .. "." .. k or k
end
local newposition
if position then
newposition = position .. ".args." .. k
else
newposition = "args." .. k
end
local err, pos = validateOptions(v, newposition, baseOptions, options.pass)
if err then
return err, pos
end
end
end
end
local validatedOptions
local values
local mysort_args
local mysort
local othersort
local othersort_validate
local baseFunc, currentLevel
function Dewdrop:FeedAceOptionsTable(options, difference)
self:argCheck(options, 2, "table")
self:argCheck(difference, 3, "nil", "number")
self:assert(currentLevel, "Cannot call `FeedAceOptionsTable' outside of a Dewdrop declaration")
if not difference then
difference = 0
end
if not validatedOptions then
validatedOptions = {}
end
if not validatedOptions[options] then
local err, position = validateOptions(options)
if err then
if position then
Dewdrop:error(position .. ": " .. err)
else
Dewdrop:error(err)
end
end
validatedOptions[options] = true
end
local level = levels[currentLevel]
self:assert(level, "Improper level given")
if not values then
values = {}
else
for k,v in pairs(values) do
values[k] = nil
end
table.setn(values, 0)
end
local current = level
while current do
if current.num == difference + 1 then
break
end
table.insert(values, current.value)
current = levels[current.num - 1]
end
local realOptions = options
local handler = options.handler
local passTable
local passValue
while table.getn(values) > 0 do
passTable = options.pass and current or nil
local value = table.remove(values)
options = options.args and options.args[value]
if not options then
return
end
handler = options.handler or handler
passValue = passTable and value or nil
end
if options.type == "group" then
for k in pairs(options.args) do
table.insert(values, k)
end
if not mysort then
mysort = function(a, b)
local alpha, bravo = mysort_args[a], mysort_args[b]
local alpha_order = alpha.order or 100
local bravo_order = bravo.order or 100
local alpha_name = alpha.guiName or alpha.name
local bravo_name = bravo.guiName or bravo.name
if alpha_order == bravo_order then
if not alpha_name then
return true
elseif not bravo_name then
return false
else
return alpha_name < bravo_name
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
end
mysort_args = options.args
table.sort(values, mysort)
mysort_args = nil
local hasBoth = table.getn(values) >= 1 and (options.args[values[1]].order or 100) > 0 and (options.args[values[table.getn(values)]].order or 100) < 0
local last_order = 1
for _,k in ipairs(values) do
local v = options.args[k]
local handler = v.handler or handler
if hasBoth and last_order > 0 and (v.order or 100) < 0 then
hasBoth = false
self:AddLine()
end
local hidden, disabled = v.guiHidden or v.hidden, v.disabled
if type(hidden) == "function" then
hidden = hidden()
elseif type(hidden) == "string" then
hidden = handler[hidden](handler)
end
if not hidden then
if type(disabled) == "function" then
disabled = disabled()
elseif type(disabled) == "string" then
disabled = handler[disabled](handler)
end
local name = v.guiName or v.name
local desc = v.desc
local tooltipTitle, tooltipText
tooltipTitle = name
if name ~= desc then
tooltipText = desc
end
if v.type == "toggle" then
local checked
if type(v.get) == "function" then
checked = v.get(passValue)
else
if not handler[v.get] then
Dewdrop:error("Handler %q not available", v.get)
end
checked = handler[v.get](handler, passValue)
end
local func, arg1, arg2, arg3
if type(v.set) == "function" then
func = v.set
if passValue ~= nil then
arg1 = passValue
arg2 = not checked
else
arg1 = not checked
end
else
if not handler[v.set] then
Dewdrop:error("Handler %q not available", v.set)
end
func = handler[v.set]
arg1 = handler
if passValue ~= nil then
arg2 = passValue
arg3 = not checked
else
arg2 = not checked
end
end
if v.guiNameIsMap then
checked = checked and true or false
name = string.gsub(tostring(v.map and v.map[checked]), "|c%x%x%x%x%x%x%x%x(.-)|r", "%1")
checked = nil
end
self:AddLine(
'text', name,
'checked', checked,
'func', func,
'arg1', arg1,
'arg2', arg2,
'arg3', arg3,
'disabled', disabled,
'tooltipTitle', tooltipTitle,
'tooltipText', tooltipText
)
elseif v.type == "execute" then
local func, arg1, arg2
if type(v.func) == "function" then
func = v.func
arg1 = passValue
else
if not handler[v.func] then
Dewdrop:error("Handler %q not available", v.func)
end
func = handler[v.func]
arg1 = handler
arg2 = passValue
end
self:AddLine(
'text', name,
'checked', checked,
'func', func,
'arg1', arg1,
'arg2', arg2,
'disabled', disabled,
'tooltipTitle', tooltipTitle,
'tooltipText', tooltipText
)
elseif v.type == "range" then
local sliderValue
if type(v.get) == "function" then
sliderValue = v.get(passValue)
else
if not handler[v.get] then
Dewdrop:error("Handler %q not available", v.get)
end
sliderValue = handler[v.get](handler, passValue)
end
local sliderFunc, sliderArg1, sliderArg2
if type(v.set) == "function" then
sliderFunc = v.set
sliderArg1 = passValue
else
if not handler[v.set] then
Dewdrop:error("Handler %q not available", v.set)
end
sliderFunc = handler[v.set]
sliderArg1 = handler
sliderArg2 = passValue
end
self:AddLine(
'text', name,
'hasArrow', true,
'hasSlider', true,
'sliderMin', v.min or 0,
'sliderMax', v.max or 1,
'sliderStep', v.step or 0,
'sliderIsPercent', v.isPercent or false,
'sliderValue', sliderValue,
'sliderFunc', sliderFunc,
'sliderArg1', sliderArg1,
'sliderArg2', sliderArg2,
'disabled', disabled,
'tooltipTitle', tooltipTitle,
'tooltipText', tooltipText
)
elseif v.type == "color" then
local r,g,b,a
if type(v.get) == "function" then
r,g,b,a = v.get(passValue)
else
if not handler[v.get] then
Dewdrop:error("Handler %q not available", v.get)
end
r,g,b,a = handler[v.get](handler, passValue)
end
local colorFunc, colorArg1, colorArg2
if type(v.set) == "function" then
colorFunc = v.set
colorArg1 = passValue
else
if not handler[v.set] then
Dewdrop:error("Handler %q not available", v.set)
end
colorFunc = handler[v.set]
colorArg1 = handler
colorArg2 = passValue
end
self:AddLine(
'text', name,
'hasArrow', true,
'hasColorSwatch', true,
'r', r,
'g', g,
'b', b,
'opacity', v.hasAlpha and a or nil,
'hasOpacity', v.hasAlpha,
'colorFunc', colorFunc,
'colorArg1', colorArg1,
'colorArg2', colorArg2,
'disabled', disabled,
'tooltipTitle', tooltipTitle,
'tooltipText', tooltipText
)
elseif v.type == "text" then
if type(v.validate) == "table" then
self:AddLine(
'text', name,
'hasArrow', true,
'value', k,
'disabled', disabled,
'tooltipTitle', tooltipTitle,
'tooltipText', tooltipText
)
else
local editBoxText
if type(v.get) == "function" then
editBoxText = v.get(passValue)
elseif v.get == false then
editBoxText = nil
else
if not handler[v.get] then
Dewdrop:error("Handler %q not available", v.get)
end
editBoxText = handler[v.get](handler, passValue)
end
local editBoxFunc, editBoxArg1, editBoxArg2
if type(v.set) == "function" then
editBoxFunc = v.set
editBoxArg1 = passValue
else
if not handler[v.set] then
Dewdrop:error("Handler %q not available", v.set)
end
editBoxFunc = handler[v.set]
editBoxArg1 = handler
editBoxArg2 = passValue
end
local editBoxValidateFunc, editBoxValidateArg1
if v.validate then
if type(v.validate) == "function" then
editBoxValidateFunc = v.validate
else
if not handler[v.validate] then
Dewdrop:error("Handler %q not available", v.validate)
end
editBoxValidateFunc = handler[v.validate]
editBoxValidateArg1 = handler
end
end
self:AddLine(
'text', name,
'hasArrow', true,
'hasEditBox', true,
'editBoxText', editBoxText,
'editBoxFunc', editBoxFunc,
'editBoxArg1', editBoxArg1,
'editBoxArg2', editBoxArg2,
'editBoxValidateFunc', editBoxValidateFunc,
'editBoxValidateArg1', editBoxValidateArg1,
'disabled', disabled,
'tooltipTitle', tooltipTitle,
'tooltipText', tooltipText
)
end
elseif v.type == "group" then
self:AddLine(
'text', name,
'hasArrow', true,
'value', k,
'disabled', disabled,
'tooltipTitle', tooltipTitle,
'tooltipText', tooltipText
)
elseif v.type == "header" then
if name == "" or not name then
self:AddLine()
else
self:AddLine(
'text', name,
'isTitle', true
)
end
end
end
last_order = v.order or 100
end
elseif options.type == "text" and type(options.validate) == "table" then
local current
if type(options.get) == "function" then
current = options.get(passValue)
else
if not handler[options.get] then
Dewdrop:error("Handler %q not available", options.get)
end
current = handler[options.get](handler, passValue)
end
local indexed = true
for k,v in pairs(options.validate) do
if type(k) ~= "number" then
indexed = false
end
table.insert(values, k)
end
if not indexed then
if not othersort then
othersort = function(alpha, bravo)
return othersort_validate[alpha] < othersort_validate[bravo]
end
end
othersort_validate = options.validate
table.sort(values, othersort)
othersort_validate = nil
end
for _,k in ipairs(values) do
local v = options.validate[k]
if type(k) == "number" then
k = v
end
local func, arg1, arg2
if type(options.set) == "function" then
func = options.set
if passValue ~= nil then
arg1 = passValue
arg2 = k
else
arg1 = k
end
else
if not handler[options.set] then
Dewdrop:error("Handler %q not available", options.set)
end
func = handler[options.set]
arg1 = handler
if passValue ~= nil then
arg2 = passValue
arg3 = k
else
arg2 = k
end
end
local checked = (k == current or (type(k) == "string" and type(current) == "string" and string.lower(k) == string.lower(current)))
self:AddLine(
'text', v,
'func', not checked and func or nil,
'arg1', not checked and arg1 or nil,
'arg2', not checked and arg2 or nil,
'arg3', not checked and arg3 or nil,
'isRadio', true,
'checked', checked,
'tooltipTitle', options.guiName or options.name,
'tooltipText', v
)
end
for k in pairs(values) do
values[k] = nil
end
table.setn(values, 0)
else
self:assert(false)
end
return true
end
function Refresh(self, level)
if type(level) == "number" then
level = levels[level]
end
if not level then
return
end
if baseFunc then
Clear(self, level)
currentLevel = level.num
if type(baseFunc) == "table" then
if currentLevel == 1 then
local handler = baseFunc.handler
if handler then
local name = tostring(handler)
if not string.find(name, '^table:') then
name = string.gsub(name, "|c%x%x%x%x%x%x%x%x(.-)|r", "%1")
self:AddLine(
'text', name,
'isTitle', true
)
end
end
end
self:FeedAceOptionsTable(baseFunc)
if currentLevel == 1 then
self:AddLine(
'text', CLOSE,
'closeWhenClicked', true
)
end
else
baseFunc(currentLevel, level.value, levels[level.num - 1] and levels[level.num - 1].value, levels[level.num - 2] and levels[level.num - 2].value, levels[level.num - 3] and levels[level.num - 3].value, levels[level.num - 4] and levels[level.num - 4].value)
end
currentLevel = nil
CheckSize(self, level)
end
end
function Dewdrop:Refresh(level)
self:argCheck(level, 2, "number")
Refresh(self, levels[level])
end
function OpenSlider(self, parent)
if not sliderFrame then
sliderFrame = CreateFrame("Frame", nil, UIParent)
sliderFrame:SetWidth(80)
sliderFrame:SetHeight(170)
sliderFrame:SetBackdrop(tmp(
'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
'tile', true,
'insets', tmp2(
'left', 5,
'right', 5,
'top', 5,
'bottom', 5
),
'tileSize', 16,
'edgeSize', 16
))
sliderFrame:SetFrameStrata("FULLSCREEN_DIALOG")
if sliderFrame.SetTopLevel then
sliderFrame:SetTopLevel(true)
end
sliderFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
sliderFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
sliderFrame:EnableMouse(true)
sliderFrame:Hide()
sliderFrame:SetPoint("CENTER", UIParent, "CENTER")
local slider = CreateFrame("Slider", nil, sliderFrame)
sliderFrame.slider = slider
slider:SetOrientation("VERTICAL")
slider:SetMinMaxValues(0, 1)
slider:SetValueStep(0.01)
slider:SetValue(0.5)
slider:SetWidth(16)
slider:SetHeight(128)
slider:SetPoint("LEFT", sliderFrame, "LEFT", 15, 0)
slider:SetBackdrop(tmp(
'bgFile', "Interface\\Buttons\\UI-SliderBar-Background",
'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border",
'tile', true,
'edgeSize', 8,
'tileSize', 8,
'insets', tmp2(
'left', 3,
'right', 3,
'top', 3,
'bottom', 3
)
))
local texture = slider:CreateTexture()
slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
local text = slider:CreateFontString(nil, "ARTWORK")
sliderFrame.topText = text
text:SetFontObject(GameFontGreenSmall)
text:SetText("100%")
text:SetPoint("BOTTOM", slider, "TOP")
local text = slider:CreateFontString(nil, "ARTWORK")
sliderFrame.bottomText = text
text:SetFontObject(GameFontGreenSmall)
text:SetText("0%")
text:SetPoint("TOP", slider, "BOTTOM")
local text = slider:CreateFontString(nil, "ARTWORK")
sliderFrame.currentText = text
text:SetFontObject(GameFontHighlightSmall)
text:SetText("50%")
text:SetPoint("LEFT", slider, "RIGHT")
text:SetPoint("RIGHT", sliderFrame, "RIGHT", -6, 0)
text:SetJustifyH("CENTER")
local changed = false
local inside = false
slider:SetScript("OnValueChanged", function()
if sliderFrame.changing then
return
end
changed = true
local done = false
if sliderFrame.parent then
if sliderFrame.parent.sliderFunc then
local min = sliderFrame.parent.sliderMin or 0
local max = sliderFrame.parent.sliderMax or 1
local step = sliderFrame.parent.sliderStep or (max - min) / 100
local a1,a2,a3,a4 = sliderFrame.parent.sliderArg1, sliderFrame.parent.sliderArg2, sliderFrame.parent.sliderArg3, sliderFrame.parent.sliderArg4
local value = (1 - slider:GetValue()) * (max - min) + min
if step > 0 then
value = math.floor((value - min) / step + 0.5) * step + min
if value > max then
value = max
elseif value < min then
value = min
end
end
local text
if a1 == nil then
text = sliderFrame.parent.sliderFunc(value)
elseif a2 == nil then
text = sliderFrame.parent.sliderFunc(a1, value)
elseif a3 == nil then
text = sliderFrame.parent.sliderFunc(a1, a2, value)
elseif a4 == nil then
text = sliderFrame.parent.sliderFunc(a1, a2, a3, value)
else
text = sliderFrame.parent.sliderFunc(a1, a2, a3, a4, value)
end
if text then
sliderFrame.currentText:SetText(text)
done = true
end
end
end
if not done then
local min = sliderFrame.parent.sliderMin or 0
local max = sliderFrame.parent.sliderMax or 1
local step = sliderFrame.parent.sliderStep or (max - min) / 100
local value = (1 - slider:GetValue()) * (max - min) + min
if step > 0 then
value = math.floor((value - min) / step + 0.5) * step + min
if value > max then
value = max
elseif value < min then
value = min
end
end
if sliderFrame.parent.sliderIsPercent then
sliderFrame.currentText:SetText(string.format("%.0f%%", value * 100))
else
if step < 0.1 then
sliderFrame.currentText:SetText(string.format("%.2f", value))
elseif step < 1 then
sliderFrame.currentText:SetText(string.format("%.1f", value))
else
sliderFrame.currentText:SetText(string.format("%.0f", value))
end
end
end
end)
sliderFrame:SetScript("OnEnter", function()
StopCounting(self, sliderFrame.level)
end)
sliderFrame:SetScript("OnLeave", function()
StartCounting(self, sliderFrame.level)
end)
slider:SetScript("OnMouseDown", function()
sliderFrame.mouseDown = true
end)
slider:SetScript("OnMouseUp", function()
sliderFrame.mouseDown = false
if changed and not inside then
local parent = sliderFrame.parent
for i = 1, sliderFrame.level - 1 do
Refresh(self, levels[i])
end
OpenSlider(self, parent)
end
end)
slider:SetScript("OnEnter", function()
inside = true
StopCounting(self, sliderFrame.level)
end)
slider:SetScript("OnLeave", function()
inside = false
StartCounting(self, sliderFrame.level)
if changed and not sliderFrame.mouseDown then
local parent = sliderFrame.parent
for i = 1, sliderFrame.level - 1 do
Refresh(self, levels[i])
end
OpenSlider(self, parent)
end
end)
end
sliderFrame.parent = parent
sliderFrame.level = parent.level.num + 1
sliderFrame.parentValue = parent.level.value
sliderFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3)
sliderFrame.slider:SetFrameLevel(sliderFrame:GetFrameLevel() + 1)
sliderFrame.changing = true
if not parent.sliderMin or not parent.sliderMax then
return
end
if not parent.sliderValue then
parent.sliderValue = (parent.sliderMin + parent.sliderMax) / 2
end
sliderFrame.slider:SetValue(1 - (parent.sliderValue - parent.sliderMin) / (parent.sliderMax - parent.sliderMin))
sliderFrame.changing = false
sliderFrame.bottomText:SetText(parent.sliderMinText or "0")
sliderFrame.topText:SetText(parent.sliderMaxText or "1")
local text
if parent.sliderFunc then
local a1,a2,a3,a4 = parent.sliderArg1, parent.sliderArg2, parent.sliderArg3, parent.sliderArg4
if a1 == nil then
text = parent.sliderFunc(parent.sliderValue)
elseif a2 == nil then
text = parent.sliderFunc(a1, parent.sliderValue)
elseif a3 == nil then
text = parent.sliderFunc(a1, a2, parent.sliderValue)
elseif a4 == nil then
text = parent.sliderFunc(a1, a2, a3, parent.sliderValue)
else
text = parent.sliderFunc(a1, a2, a3, a4, parent.sliderValue)
end
end
if text then
sliderFrame.currentText:SetText(text)
elseif parent.sliderIsPercent then
sliderFrame.currentText:SetText(string.format("%.0f%%", parent.sliderValue * 100))
else
sliderFrame.currentText:SetText(parent.sliderValue)
end
local level = parent.level
sliderFrame:Show()
sliderFrame:ClearAllPoints()
if level.lastDirection == "RIGHT" then
if level.lastVDirection == "DOWN" then
sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
else
sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
end
else
if level.lastVDirection == "DOWN" then
sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
else
sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
end
end
local dirty
if level.lastDirection == "RIGHT" then
if sliderFrame:GetRight() > GetScreenWidth() then
level.lastDirection = "LEFT"
dirty = true
end
elseif sliderFrame:GetLeft() < 0 then
level.lastDirection = "RIGHT"
dirty = true
end
if level.lastVDirection == "DOWN" then
if sliderFrame:GetBottom() < 0 then
level.lastVDirection = "UP"
dirty = true
end
elseif sliderFrame:GetTop() > GetScreenWidth() then
level.lastVDirection = "DOWN"
dirty = true
end
if dirty then
sliderFrame:ClearAllPoints()
if level.lastDirection == "RIGHT" then
if level.lastVDirection == "DOWN" then
sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
else
sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
end
else
if level.lastVDirection == "DOWN" then
sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
else
sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
end
end
end
local left, bottom = sliderFrame:GetLeft(), sliderFrame:GetBottom()
sliderFrame:ClearAllPoints()
sliderFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
if mod(level.num, 5) == 0 then
local left, bottom = level:GetLeft(), level:GetBottom()
level:ClearAllPoints()
level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
end
end
function OpenEditBox(self, parent)
if not editBoxFrame then
editBoxFrame = CreateFrame("Frame", nil, UIParent)
editBoxFrame:SetWidth(200)
editBoxFrame:SetHeight(40)
editBoxFrame:SetBackdrop(tmp(
'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
'tile', true,
'insets', tmp2(
'left', 5,
'right', 5,
'top', 5,
'bottom', 5
),
'tileSize', 16,
'edgeSize', 16
))
editBoxFrame:SetFrameStrata("FULLSCREEN_DIALOG")
if editBoxFrame.SetTopLevel then
editBoxFrame:SetTopLevel(true)
end
editBoxFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
editBoxFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
editBoxFrame:EnableMouse(true)
editBoxFrame:Hide()
editBoxFrame:SetPoint("CENTER", UIParent, "CENTER")
local editBox = CreateFrame("EditBox", nil, editBoxFrame)
editBoxFrame.editBox = editBox
editBox:SetFontObject(ChatFontNormal)
editBox:SetWidth(160)
editBox:SetHeight(13)
editBox:SetPoint("CENTER", editBoxFrame, "CENTER", 0, 0)
local left = editBox:CreateTexture(nil, "BACKGROUND")
left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left")
left:SetTexCoord(0, 100 / 256, 0, 1)
left:SetWidth(100)
left:SetHeight(32)
left:SetPoint("LEFT", editBox, "LEFT", -10, 0)
local right = editBox:CreateTexture(nil, "BACKGROUND")
right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right")
right:SetTexCoord(156/256, 1, 0, 1)
right:SetWidth(100)
right:SetHeight(32)
right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0)
editBox:SetScript("OnEnterPressed", function()
if editBoxFrame.parent and editBoxFrame.parent.editBoxValidateFunc then
local a1,a2,a3,a4 = editBoxFrame.parent.editBoxValidateArg1, editBoxFrame.parent.editBoxValidateArg2, editBoxFrame.parent.editBoxValidateArg3, editBoxFrame.parent.editBoxValidateArg4
local result
if a1 == nil then
result = editBoxFrame.parent.editBoxValidateFunc(editBox:GetText() or "")
elseif a2 == nil then
result = editBoxFrame.parent.editBoxValidateFunc(a1, editBox:GetText() or "")
elseif a3 == nil then
result = editBoxFrame.parent.editBoxValidateFunc(a1, a2, editBox:GetText() or "")
elseif a4 == nil then
result = editBoxFrame.parent.editBoxValidateFunc(a1, a2, a3, editBox:GetText() or "")
else
result = editBoxFrame.parent.editBoxValidateFunc(a1, a2, a3, a4, editBox:GetText() or "")
end
if not result then
message("Validation error: [" .. tostring(text) .. "]")
return
end
end
if editBoxFrame.parent and editBoxFrame.parent.editBoxFunc then
local a1,a2,a3,a4 = editBoxFrame.parent.editBoxArg1, editBoxFrame.parent.editBoxArg2, editBoxFrame.parent.editBoxArg3, editBoxFrame.parent.editBoxArg4
if a1 == nil then
editBoxFrame.parent.editBoxFunc(editBox:GetText() or "")
elseif a2 == nil then
editBoxFrame.parent.editBoxFunc(a1, editBox:GetText() or "")
elseif a3 == nil then
editBoxFrame.parent.editBoxFunc(a1, a2, editBox:GetText() or "")
elseif a4 == nil then
editBoxFrame.parent.editBoxFunc(a1, a2, a3, editBox:GetText() or "")
else
editBoxFrame.parent.editBoxFunc(a1, a2, a3, a4, editBox:GetText() or "")
end
end
self:Close(editBoxFrame.level)
for i = 1, editBoxFrame.level - 1 do
Refresh(self, levels[i])
end
end)
editBox:SetScript("OnEscapePressed", function()
self:Close(editBoxFrame.level)
end)
local changing = false
local skipNext = false
function editBox:SpecialSetText(text)
local oldText = editBox:GetText() or ""
if not text then
text = ""
end
if text ~= oldText then
changing = true
self:SetText(text)
changing = false
skipNext = true
end
end
editBox:SetScript("OnTextChanged", function()
if skipNext then
skipNext = false
elseif not changing and editBoxFrame.parent and editBoxFrame.parent.editBoxChangeFunc then
local a1,a2,a3,a4 = editBoxFrame.parent.editBoxChangeArg1, editBoxFrame.parent.editBoxChangeArg2, editBoxFrame.parent.editBoxChangeArg3, editBoxFrame.parent.editBoxChangeArg4
local text
if a1 == nil then
text = editBoxFrame.parent.editBoxChangeFunc(editBox:GetText() or "")
elseif a2 == nil then
text = editBoxFrame.parent.editBoxChangeFunc(a1, editBox:GetText() or "")
elseif a3 == nil then
text = editBoxFrame.parent.editBoxChangeFunc(a1, a2, editBox:GetText() or "")
elseif a4 == nil then
text = editBoxFrame.parent.editBoxChangeFunc(a1, a2, a3, editBox:GetText() or "")
else
text = editBoxFrame.parent.editBoxChangeFunc(a1, a2, a3, a4, editBox:GetText() or "")
end
if text then
editBox:SpecialSetText(text)
end
end
end)
editBoxFrame:SetScript("OnEnter", function()
StopCounting(self, editBoxFrame.level)
end)
editBoxFrame:SetScript("OnLeave", function()
StartCounting(self, editBoxFrame.level)
end)
editBox:SetScript("OnEnter", function()
StopCounting(self, editBoxFrame.level)
end)
editBox:SetScript("OnLeave", function()
StartCounting(self, editBoxFrame.level)
end)
end
editBoxFrame.parent = parent
editBoxFrame.level = parent.level.num + 1
editBoxFrame.parentValue = parent.level.value
editBoxFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3)
editBoxFrame.editBox:SetFrameLevel(editBoxFrame:GetFrameLevel() + 1)
editBoxFrame.editBox:SpecialSetText(parent.editBoxText)
local level = parent.level
editBoxFrame:Show()
editBoxFrame:ClearAllPoints()
if level.lastDirection == "RIGHT" then
if level.lastVDirection == "DOWN" then
editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
else
editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
end
else
if level.lastVDirection == "DOWN" then
editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
else
editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
end
end
local dirty
if level.lastDirection == "RIGHT" then
if editBoxFrame:GetRight() > GetScreenWidth() then
level.lastDirection = "LEFT"
dirty = true
end
elseif editBoxFrame:GetLeft() < 0 then
level.lastDirection = "RIGHT"
dirty = true
end
if level.lastVDirection == "DOWN" then
if editBoxFrame:GetBottom() < 0 then
level.lastVDirection = "UP"
dirty = true
end
elseif editBoxFrame:GetTop() > GetScreenWidth() then
level.lastVDirection = "DOWN"
dirty = true
end
if dirty then
editBoxFrame:ClearAllPoints()
if level.lastDirection == "RIGHT" then
if level.lastVDirection == "DOWN" then
editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
else
editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
end
else
if level.lastVDirection == "DOWN" then
editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
else
editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
end
end
end
local left, bottom = editBoxFrame:GetLeft(), editBoxFrame:GetBottom()
editBoxFrame:ClearAllPoints()
editBoxFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
if mod(level.num, 5) == 0 then
local left, bottom = level:GetLeft(), level:GetBottom()
level:ClearAllPoints()
level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
end
end
function Dewdrop:IsOpen(parent)
self:argCheck(parent, 2, "table", "nil")
return levels[1] and levels[1]:IsShown() and (not parent or parent == levels[1].parent or parent == levels[1]:GetParent())
end
function Dewdrop:GetOpenedParent()
return (levels[1] and levels[1]:IsShown()) and (levels[1].parent or levels[1]:GetParent())
end
function Open(self, parent, func, level, value, point, relativePoint, cursorX, cursorY)
self:Close(level)
if DewdropLib then
local d = DewdropLib:GetInstance('1.0')
local ret, val = pcall(d, IsOpen, d)
if ret and val then
DewdropLib:GetInstance('1.0'):Close()
end
end
parent:GetCenter()
local frame = AcquireLevel(self, level)
if level == 1 then
frame.lastDirection = "RIGHT"
frame.lastVDirection = "DOWN"
else
frame.lastDirection = levels[level - 1].lastDirection
frame.lastVDirection = levels[level - 1].lastVDirection
end
frame:SetFrameStrata("FULLSCREEN_DIALOG")
frame:ClearAllPoints()
frame.parent = parent
frame:SetPoint("LEFT", UIParent, "RIGHT", 10000, 0)
frame:Show()
if level == 1 then
baseFunc = func
end
levels[level].value = value
relativePoint = relativePoint or point
Refresh(self, levels[level])
if point or (cursorX and cursorY) then
frame:ClearAllPoints()
if cursorX and cursorY then
local curX, curY = GetScaledCursorPosition()
if curY < GetScreenHeight() / 2 then
point, relativePoint = "BOTTOM", "BOTTOM"
else
point, relativePoint = "TOP", "TOP"
end
if curX < GetScreenWidth() / 2 then
point, relativePoint = point .. "LEFT", relativePoint .. "RIGHT"
else
point, relativePoint = point .. "RIGHT", relativePoint .. "LEFT"
end
end
frame:SetPoint(point, parent, relativePoint)
if cursorX and cursorY then
local left = frame:GetLeft()
local width = frame:GetWidth()
local bottom = frame:GetBottom()
local height = frame:GetHeight()
local curX, curY = GetScaledCursorPosition()
frame:ClearAllPoints()
relativePoint = relativePoint or point
if point == "BOTTOM" or point == "TOP" then
if curX < GetScreenWidth() / 2 then
point = point .. "LEFT"
else
point = point .. "RIGHT"
end
elseif point == "CENTER" then
if curX < GetScreenWidth() / 2 then
point = "LEFT"
else
point = "RIGHT"
end
end
local xOffset, yOffset = 0, 0
if curY > GetScreenHeight() / 2 then
yOffset = -height
end
if curX > GetScreenWidth() / 2 then
xOffset = -width
end
frame:SetPoint(point, parent, relativePoint, curX - left + xOffset, curY - bottom + yOffset)
if level == 1 then
frame.lastDirection = "RIGHT"
end
elseif cursorX then
local left = frame:GetLeft()
local width = frame:GetWidth()
local curX, curY = GetScaledCursorPosition()
frame:ClearAllPoints()
relativePoint = relativePoint or point
if point == "BOTTOM" or point == "TOP" then
if curX < GetScreenWidth() / 2 then
point = point .. "LEFT"
else
point = point .. "RIGHT"
end
elseif point == "CENTER" then
if curX < GetScreenWidth() / 2 then
point = "LEFT"
else
point = "RIGHT"
end
end
frame:SetPoint(point, parent, relativePoint, curX - left - width / 2, 0)
if level == 1 then
frame.lastDirection = "RIGHT"
end
elseif cursorY then
local bottom = frame:GetBottom()
local height = frame:GetHeight()
local curX, curY = GetScaledCursorPosition()
frame:ClearAllPoints()
relativePoint = relativePoint or point
if point == "LEFT" or point == "RIGHT" then
if curX < GetScreenHeight() / 2 then
point = point .. "BOTTOM"
else
point = point .. "TOP"
end
elseif point == "CENTER" then
if curX < GetScreenHeight() / 2 then
point = "BOTTOM"
else
point = "TOP"
end
end
frame:SetPoint(point, parent, relativePoint, 0, curY - bottom - height / 2)
if level == 1 then
frame.lastDirection = "DOWN"
end
end
if (strsub(point, 1, 3) ~= strsub(relativePoint, 1, 3)) then
if frame:GetBottom() < 0 then
local point, parent, relativePoint, x, y = frame:GetPoint(1)
local change = GetScreenHeight() - frame:GetTop()
local otherChange = -frame:GetBottom()
if otherChange < change then
change = otherChange
end
frame:SetPoint(point, parent, relativePoint, x, y + change)
elseif frame:GetTop() > GetScreenHeight() then
local point, parent, relativePoint, x, y = frame:GetPoint(1)
local change = GetScreenHeight() - frame:GetTop()
local otherChange = -frame:GetBottom()
if otherChange < change then
change = otherChange
end
frame:SetPoint(point, parent, relativePoint, x, y + change)
end
end
end
CheckDualMonitor(self, frame)
StartCounting(self, level)
end
function Dewdrop:IsRegistered(parent)
self:argCheck(parent, 2, "table")
return not not self.registry[parent]
end
function Dewdrop:Register(parent, 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)
self:argCheck(parent, 2, "table")
if self.registry[parent] then
self:Unregister(parent)
end
local info = 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)
if type(info.children) == "table" then
local err, position = validateOptions(info.children)
if err then
if position then
Dewdrop:error(position .. ": " .. err)
else
Dewdrop:error(err)
end
end
end
self.registry[parent] = info
if not info.dontHook and not self.onceRegistered[parent] then
if parent:HasScript("OnMouseUp") then
local script = parent:GetScript("OnMouseUp")
parent:SetScript("OnMouseUp", function()
if script then
script()
end
if arg1 == "RightButton" and self.registry[parent] then
if self:IsOpen(parent) then
self:Close()
else
self:Open(parent)
end
end
end)
end
if parent:HasScript("OnMouseDown") then
local script = parent:GetScript("OnMouseDown")
parent:SetScript("OnMouseDown", function()
if script then
script()
end
if self.registry[parent] then
self:Close()
end
end)
end
end
self.onceRegistered[parent] = true
end
function Dewdrop:Unregister(parent)
self:argCheck(parent, 2, "table")
self.registry[parent] = nil
end
function Dewdrop:Open(parent, 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)
self:argCheck(parent, 2, "table")
local info
if type(k1) == "table" and k1[0] and k1.IsFrameType and self.registry[k1] then
info = tmp()
for k,v in pairs(self.registry[k1]) do
info[k] = v
end
else
info = 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)
if self.registry[parent] then
for k,v in pairs(self.registry[parent]) do
if info[k] == nil then
info[k] = v
end
end
end
end
local point = info.point
local relativePoint = info.relativePoint
local cursorX = info.cursorX
local cursorY = info.cursorY
if type(point) == "function" then
local b
point, b = point(parent)
if b then
relativePoint = b
end
end
if type(relativePoint) == "function" then
relativePoint = relativePoint(parent)
end
Open(self, parent, info.children, 1, nil, point, relativePoint, cursorX, cursorY)
end
function Clear(self, level)
if level then
if level.buttons then
for i = table.getn(level.buttons), 1, -1 do
ReleaseButton(self, level, i)
end
end
end
end
function Dewdrop:Close(level)
if DropDownList1:IsShown() then
DropDownList1:Hide()
end
if DewdropLib then
local d = DewdropLib:GetInstance('1.0')
local ret, val = pcall(d, IsOpen, d)
if ret and val then
DewdropLib:GetInstance('1.0'):Close()
end
end
self:argCheck(level, 2, "number", "nil")
if not level then
level = 1
end
if level == 1 and levels[level] then
levels[level].parented = false
end
if sliderFrame and sliderFrame.level >= level then
sliderFrame:Hide()
end
if editBoxFrame and editBoxFrame.level >= level then
editBoxFrame:Hide()
end
for i = level, table.getn(levels) do
Clear(self, levels[level])
levels[level]:Hide()
levels[i]:ClearAllPoints()
levels[i]:SetPoint("CENTER", UIParent, "CENTER")
end
end
function Dewdrop:AddLine(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 info = 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)
local level = info.level or currentLevel
info.level = nil
local button = AcquireButton(self, level)
if not next(info) then
info.disabled = true
end
button.disabled = info.isTitle or info.notClickable or info.disabled
button.isTitle = info.isTitle
button.notClickable = info.notClickable
if button.isTitle then
button.text:SetFontObject(GameFontNormalSmall)
elseif button.notClickable then
button.text:SetFontObject(GameFontHighlightSmall)
elseif button.disabled then
button.text:SetFontObject(GameFontDisableSmall)
else
button.text:SetFontObject(GameFontHighlightSmall)
end
if info.disabled then
button.arrow:SetDesaturated(true)
button.check:SetDesaturated(true)
else
button.arrow:SetDesaturated(false)
button.check:SetDesaturated(false)
end
if info.textR and info.textG and info.textB then
button.textR = info.textR
button.textG = info.textG
button.textB = info.textB
button.text:SetTextColor(button.textR, button.textG, button.textB)
else
button.text:SetTextColor(button.text:GetFontObject():GetTextColor())
end
button.notCheckable = info.notCheckable
button.text:SetPoint("LEFT", button, "LEFT", button.notCheckable and 0 or 24, 0)
button.checked = not info.notCheckable and info.checked
button.isRadio = not info.notCheckable and info.isRadio
if info.isRadio then
button.check:Show()
button.check:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton")
if button.checked then
button.check:SetTexCoord(0.25, 0.5, 0, 1)
button.check:SetVertexColor(1, 1, 1, 1)
else
button.check:SetTexCoord(0, 0.25, 0, 1)
button.check:SetVertexColor(1, 1, 1, 0.5)
end
button.radioHighlight:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton")
button.check:SetWidth(16)
button.check:SetHeight(16)
else
if button.checked then
if info.checkIcon then
button.check:SetWidth(16)
button.check:SetHeight(16)
button.check:SetTexture(info.checkIcon)
if string.sub(info.checkIcon, 1, 16) == "Interface\\Icons\\" then
button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95)
else
button.check:SetTexCoord(0, 1, 0, 1)
end
else
button.check:SetWidth(24)
button.check:SetHeight(24)
button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
button.check:SetTexCoord(0, 1, 0, 1)
end
button.check:SetVertexColor(1, 1, 1, 1)
else
button.check:SetVertexColor(1, 1, 1, 0)
end
end
if not button.disabled then
button.func = info.func
end
button.hasColorSwatch = info.hasColorSwatch
if button.hasColorSwatch then
button.colorSwatch:Show()
button.colorSwatch.texture:Show()
button.r = info.r or 1
button.g = info.g or 1
button.b = info.b or 1
button.colorSwatch.texture:SetTexture(button.r, button.g, button.b)
button.checked = false
button.func = nil
button.colorFunc = info.colorFunc
button.colorArg1 = info.colorArg1
button.colorArg2 = info.colorArg2
button.colorArg3 = info.colorArg3
button.colorArg4 = info.colorArg4
button.hasOpacity = info.hasOpacity
button.opacity = info.opacity or 1
else
button.colorSwatch:Hide()
button.colorSwatch.texture:Hide()
end
button.hasArrow = not button.hasColorSwatch and (info.value or info.hasSlider or info.hasEditBox) and info.hasArrow
if button.hasArrow then
button.arrow:SetAlpha(1)
if info.hasSlider then
button.hasSlider = true
button.sliderMin = info.sliderMin or 0
button.sliderMax = info.sliderMax or 1
button.sliderStep = info.sliderStep or 0
button.sliderIsPercent = info.sliderIsPercent and true or false
button.sliderMinText = info.sliderMinText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMin * 100) or button.sliderMin
button.sliderMaxText = info.sliderMaxText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMax * 100) or button.sliderMax
button.sliderFunc = info.sliderFunc
button.sliderValue = info.sliderValue
button.sliderArg1 = info.sliderArg1
button.sliderArg2 = info.sliderArg2
button.sliderArg3 = info.sliderArg3
button.sliderArg4 = info.sliderArg4
elseif info.hasEditBox then
button.hasEditBox = true
button.editBoxText = info.editBoxText or ""
button.editBoxFunc = info.editBoxFunc
button.editBoxArg1 = info.editBoxArg1
button.editBoxArg2 = info.editBoxArg2
button.editBoxArg3 = info.editBoxArg3
button.editBoxArg4 = info.editBoxArg4
button.editBoxChangeFunc = info.editBoxChangeFunc
button.editBoxChangeArg1 = info.editBoxChangeArg1
button.editBoxChangeArg2 = info.editBoxChangeArg2
button.editBoxChangeArg3 = info.editBoxChangeArg3
button.editBoxChangeArg4 = info.editBoxChangeArg4
button.editBoxValidateFunc = info.editBoxValidateFunc
button.editBoxValidateArg1 = info.editBoxValidateArg1
button.editBoxValidateArg2 = info.editBoxValidateArg2
button.editBoxValidateArg3 = info.editBoxValidateArg3
button.editBoxValidateArg4 = info.editBoxValidateArg4
else
button.value = info.value
end
else
button.arrow:SetAlpha(0)
end
button.arg1 = info.arg1
button.arg2 = info.arg2
button.arg3 = info.arg3
button.arg4 = info.arg4
button.closeWhenClicked = info.closeWhenClicked
button.textHeight = info.textHeight or UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT or 10
local font,_ = button.text:GetFont()
button.text:SetFont(STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF", button.textHeight)
button:SetHeight(button.textHeight + 6)
button.text:SetPoint("RIGHT", button.arrow, (button.hasColorSwatch or button.hasArrow) and "LEFT" or "RIGHT")
button.text:SetJustifyH(info.justifyH or "LEFT")
button.text:SetText(info.text)
button.tooltipTitle = info.tooltipTitle
button.tooltipText = info.tooltipText
button.tooltipFunc = info.tooltipFunc
button.tooltipArg1 = info.tooltipArg1
button.tooltipArg2 = info.tooltipArg2
button.tooltipArg3 = info.tooltipArg3
button.tooltipArg4 = info.tooltipArg4
if not button.tooltipTitle and not button.tooltipText and not button.tooltipFunc and not info.isTitle then
button.tooltipTitle = info.text
end
if type(button.func) == "string" then
self:assert(type(button.arg1) == "table", "Cannot call method " .. button.func .. " on a non-table")
self:assert(type(button.arg1[button.func]) == "function", "Method " .. button.func .. " nonexistant.")
end
end
function Dewdrop:InjectAceOptionsTable(handler, options)
self:argCheck(handler, 2, "table")
self:argCheck(options, 3, "table")
if string.lower(tostring(options.type)) ~= "group" then
self:error('Cannot inject into options table argument #3 if its type is not "group"')
end
if options.handler ~= nil and options.handler ~= handler then
self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2")
end
options.handler = handler
local class = handler.class
if not AceLibrary:HasInstance("AceOO-2.0") or not class then
self:error("Cannot retrieve AceOptions tables from a non-object argument #2")
end
while class and class ~= AceLibrary("AceOO-2.0").Class do
if type(class.GetAceOptionsDataTable) == "function" then
local t = class:GetAceOptionsDataTable(handler)
for k,v in pairs(t) do
if type(options.args) ~= "table" then
options.args = {}
end
if options.args[k] == nil then
options.args[k] = v
end
end
end
local mixins = class.mixins
if mixins then
for mixin in pairs(mixins) do
if type(mixin.GetAceOptionsDataTable) == "function" then
local t = mixin:GetAceOptionsDataTable(handler)
for k,v in pairs(t) do
if type(options.args) ~= "table" then
options.args = {}
end
if options.args[k] == nil then
options.args[k] = v
end
end
end
end
end
class = class.super
end
return options
end
local function activate(self, oldLib, oldDeactivate)
Dewdrop = self
if oldLib and oldLib.registry then
self.registry = oldLib.registry
self.onceRegistered = oldLib.onceRegistered
else
self.registry = {}
self.onceRegistered = {}
local WorldFrame_OnMouseDown = WorldFrame:GetScript("OnMouseDown")
local WorldFrame_OnMouseUp = WorldFrame:GetScript("OnMouseUp")
local oldX, oldY, clickTime
WorldFrame:SetScript("OnMouseDown", function()
oldX,oldY = GetCursorPosition()
clickTime = GetTime()
if WorldFrame_OnMouseDown then
WorldFrame_OnMouseDown()
end
end)
WorldFrame:SetScript("OnMouseUp", function()
local x,y = GetCursorPosition()
if not oldX or not oldY or not x or not y or not clickTime then
self:Close()
if WorldFrame_OnMouseUp then
WorldFrame_OnMouseUp()
end
return
end
local d = math.abs(x - oldX) + math.abs(y - oldY)
if d <= 5 and GetTime() - clickTime < 0.5 then
self:Close()
end
if WorldFrame_OnMouseUp then
WorldFrame_OnMouseUp()
end
end)
local DropDownList1_Show = DropDownList1.Show
function DropDownList1.Show(DropDownList1)
if levels[1] and levels[1]:IsVisible() then
self:Close()
end
DropDownList1_Show(DropDownList1)
end
local old_HideDropDownMenu = HideDropDownMenu
function HideDropDownMenu(num)
if levels[1] and levels[1]:IsVisible() then
self:Close()
end
old_HideDropDownMenu(num)
end
local old_CloseDropDownMenus = CloseDropDownMenus
function CloseDropDownMenus(num)
if levels[1] and levels[1]:IsVisible() then
self:Close()
end
old_CloseDropDownMenus(num)
end
end
levels = {}
buttons = {}
if oldDeactivate then
oldDeactivate(oldLib)
end
end
AceLibrary:Register(Dewdrop, MAJOR_VERSION, MINOR_VERSION, activate)