--[[ |
Name: Dewdrop-2.0 |
Revision: $Rev$ |
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 |
License: LGPL v2.1 |
]] |
|
local MAJOR_VERSION = "Dewdrop-2.0" |
local MINOR_VERSION = tonumber(strmatch("$Revision$", "%d+")) + 90000 |
|
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end |
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end |
|
local Dewdrop = {} |
|
local SharedMedia |
|
local CLOSE = "Close" |
local CLOSE_DESC = "Close the menu." |
local VALIDATION_ERROR = "Validation error." |
local USAGE_TOOLTIP = "Usage: %s." |
local RANGE_TOOLTIP = "Note that you can scroll your mouse wheel while over the slider to step by one." |
local RESET_KEYBINDING_DESC = "Hit escape to clear the keybinding." |
local KEY_BUTTON1 = "Left Mouse" |
local KEY_BUTTON2 = "Right Mouse" |
local DISABLED = "Disabled" |
local DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" |
|
if GetLocale() == "deDE" then |
CLOSE = "Schlie\195\159en" |
CLOSE_DESC = "Men\195\188 schlie\195\159en." |
VALIDATION_ERROR = "Validierungsfehler." |
USAGE_TOOLTIP = "Benutzung: %s." |
RANGE_TOOLTIP = "Beachte das du mit dem Mausrad scrollen kannst solange du mit dem Mauszeiger \195\188ber dem Schieberegler bist, um feinere Spr\195\188nge zu machen." |
RESET_KEYBINDING_DESC = "Escape dr\195\188cken, um die Tastenbelegung zu l\195\182schen." |
KEY_BUTTON1 = "Linke Maustaste" |
KEY_BUTTON2 = "Rechte Maustaste" |
DISABLED = "Deaktiviert" |
DEFAULT_CONFIRM_MESSAGE = "Bist du sicher das du `%s' machen willst?" |
elseif GetLocale() == "koKR" then |
CLOSE = "ë«ê¸°" |
CLOSE_DESC = "ë©ë´ë¥¼ ë«ìµëë¤." |
VALIDATION_ERROR = "ì¤ë¥ íì¸." |
USAGE_TOOLTIP = "ì¬ì©ë²: %s." |
RANGE_TOOLTIP = "ì림 : ì¬ë¼ì´ë ììì ë§ì°ì¤ í ì ì¬ì©íë©´ íë¨ê³ì© ì¡°ì í ì ììµëë¤." |
RESET_KEYBINDING_DESC = "ë¨ì¶í¤ë¥¼ í´ì íë ¤ë©´ ESCí¤ë¥¼ ë르ì¸ì." |
KEY_BUTTON1 = "ì¼ìª½ ë§ì°ì¤" |
KEY_BUTTON2 = "ì¤ë¥¸ìª½ ë§ì°ì¤" |
DISABLED = "ë¹íì±íë¨" |
DEFAULT_CONFIRM_MESSAGE = "ì ë§ë¡ `%s' ì¤íì íìê² ìµëê¹ ?" |
elseif GetLocale() == "frFR" then |
CLOSE = "Fermer" |
CLOSE_DESC = "Ferme le menu." |
VALIDATION_ERROR = "Erreur de validation." |
USAGE_TOOLTIP = "Utilisation : %s." |
RANGE_TOOLTIP = "Vous pouvez aussi utiliser la molette de la souris pour pour modifier progressivement." |
RESET_KEYBINDING_DESC = "Appuyez sur la touche Echappement pour effacer le raccourci." |
KEY_BUTTON1 = "Clic gauche" |
KEY_BUTTON2 = "Clic droit" |
DISABLED = "D\195\169sactiv\195\169" |
DEFAULT_CONFIRM_MESSAGE = "\195\138tes-vous s\195\187r de vouloir effectuer '%s' ?" |
elseif GetLocale() == "esES" then |
CLOSE = "Cerrar" |
CLOSE_DESC = "Cierra el menú." |
VALIDATION_ERROR = "Error de validación." |
USAGE_TOOLTIP = "Uso: %s." |
RANGE_TOOLTIP = "Puedes desplazarte verticalmente con la rueda del ratón sobre el desplazador." |
RESET_KEYBINDING_DESC = "Pulsa Escape para borrar la asignación de tecla." |
KEY_BUTTON1 = "Clic Izquierdo" |
KEY_BUTTON2 = "Clic Derecho" |
DISABLED = "Desactivado" |
DEFAULT_CONFIRM_MESSAGE = "¿Estás seguro de querer realizar `%s'?" |
elseif GetLocale() == "zhTW" then |
CLOSE = "éé" |
CLOSE_DESC = "ééé¸å®ã" |
VALIDATION_ERROR = "é©èé¯èª¤ã" |
USAGE_TOOLTIP = "ç¨æ³: %sã" |
RANGE_TOOLTIP = "ä½ å¯ä»¥å¨æ²åæ¢ä¸ä½¿ç¨æ»é¼ 滾輪ä¾æ²åã" |
RESET_KEYBINDING_DESC = "æEscéµæ¸
é¤å¿«æ·éµã" |
KEY_BUTTON1 = "æ»é¼ å·¦éµ" |
KEY_BUTTON2 = "æ»é¼ å³éµ" |
DISABLED = "åç¨" |
DEFAULT_CONFIRM_MESSAGE = "æ¯å¦å·è¡ã%sã?" |
elseif GetLocale() == "zhCN" then |
CLOSE = "å
³é" |
CLOSE_DESC = "å
³éèå" |
VALIDATION_ERROR = "éªè¯é误." |
USAGE_TOOLTIP = "ç¨æ³: %s." |
RANGE_TOOLTIP = "ä½ å¯ä»¥å¨æ»å¨æ¡ä¸ä½¿ç¨é¼ æ æ»è½®æ¥ç¿»é¡µ." |
RESET_KEYBINDING_DESC = "æESCé®æ¸
é¤æé®ç»å®" |
KEY_BUTTON1 = "é¼ æ å·¦é®" |
KEY_BUTTON2 = "é¼ æ å³é®" |
DISABLED = "ç¦ç¨" |
DEFAULT_CONFIRM_MESSAGE = "æ¯å¦æ§è¡'%s'?" |
elseif GetLocale() == "ruRU" then |
CLOSE = "ÐакÑÑÑÑ" |
CLOSE_DESC = "ÐакÑÑÑÑ Ð¼ÐµÐ½Ñ." |
VALIDATION_ERROR = "ÐÑибка пÑовеÑки даннÑÑ
." |
USAGE_TOOLTIP = "ÐÑполÑзÑйÑе: %s." |
RANGE_TOOLTIP = "ÐÑполÑзÑйÑе колеÑо мÑÑи Ð´Ð»Ñ Ð¿ÑокÑÑÑки ползÑнка." |
RESET_KEYBINDING_DESC = "ÐажмиÑе клавиÑÑ Escape Ð´Ð»Ñ Ð¾ÑиÑÑки клавиÑи." |
KEY_BUTTON1 = "ÐÐÐ" |
KEY_BUTTON2 = "ÐÐÐ" |
DISABLED = "ÐÑклÑÑено" |
DEFAULT_CONFIRM_MESSAGE = "ÐÑ ÑвеÑÐµÐ½Ñ ÑÑо Ð²Ñ Ñ
оÑиÑе вÑполнÑÑÑ `%s'?" |
end |
|
Dewdrop.KEY_BUTTON1 = KEY_BUTTON1 |
Dewdrop.KEY_BUTTON2 = KEY_BUTTON2 |
|
local function new(...) |
local t = {} |
for i = 1, select('#', ...), 2 do |
local k = select(i, ...) |
if k then |
t[k] = select(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 |
for i = 1, select('#', ...), 2 do |
local k = select(i, ...) |
if k then |
t[k] = select(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 |
for i = 1, select('#', ...), 2 do |
local k = select(i, ...) |
if k then |
t[k] = select(i+1, ...) |
else |
break |
end |
end |
return t |
end |
end |
local levels |
local buttons |
|
|
-- Secure frame handling: |
-- Rather than using secure buttons in the menu (has problems), we have one |
-- master secureframe that we pop onto menu items on mouseover. This requires |
-- some dark magic with OnLeave etc, but it's not too bad. |
|
local secureFrame = CreateFrame("Button", nil, nil, "SecureActionButtonTemplate") |
secureFrame:Hide() |
|
local function secureFrame_Show(self) |
local owner = self.owner |
|
if self.secure then -- Leftovers from previos owner, clean up! ("Shouldn't" happen but does..) |
for k,v in pairs(self.secure) do |
self:SetAttribute(k, nil) |
end |
end |
self.secure = owner.secure; -- Grab hold of new secure data |
|
local scale = owner:GetEffectiveScale() |
|
self:SetPoint("TOPLEFT", nil, "BOTTOMLEFT", owner:GetLeft() * scale, owner:GetTop() * scale) |
self:SetPoint("BOTTOMRIGHT", nil, "BOTTOMLEFT", owner:GetRight() * scale, owner:GetBottom() * scale) |
self:EnableMouse(true) |
for k,v in pairs(self.secure) do |
self:SetAttribute(k, v) |
end |
|
secureFrame:SetFrameStrata(owner:GetFrameStrata()) |
secureFrame:SetFrameLevel(owner:GetFrameLevel()+1) |
|
self:Show() |
end |
|
local function secureFrame_Hide(self) |
self:Hide() |
if self.secure then |
for k,v in pairs(self.secure) do |
self:SetAttribute(k, nil) |
end |
end |
self.secure = nil |
end |
|
secureFrame:SetScript("OnEvent", |
function() |
if event=="PLAYER_REGEN_ENABLED" then |
this.combat = false |
if not this:IsShown() and this.owner then |
secureFrame_Show(this) |
end |
elseif event=="PLAYER_REGEN_DISABLED" then |
this.combat = true |
if this:IsShown() then |
secureFrame_Hide(this) |
end |
end |
end |
) |
secureFrame:RegisterEvent("PLAYER_REGEN_ENABLED") |
secureFrame:RegisterEvent("PLAYER_REGEN_DISABLED") |
|
secureFrame:SetScript("OnLeave", |
function() |
local owner=this.owner |
this:Deactivate() |
owner:GetScript("OnLeave")() |
end |
) |
|
secureFrame:HookScript("OnClick", |
function() |
local realthis = this |
this = this.owner |
this:GetScript("OnClick")() |
end |
) |
|
function secureFrame:IsOwnedBy(frame) |
return self.owner == frame |
end |
|
function secureFrame:Activate(owner) |
if self.owner then -- "Shouldn't" happen but apparently it does and I cba to troubleshoot... |
if not self.combat then |
secureFrame_Hide(self) |
end |
end |
self.owner = owner |
if not self.combat then |
secureFrame_Show(self) |
end |
end |
|
function secureFrame:Deactivate() |
if not self.combat then |
secureFrame_Hide(self) |
end |
self.owner = nil |
end |
|
-- END secure frame utilities |
|
|
-- Underline on mouseover - use a single global underline that we move around, no point in creating lots of copies |
local underlineFrame = CreateFrame("Frame", nil) |
underlineFrame.tx = underlineFrame:CreateTexture() |
underlineFrame.tx:SetTexture(1,1,0.5,0.75) |
underlineFrame:SetScript("OnHide", function(this) this:Hide(); end) |
underlineFrame:SetScript("OnShow", function(this) -- change sizing on the fly to catch runtime uiscale changes |
underlineFrame.tx:SetPoint("TOPLEFT", -1, -2/this:GetEffectiveScale()) |
underlineFrame.tx:SetPoint("RIGHT", 1,0) |
underlineFrame.tx:SetHeight(0.6 / this:GetEffectiveScale()); |
end) |
underlineFrame:SetHeight(1) |
|
-- END underline on mouseover |
|
|
local function GetScaledCursorPosition() |
local x, y = GetCursorPosition() |
local scale = UIParent:GetEffectiveScale() |
return x / scale, y / scale |
end |
|
local function StartCounting(self, level) |
for i = level, 1, -1 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, elapsed) |
for _,level in ipairs(levels) do |
local count = level.count |
if count then |
count = count - elapsed |
if count < 0 then |
level.count = nil |
self:Close(level.num) |
else |
level.count = count |
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() |
local parent = level.parent or level:GetParent() |
if type(parent) ~= "table" then |
parent = UIParent |
end |
if level.lastDirection == "RIGHT" then |
if level.lastVDirection == "DOWN" then |
level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) |
else |
level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) |
end |
else |
if level.lastVDirection == "DOWN" then |
level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) |
else |
level:SetPoint("BOTTOMRIGHT", parent, "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() |
local parent = level.parent or level:GetParent() |
if type(parent) ~= "table" then |
parent = UIParent |
end |
if level.lastDirection == "RIGHT" then |
if level.lastVDirection == "DOWN" then |
level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) |
else |
level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) |
end |
else |
if level.lastVDirection == "DOWN" then |
level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) |
else |
level:SetPoint("BOTTOMRIGHT", parent, "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 |
-- button.arrow:SetVertexColor(1, 1, 1) |
-- button.arrow:SetHeight(16) |
-- button.arrow:SetWidth(16) |
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 function getArgs(t, str, num, ...) |
local x = t[str .. num] |
if x == nil then |
return ... |
else |
return x, getArgs(t, str, num + 1, ...) |
end |
end |
|
local sliderFrame |
local editBoxFrame |
|
local normalFont |
local lastSetFont |
local justSetFont = false |
local regionTmp = {} |
local function fillRegionTmp(...) |
for i = 1, select('#', ...) do |
regionTmp[i] = select(i, ...) |
end |
end |
|
local function showGameTooltip(this) |
if this.tooltipTitle or this.tooltipText then |
GameTooltip_SetDefaultAnchor(GameTooltip, this) |
local disabled = not this.isTitle and this.disabled |
local font |
if this.tooltipTitle then |
if SharedMedia and SharedMedia:IsValid("font", this.tooltipTitle) then |
font = SharedMedia:Fetch("font", this.tooltipTitle) |
end |
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 not font and SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then |
font = SharedMedia:Fetch("font", this.tooltipText) |
end |
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 SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then |
font = SharedMedia:Fetch("font", this.tooltipText) |
end |
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 |
if font then |
fillRegionTmp(GameTooltip:GetRegions()) |
lastSetFont = font |
justSetFont = true |
for i,v in ipairs(regionTmp) do |
if v.SetFont then |
local norm,size,outline = v:GetFont() |
v:SetFont(font, size, outline) |
if not normalFont then |
normalFont = norm |
end |
end |
regionTmp[i] = nil |
end |
elseif not normalFont then |
fillRegionTmp(GameTooltip:GetRegions()) |
for i,v in ipairs(regionTmp) do |
if v.GetFont and not normalFont then |
normalFont = v:GetFont() |
end |
regionTmp[i] = nil |
end |
end |
GameTooltip:Show() |
end |
if this.tooltipFunc then |
GameTooltip:SetOwner(this, "ANCHOR_NONE") |
GameTooltip:SetPoint("TOPLEFT", this, "TOPRIGHT", 5, 0) |
this.tooltipFunc(getArgs(this, 'tooltipArg', 1)) |
GameTooltip:Show() |
end |
end |
|
local tmpt = setmetatable({}, {mode='v'}) |
local numButtons = 0 |
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 #buttons == 0 then |
numButtons = numButtons + 1 |
button = CreateFrame("Button", "Dewdrop20Button" .. numButtons, nil) |
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.secure then |
secureFrame:Activate(this) |
elseif 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 |
if this.mouseoverUnderline then |
underlineFrame:SetParent(this) |
underlineFrame:SetPoint("BOTTOMLEFT",this.text,0,0) |
underlineFrame:SetWidth(this.text:GetWidth()) |
underlineFrame:Show() |
end |
end |
showGameTooltip(this) |
end) |
button:SetScript("OnHide", function() |
if this.secure and secureFrame:IsOwnedBy(this) then |
secureFrame:Deactivate() |
end |
end) |
button:SetScript("OnLeave", function() |
if this.secure and secureFrame:IsShown() then |
return; -- it's ok, we didn't actually mouse out of the button, only onto the secure frame on top of it |
end |
underlineFrame:Hide() |
if not this.selected then |
highlight:Hide() |
end |
button.radioHighlight:Hide() |
if this.level then |
StartCounting(self, this.level.num) |
end |
GameTooltip:Hide() |
end) |
local first = true |
button:SetScript("OnClick", function() |
if not this.disabled then |
if this.hasColorSwatch then |
local func = button.colorFunc |
local hasOpacity = this.hasOpacity |
local this = this |
for k in pairs(tmpt) do |
tmpt[k] = nil |
end |
for i = 1, 1000 do |
local x = this['colorArg'..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 = #tmpt |
tmpt[n+1] = r |
tmpt[n+2] = g |
tmpt[n+3] = b |
tmpt[n+4] = a |
func(unpack(tmpt)) |
tmpt[n+1] = nil |
tmpt[n+2] = nil |
tmpt[n+3] = nil |
tmpt[n+4] = nil |
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 func then |
local n = #tmpt |
tmpt[n+1] = r |
tmpt[n+2] = g |
tmpt[n+3] = b |
tmpt[n+4] = a |
func(unpack(tmpt)) |
for i = 1, n+4 do |
tmpt[i] = nil |
end |
end |
end |
self:Close(1) |
ShowUIPanel(ColorPickerFrame) |
elseif this.func then |
local level = this.level |
if type(this.func) == "string" then |
if type(this.arg1[this.func]) ~= "function" then |
self:error("Cannot call method %q", this.func) |
end |
this.arg1[this.func](this.arg1, getArgs(this, 'arg', 2)) |
else |
this.func(getArgs(this, 'arg', 1)) |
end |
if this.closeWhenClicked then |
self:Close() |
elseif level:IsShown() then |
for i = 1, level.num do |
Refresh(self, levels[i]) |
end |
local value = levels[level.num].value |
for i = level.num-1, 1, -1 do |
local level = levels[i] |
local good = false |
for _,button in ipairs(level.buttons) do |
if button.value == value then |
good = true |
break |
end |
end |
if not good then |
Dewdrop:Close(i+1) |
end |
value = levels[i].value |
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("LEFT", button, "RIGHT", -16, 0) |
arrow:SetWidth(16) |
arrow:SetHeight(16) |
arrow:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow") |
local colorSwatch = button:CreateTexture(nil, "ARTWORK") |
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("Interface\\Buttons\\WHITE8X8") |
texture:SetWidth(11.5) |
texture:SetHeight(11.5) |
texture:Show() |
texture:SetPoint("CENTER", colorSwatch, "CENTER") |
colorSwatch:SetPoint("RIGHT", button, "RIGHT", 0, 0) |
else |
button = table.remove(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 #level.buttons == 0 then |
button:SetPoint("TOP", level, "TOP", 0, -10) |
else |
button:SetPoint("TOP", level.buttons[#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 and type(level.parent) == "table" then |
level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT") |
else |
level:SetPoint("CENTER", UIParent, "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 |
button:SetAlpha(1) |
return button |
end |
|
local numLevels = 0 |
local function AcquireLevel(self, level) |
if not levels[level] then |
for i = #levels + 1, level, -1 do |
local i = i |
numLevels = numLevels + 1 |
local frame = CreateFrame("Button", "Dewdrop20Level" .. numLevels, nil) |
if i == 1 then |
local old_CloseSpecialWindows = CloseSpecialWindows |
function CloseSpecialWindows() |
local found = old_CloseSpecialWindows() |
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) |
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(this, arg1) |
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 |
local fullscreenFrame = GetUIPanel("fullscreen") |
local l = levels[level] |
local strata, framelevel = l:GetFrameStrata(), l:GetFrameLevel() |
if fullscreenFrame then |
l:SetParent(fullscreenFrame) |
else |
l:SetParent(UIParent) |
end |
l:SetFrameStrata(strata) |
l:SetFrameLevel(framelevel) |
l:SetAlpha(1) |
return l |
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 ~= "dragLink" and kind ~= "header" then |
return '"type" must either be "range", "text", "group", "toggle", "execute", "color", "dragLink", 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 |
end |
if options ~= baseOptions then |
if kind == "header" then |
elseif type(options.desc) ~= "string" then |
return '"desc" must be a string', position |
elseif options.desc:len() == 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 options.cmdName:len() == 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 options.guiName:len() == 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 options.name:len() == 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 > #t then |
return '"validate" numeric keys must be indexed properly. >= 1 and <= #t', 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 |
if options.multiToggle and options.multiToggle ~= true then |
return '"multiToggle" must be a boolean or nil if "validate" is a table', position |
end |
elseif options.validate == "keybinding" then |
-- no other checks |
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 |
if options.multiToggle and type(options.validate) ~= "table" then |
return '"validate" must be a table if "multiToggle" is true', position |
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.bigStep then |
if type(options.bigStep) ~= "number" then |
return '"bigStep" must be a number', position |
elseif options.bigStep < 0 then |
return '"bigStep" 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) ~= "number" then |
if type(k) ~= "string" then |
return '"args" keys must be strings or numbers', position |
elseif k:len() == 0 then |
return '"args" keys must not be 0-length strings.', position |
end |
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 |
elseif kind == "execute" then |
if type(options.confirm) ~= "string" and type(options.confirm) ~= "boolean" and type(options.confirm) ~= "nil" then |
return '"confirm" must be a string, boolean, or nil', position |
end |
end |
if options.icon and type(options.icon) ~= "string" then |
return'"icon" must be a string', position |
end |
if options.iconWidth or options.iconHeight then |
if type(options.iconWidth) ~= "number" or type(options.iconHeight) ~= "number" then |
return '"iconHeight" and "iconWidth" must be numbers', position |
end |
end |
if options.iconCoordLeft or options.iconCoordRight or options.iconCoordTop or options.iconCoordBottom then |
if type(options.iconCoordLeft) ~= "number" or type(options.iconCoordRight) ~= "number" or type(options.iconCoordTop) ~= "number" or type(options.iconCoordBottom) ~= "number" then |
return '"iconCoordLeft", "iconCoordRight", "iconCoordTop", and "iconCoordBottom" must be numbers', position |
end |
end |
end |
|
local validatedOptions |
|
local values |
local mysort_args |
local mysort |
local othersort |
local othersort_validate |
|
local baseFunc, currentLevel |
|
local function confirmPopup(message, func, ...) |
if not StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] then |
StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] = {} |
end |
local t = StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] |
for k in pairs(t) do |
t[k] = nil |
end |
t.text = message |
t.button1 = ACCEPT or "Accept" |
t.button2 = CANCEL or "Cancel" |
t.OnAccept = function() |
func(unpack(t)) |
end |
for i = 1, select('#', ...) do |
t[i] = select(i, ...) |
end |
t.timeout = 0 |
t.whileDead = 1 |
t.hideOnEscape = 1 |
|
Dewdrop:Close() |
StaticPopup_Show("DEWDROP20_CONFIRM_DIALOG") |
end |
|
|
local function getMethod(settingname, handler, v, methodName, ...) -- "..." is simply returned straight out cause you can't do "a,b,c = 111,f(),222" |
assert(v and type(v)=="table") |
assert(methodName and type(methodName)=="string") |
|
local method = v[methodName] |
if type(method)=="function" then |
return method, ... |
elseif type(method)=="string" then |
if not handler then |
Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method) |
elseif not handler[method] then |
Dewdrop:error("[%s] 'handler' method %q not defined", tostring(settingname), method) |
end |
return handler[method], handler, ... |
end |
|
Dewdrop:error("[%s] Missing %q directive", tostring(settingname), methodName) |
end |
|
local function callMethod(settingname, handler, v, methodName, ...) |
assert(v and type(v)=="table") |
assert(methodName and type(methodName)=="string") |
|
local method = v[methodName] |
if type(method)=="function" then |
local success, ret,ret2,ret3,ret4 = pcall(v[methodName], ...) |
if not success then |
geterrorhandler()(ret) |
return nil |
end |
return ret,ret2,ret3,ret4 |
|
elseif type(method)=="string" then |
|
local neg = method:match("^~(.-)$") |
if neg then |
method = neg |
end |
if not handler then |
Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method) |
elseif not handler[method] then |
Dewdrop:error("[%s] 'handler' (%q) method %q not defined", tostring(settingname), handler.name or "(unnamed)", method) |
end |
local success, ret,ret2,ret3,ret4 = pcall(handler[method], handler, ...) |
if not success then |
geterrorhandler()(ret) |
return nil |
end |
if neg then |
return not ret |
end |
return ret,ret2,ret3,ret4 |
elseif method == false then |
return nil |
end |
|
Dewdrop:error("[%s] Missing %q directive in %q", tostring(settingname), methodName, v.name or "(unnamed)") |
end |
|
local function skip1Nil(...) |
if select(1,...)==nil then |
return select(2,...) |
end |
return ... |
end |
|
function Dewdrop:FeedAceOptionsTable(options, difference) |
self:argCheck(options, 2, "table") |
self:argCheck(difference, 3, "nil", "number") |
if not currentLevel then |
self:error("Cannot call `FeedAceOptionsTable' outside of a Dewdrop declaration") |
end |
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] |
if not level then |
self:error("Improper level given") |
end |
if not values then |
values = {} |
else |
for k,v in pairs(values) do |
values[k] = nil |
end |
end |
|
local current = level |
while current do -- this traverses from higher level numbers to lower, building "values" with leaf nodes first and trunk nodes later |
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 #values > 0 do -- This loop traverses values from the END (trunk nodes first, then onto leaf nodes) |
if options.pass then |
if options.get and options.set then |
passTable = options |
elseif not passTable then |
passTable = options |
end |
else |
passTable = nil |
end |
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 |
local hidden = options.hidden |
if type(hidden) == "function" or type(hidden) == "string" then |
hidden = callMethod(options.name or "(options root)", handler, options, "hidden", options.passValue) or false |
end |
if hidden then |
return |
end |
local disabled = options.disabled |
if type(disabled) == "function" or type(disabled) == "string" then |
disabled = callMethod(options.name or "(options root)", handler, options, "disabled", options.passValue) or false |
end |
if disabled then |
self:AddLine( |
'text', DISABLED, |
'disabled', true |
) |
return |
end |
for k in pairs(options.args) do |
table.insert(values, k) |
end |
if options.pass then |
if options.get and options.set then |
passTable = options |
elseif not passTable then |
passTable = options |
end |
else |
passTable = nil |
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 bravo_name |
elseif not bravo_name then |
return false |
else |
return alpha_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < bravo_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() |
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 = #values >= 1 and (options.args[values[1]].order or 100) > 0 and (options.args[values[#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" or type(hidden) == "string" then |
hidden = callMethod(k, handler, v, "hidden", v.passValue) or false |
end |
if not hidden then |
if type(disabled) == "function" or type(disabled) == "string" then |
disabled = callMethod(k, handler, v, "disabled", v.passValue) or false |
end |
local name = (v.guiIconOnly and v.icon) and "" or (v.guiName or v.name) |
local desc = v.guiDesc or v.desc |
local iconHeight = v.iconHeight or 16 |
local iconWidth = v.iconWidth or 16 |
local iconCoordLeft = v.iconCoordLeft |
local iconCoordRight = v.iconCoordRight |
local iconCoordBottom = v.iconCoordBottom |
local iconCoordTop = v.iconCoordTop |
local tooltipTitle, tooltipText |
tooltipTitle = name |
if name ~= desc then |
tooltipText = desc |
end |
if type(v.usage) == "string" and v.usage:trim():len() > 0 then |
if tooltipText then |
tooltipText = tooltipText .. "\n\n" .. USAGE_TOOLTIP:format(v.usage) |
else |
tooltipText = USAGE_TOOLTIP:format(v.usage) |
end |
end |
local v_p = passTable |
if not v_p or (v.type ~= "execute" and v.get and v.set) or (v.type == "execute" and v.func) then |
v_p = v |
end |
local passValue = v.passValue or (v_p~=v and k) or nil |
if v.type == "toggle" then |
local checked = callMethod(name, handler, v_p, "get", passValue) or false |
local checked_arg = checked |
if type(v_p.get)=="string" and v_p.get:match("^~") then |
checked_arg = not checked |
end |
local func, arg1, arg2, arg3 = getMethod(name, handler, v_p, "set", skip1Nil(passValue, not checked_arg)) |
if v.guiNameIsMap then |
checked = checked and true or false |
name = tostring(v.map and v.map[checked]):gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") |
tooltipTitle = name |
checked = true--nil |
end |
self:AddLine( |
'text', name, |
'checked', checked, |
'isRadio', v.isRadio, |
'func', func, |
'arg1', arg1, |
'arg2', arg2, |
'arg3', arg3, |
'disabled', disabled, |
'tooltipTitle', tooltipTitle, |
'tooltipText', tooltipText |
) |
elseif v.type == "execute" then |
local func, arg1, arg2, arg3, arg4 |
local confirm = v.confirm |
if confirm == true then |
confirm = DEFAULT_CONFIRM_MESSAGE:format(tooltipText or tooltipTitle) |
func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue) |
elseif type(confirm) == "string" then |
func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue) |
else |
func,arg1,arg2 = getMethod(name, handler, v_p, "func", passValue) |
end |
self:AddLine( |
'text', name, |
'checked', checked, |
'func', func, |
'arg1', arg1, |
'arg2', arg2, |
'arg3', arg3, |
'arg4', arg4, |
'disabled', disabled, |
'tooltipTitle', tooltipTitle, |
'tooltipText', tooltipText, |
'icon', v.icon, |
'iconHeight', iconHeight, |
'iconWidth', iconWidth, |
'iconCoordLeft', iconCoordLeft, |
'iconCoordRight', iconCoordRight, |
'iconCoordTop', iconCoordTop, |
'iconCoordBottom', iconCoordBottom |
) |
elseif v.type == "range" then |
local sliderValue |
sliderValue = callMethod(name, handler, v_p, "get", passValue) or 0 |
local sliderFunc, sliderArg1, sliderArg2 = getMethod(name, handler, v_p, "set", passValue) |
if tooltipText then |
tooltipText = format("%s\n\n%s", tooltipText, RANGE_TOOLTIP) |
else |
tooltipText = RANGE_TOOLTIP |
end |
self:AddLine( |
'text', name, |
'hasArrow', true, |
'hasSlider', true, |
'sliderMin', v.min or 0, |
'sliderMax', v.max or 1, |
'sliderStep', v.step or 0, |
'sliderBigStep', v.bigStep or nil, |
'sliderIsPercent', v.isPercent or false, |
'sliderValue', sliderValue, |
'sliderFunc', sliderFunc, |
'sliderArg1', sliderArg1, |
'sliderArg2', sliderArg2, |
'fromAceOptions', true, |
'disabled', disabled, |
'tooltipTitle', tooltipTitle, |
'tooltipText', tooltipText, |
'icon', v.icon, |
'iconHeight', iconHeight, |
'iconWidth', iconWidth, |
'iconCoordLeft', iconCoordLeft, |
'iconCoordRight', iconCoordRight, |
'iconCoordTop', iconCoordTop, |
'iconCoordBottom', iconCoordBottom |
) |
elseif v.type == "color" then |
local r,g,b,a = callMethod(name, handler, v_p, "get", passValue) |
if not r then |
r,g,b,a = 0,0,0,0 |
end |
local colorFunc, colorArg1, colorArg2 = getMethod(name, handler, v_p, "set", passValue) |
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 |
local func,arg1,arg2 |
if v.onClick then |
func,arg1,arg2 = getMethod(name, handler, v, "onClick", passValue) |
end |
local checked |
if v.isChecked then |
checked = callMethod(name, handler, v, "isChecked", passValue) or false |
end |
self:AddLine( |
'text', name, |
'hasArrow', true, |
'value', k, |
'func', func, |
'arg1', arg1, |
'arg2', arg2, |
'mouseoverUnderline', func and true or nil, |
'disabled', disabled, |
'checked', checked, |
'tooltipTitle', tooltipTitle, |
'tooltipText', tooltipText, |
'icon', v.icon, |
'iconHeight', iconHeight, |
'iconWidth', iconWidth, |
'iconCoordLeft', iconCoordLeft, |
'iconCoordRight', iconCoordRight, |
'iconCoordTop', iconCoordTop, |
'iconCoordBottom', iconCoordBottom |
) |
else |
local editBoxText |
editBoxText = callMethod(name, handler, v_p, "get", passValue) or "" |
local editBoxFunc, editBoxArg1, editBoxArg2 = getMethod(name, handler, v_p, "set", passValue) |
|
local editBoxValidateFunc, editBoxValidateArg1 |
|
if v.validate and v.validate ~= "keybinding" then |
if v.validate == "keybinding" then |
if tooltipText then |
tooltipText = format("%s\n\n%s", tooltipText, RESET_KEYBINDING_DESC) |
else |
tooltipText = RESET_KEYBINDING_DESC |
end |
else |
editBoxValidateFunc, editBoxValidateArg1 = getMethod(name, handler, v, "validate") -- no passvalue! |
end |
end |
|
self:AddLine( |
'text', name, |
'hasArrow', true, |
'icon', v.icon, |
'iconHeight', iconHeight, |
'iconWidth', iconWidth, |
'iconCoordLeft', iconCoordLeft, |
'iconCoordRight', iconCoordRight, |
'iconCoordTop', iconCoordTop, |
'iconCoordBottom', iconCoordBottom, |
'hasEditBox', true, |
'editBoxText', editBoxText, |
'editBoxFunc', editBoxFunc, |
'editBoxArg1', editBoxArg1, |
'editBoxArg2', editBoxArg2, |
'editBoxValidateFunc', editBoxValidateFunc, |
'editBoxValidateArg1', editBoxValidateArg1, |
'editBoxIsKeybinding', v.validate == "keybinding", |
'editBoxKeybindingOnly', v.keybindingOnly, |
'editBoxKeybindingExcept', v.keybindingExcept, |
'disabled', disabled, |
'tooltipTitle', tooltipTitle, |
'tooltipText', tooltipText |
) |
end |
elseif v.type == "group" then |
local func,arg1,arg2 |
if v.onClick then |
func,arg1,arg2 = getMethod(name, handler, v, "onClick", passValue) |
end |
local checked |
if v.isChecked then |
checked = callMethod(name, handler, v, "isChecked", passValue) or false |
end |
self:AddLine( |
'text', name, |
'hasArrow', true, |
'value', k, |
'func', func, |
'arg1', arg1, |
'arg2', arg2, |
'mouseoverUnderline', func and true or nil, |
'disabled', disabled, |
'checked', checked, |
'tooltipTitle', tooltipTitle, |
'tooltipText', tooltipText, |
'icon', v.icon, |
'iconHeight', iconHeight, |
'iconWidth', iconWidth, |
'iconCoordLeft', iconCoordLeft, |
'iconCoordRight', iconCoordRight, |
'iconCoordTop', iconCoordTop, |
'iconCoordBottom', iconCoordBottom |
) |
elseif v.type == "header" then |
if name == "" or not name then |
self:AddLine( |
'isTitle', true, |
'icon', v.icon, |
'iconHeight', iconHeight, |
'iconWidth', iconWidth, |
'iconCoordLeft', iconCoordLeft, |
'iconCoordRight', iconCoordRight, |
'iconCoordTop', iconCoordTop, |
'iconCoordBottom', iconCoordBottom |
) |
else |
self:AddLine( |
'text', name, |
'isTitle', true, |
'icon', v.icon, |
'iconHeight', iconHeight, |
'iconWidth', iconWidth, |
'iconCoordLeft', iconCoordLeft, |
'iconCoordRight', iconCoordRight, |
'iconCoordTop', iconCoordTop, |
'iconCoordBottom', iconCoordBottom |
) |
end |
end |
end |
last_order = v.order or 100 |
end |
elseif options.type == "text" and type(options.validate) == "table" then |
local current |
local options_p = passTable |
if not options_p or (options.get and options.set) then |
options_p = options |
passTable = nil |
passValue = nil |
end |
local multiToggle = options.multiToggle |
local passValue = options.passValue or passValue |
if not multiToggle then |
current = callMethod(k, handler, options_p, "get", 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]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < othersort_validate[bravo]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() |
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, arg3, arg4 = getMethod(k, handler, options_p, "set", skip1Nil(passValue, k)) |
local checked |
if multiToggle then |
checked = callMethod(k, handler, options_p, "get", skip1Nil(passValue, k)) or false |
if arg2 == nil then |
arg2 = not checked |
elseif arg3 == nil then |
arg3 = not checked |
else |
arg4 = not checked |
end |
else |
checked = (k == current or (type(k) == "string" and type(current) == "string" and k:lower() == current:lower())) |
if checked then |
func, arg1, arg2, arg3, arg4 = nil, nil, nil, nil, nil |
end |
end |
local tooltipTitle |
local tooltipText |
if options.validateDesc then |
tooltipTitle = v |
tooltipText = options.validateDesc[k] |
else |
tooltipTitle = options.guiName or options.name |
tooltipText = v |
end |
self:AddLine( |
'text', v, |
'func', func, |
'arg1', arg1, |
'arg2', arg2, |
'arg3', arg3, |
'arg4', arg4, |
'isRadio', not multiToggle, |
'checked', checked, |
'tooltipTitle', tooltipTitle, |
'tooltipText', tooltipText |
) |
end |
for k in pairs(values) do |
values[k] = nil |
end |
else |
return false |
end |
return true |
end |
|
function Dewdrop:FeedTable(s, difference) |
self:argCheck(s, 2, "table") |
self:argCheck(difference, 3, "nil", "number") |
if not currentLevel then |
self:error("Cannot call `FeedTable' outside of a Dewdrop declaration") |
end |
if not difference then |
difference = 0 |
end |
local level = levels[currentLevel] |
if not level then |
self:error("Improper level given") |
end |
if not values then |
values = {} |
else |
for k,v in pairs(values) do |
values[k] = nil |
end |
end |
local t = s.subMenu and s or {subMenu = s} |
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 |
|
while #values > 0 do |
local value = table.remove(values) |
t = t.subMenu and t.subMenu[value] |
if not t then |
return |
end |
end |
|
if t.subMenu or current.num == 1 then |
for k in pairs(t.subMenu) do |
table.insert(values, k) |
end |
table.sort(values) |
for _,k in ipairs(values) do |
local argTable = {"value", k} |
for key, val in pairs(t.subMenu[k]) do |
table.insert(argTable, key) |
table.insert(argTable, val) |
end |
self:AddLine(unpack(argTable)) |
end |
for k in pairs(values) do |
values[k] = nil |
end |
return 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 name:find('^table:') and not handler.hideMenuTitle then |
name = name:gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") |
self:AddLine( |
'text', name, |
'isTitle', true |
) |
end |
end |
-- elseif level.parentText then |
-- self:AddLine( |
-- 'text', level.parentText, |
-- 'tooltipTitle', level.parentTooltipTitle, |
-- 'tooltipText', level.parentTooltipText, |
-- 'tooltipFunc', level.parentTooltipFunc, |
-- 'isTitle', true |
-- ) |
end |
self:FeedAceOptionsTable(baseFunc) |
if currentLevel == 1 then |
self:AddLine( |
'text', CLOSE, |
'tooltipTitle', CLOSE, |
'tooltipText', CLOSE_DESC, |
'closeWhenClicked', true |
) |
end |
else |
-- if level.parentText then |
-- self:AddLine( |
-- 'text', level.parentText, |
-- 'tooltipTitle', level.parentTooltipTitle, |
-- 'tooltipText', level.parentTooltipText, |
-- 'tooltipFunc', level.parentTooltipFunc, |
-- 'isTitle', true |
-- ) |
-- end |
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", "nil") |
if not level then |
for k,v in pairs(levels) do |
Refresh(self, v) |
end |
else |
Refresh(self, levels[level]) |
end |
end |
|
function OpenSlider(self, parent) |
if not sliderFrame then |
sliderFrame = CreateFrame("Frame", nil, nil) |
sliderFrame:SetWidth(100) |
sliderFrame:SetHeight(170) |
sliderFrame:SetScale(UIParent:GetScale()) |
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:EnableMouseWheel(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.000000001) |
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 editBox = CreateFrame("EditBox", nil, sliderFrame) |
sliderFrame.currentText = editBox |
editBox:SetFontObject(ChatFontNormal) |
editBox:SetHeight(13) |
editBox:SetPoint("RIGHT", sliderFrame, "RIGHT", -16, 0) |
editBox:SetPoint("LEFT", slider, "RIGHT", 12, 0) |
editBox:SetText("50%") |
editBox:SetJustifyH("CENTER") |
|
local width = editBox:GetWidth()/2 + 10 |
local left = editBox:CreateTexture(nil, "BACKGROUND") |
left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left") |
left:SetTexCoord(0, width / 256, 0, 1) |
left:SetWidth(width) |
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(1 - width / 256, 1, 0, 1) |
right:SetWidth(width) |
right:SetHeight(32) |
right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0) |
|
local changed = false |
local inside = false |
slider:SetScript("OnValueChanged", function() |
if sliderFrame.changing then |
return |
end |
changed = true |
local done = false |
if sliderFrame.parent and sliderFrame.parent.sliderFunc then |
local min = sliderFrame.parent.sliderMin or 0 |
local max = sliderFrame.parent.sliderMax or 1 |
local step |
if sliderFrame.fineStep then |
step = sliderFrame.parent.sliderStep or (max - min) / 100 |
else |
step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100 |
end |
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 value == sliderFrame.lastValue then |
return |
end |
sliderFrame.lastValue = value |
local text = sliderFrame.parent.sliderFunc(getArgs(sliderFrame.parent, 'sliderArg', 1, value)) |
if sliderFrame.parent.fromAceOptions then |
text = nil |
elseif type(text) == "string" or type(text) == "number" then |
sliderFrame.currentText:SetText(text) |
done = true |
end |
end |
if not done then |
local min = sliderFrame.parent.sliderMin or 0 |
local max = sliderFrame.parent.sliderMax or 1 |
local step |
if sliderFrame.fineStep then |
step = sliderFrame.parent.sliderStep or (max - min) / 100 |
else |
step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100 |
end |
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) |
local function onEnter() |
StopCounting(self, sliderFrame.level) |
showGameTooltip(sliderFrame.parent) |
end |
local function onLeave() |
GameTooltip:Hide() |
end |
sliderFrame:SetScript("OnEnter", onEnter) |
sliderFrame:SetScript("OnLeave", function() |
GameTooltip:Hide() |
if changed then |
local parent = sliderFrame.parent |
local sliderFunc = parent.sliderFunc |
for i = 1, sliderFrame.level - 1 do |
Refresh(self, levels[i]) |
end |
local newParent |
for _,button in ipairs(levels[sliderFrame.level-1].buttons) do |
if button.sliderFunc == sliderFunc then |
newParent = button |
break |
end |
end |
if newParent then |
OpenSlider(self, newParent) |
else |
sliderFrame:Hide() |
end |
end |
end) |
editBox:SetScript("OnEnter", onEnter) |
editBox:SetScript("OnLeave", onLeave) |
slider:SetScript("OnMouseDown", function() |
sliderFrame.mouseDown = true |
GameTooltip:Hide() |
end) |
slider:SetScript("OnMouseUp", function() |
sliderFrame.mouseDown = false |
if changed--[[ and not inside]] then |
local parent = sliderFrame.parent |
local sliderFunc = parent.sliderFunc |
for i = 1, sliderFrame.level - 1 do |
Refresh(self, levels[i]) |
end |
local newParent |
for _,button in ipairs(levels[sliderFrame.level-1].buttons) do |
if button.sliderFunc == sliderFunc then |
newParent = button |
break |
end |
end |
if newParent then |
OpenSlider(self, newParent) |
else |
sliderFrame:Hide() |
end |
end |
if inside then |
showGameTooltip(sliderFrame.parent) |
end |
end) |
slider:SetScript("OnEnter", function() |
inside = true |
StopCounting(self, sliderFrame.level) |
showGameTooltip(sliderFrame.parent) |
end) |
slider:SetScript("OnLeave", function() |
inside = false |
GameTooltip:Hide() |
if changed and not sliderFrame.mouseDown then |
local parent = sliderFrame.parent |
local sliderFunc = parent.sliderFunc |
for i = 1, sliderFrame.level - 1 do |
Refresh(self, levels[i]) |
end |
local newParent |
for _,button in ipairs(levels[sliderFrame.level-1].buttons) do |
if button.sliderFunc == sliderFunc then |
newParent = button |
break |
end |
end |
if newParent then |
OpenSlider(self, newParent) |
else |
sliderFrame:Hide() |
end |
|
changed = false |
end |
end) |
sliderFrame:SetScript("OnMouseWheel", function(t, a1) |
local arg1 = a1 or arg1 |
local up = arg1 > 0 |
|
local min = sliderFrame.parent.sliderMin or 0 |
local max = sliderFrame.parent.sliderMax or 1 |
local step = sliderFrame.parent.sliderStep or (max - min) / 100 |
if step <= 0 then |
step = (max - min) / 100 |
end |
|
local value = (1 - slider:GetValue()) * (max - min) + min |
if up then |
value = value + step |
else |
value = value - step |
end |
if value > max then |
value = max |
elseif value < min then |
value = min |
end |
sliderFrame.fineStep = true |
if max<=min then |
slider:SetValue(0) |
else |
slider:SetValue(1 - (value - min) / (max - min)) |
end |
sliderFrame.fineStep = nil |
end) |
slider:SetScript("OnMouseWheel", sliderFrame:GetScript("OnMouseWheel")) |
editBox:SetScript("OnEnterPressed", function(t, a1) |
local value = editBox:GetNumber() |
|
if sliderFrame.parent.sliderIsPercent then |
value = value / 100 |
end |
|
local min = sliderFrame.parent.sliderMin or 0 |
local max = sliderFrame.parent.sliderMax or 1 |
|
if value > max then |
value = max |
elseif value < min then |
value = min |
end |
sliderFrame.fineStep = true |
if max <= min then |
slider:SetValue(0) |
else |
slider:SetValue(1 - (value - min) / (max - min)) |
end |
sliderFrame.fineStep = nil |
|
StartCounting(self, sliderFrame.level) |
end) |
editBox:SetScript("OnEscapePressed", function() |
self:Close(sliderFrame.level) |
StartCounting(self, sliderFrame.level) |
end) |
editBox:SetAutoFocus(false) |
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.currentText:SetFrameLevel(sliderFrame:GetFrameLevel() + 1) |
sliderFrame.currentText:ClearFocus() |
sliderFrame.changing = true |
if not parent.sliderMin or not parent.sliderMax then |
return |
end |
|
if parent.arrow then |
-- parent.arrow:SetVertexColor(0.2, 0.6, 0) |
-- parent.arrow:SetHeight(24) |
-- parent.arrow:SetWidth(24) |
parent.selected = true |
parent.highlight:Show() |
end |
|
sliderFrame:SetClampedToScreen(false) |
if not parent.sliderValue then |
parent.sliderValue = (parent.sliderMin + parent.sliderMax) / 2 |
end |
if parent.sliderMax <= parent.sliderMin then |
sliderFrame.slider:SetValue(0) |
else |
sliderFrame.slider:SetValue(1 - (parent.sliderValue - parent.sliderMin) / (parent.sliderMax - parent.sliderMin)) |
end |
sliderFrame.changing = false |
sliderFrame.bottomText:SetText(parent.sliderMinText or "0") |
sliderFrame.topText:SetText(parent.sliderMaxText or "1") |
local text |
if parent.sliderFunc and not parent.fromAceOptions then |
text = parent.sliderFunc(getArgs(parent, 'sliderArg', 1, parent.sliderValue)) |
end |
if type(text) == "number" or type(text) == "string" then |
sliderFrame.currentText:SetText(text) |
elseif parent.sliderIsPercent then |
sliderFrame.currentText:SetText(string.format("%.0f%%", parent.sliderValue * 100)) |
else |
if parent.sliderStep < 0.1 then |
sliderFrame.currentText:SetText(string.format("%.2f", parent.sliderValue)) |
elseif parent.sliderStep < 1 then |
sliderFrame.currentText:SetText(string.format("%.1f", parent.sliderValue)) |
else |
sliderFrame.currentText:SetText(string.format("%.0f", parent.sliderValue)) |
end |
end |
|
|
sliderFrame.lastValue = parent.sliderValue |
|
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 |
sliderFrame:SetClampedToScreen(true) |
end |
|
function OpenEditBox(self, parent) |
if not editBoxFrame then |
editBoxFrame = CreateFrame("Frame", nil, nil) |
editBoxFrame:SetWidth(200) |
editBoxFrame:SetHeight(40) |
editBoxFrame:SetScale(UIParent:GetScale()) |
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:EnableMouseWheel(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 t = editBox.realText or editBox:GetText() or "" |
local result = editBoxFrame.parent.editBoxValidateFunc(getArgs(editBoxFrame.parent, 'editBoxValidateArg', 1, t)) |
if not result then |
UIErrorsFrame:AddMessage(VALIDATION_ERROR, 1, 0, 0) |
return |
end |
end |
if editBoxFrame.parent and editBoxFrame.parent.editBoxFunc then |
local t |
if editBox.realText ~= "NONE" then |
t = editBox.realText or editBox:GetText() or "" |
end |
editBoxFrame.parent.editBoxFunc(getArgs(editBoxFrame.parent, 'editBoxArg', 1, t)) |
end |
self:Close(editBoxFrame.level) |
for i = 1, editBoxFrame.level - 1 do |
Refresh(self, levels[i]) |
end |
StartCounting(self, editBoxFrame.level-1) |
end) |
editBox:SetScript("OnEscapePressed", function() |
self:Close(editBoxFrame.level) |
StartCounting(self, editBoxFrame.level-1) |
end) |
editBox:SetScript("OnReceiveDrag", function(this) |
if GetCursorInfo then |
local type, alpha, bravo = GetCursorInfo() |
local text |
if type == "spell" then |
text = GetSpellName(alpha, bravo) |
elseif type == "item" then |
text = bravo |
end |
if not text then |
return |
end |
ClearCursor() |
editBox:SetText(text) |
end |
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(tostring(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 t |
if editBox.realText ~= "NONE" then |
t = editBox.realText or editBox:GetText() or "" |
end |
local text = editBoxFrame.parent.editBoxChangeFunc(getArgs(editBoxFrame.parent, 'editBoxChangeArg', 1, t)) |
if text then |
editBox:SpecialSetText(text) |
end |
end |
end) |
editBoxFrame:SetScript("OnEnter", function() |
StopCounting(self, editBoxFrame.level) |
showGameTooltip(editBoxFrame.parent) |
end) |
editBoxFrame:SetScript("OnLeave", function() |
GameTooltip:Hide() |
end) |
editBox:SetScript("OnEnter", function() |
StopCounting(self, editBoxFrame.level) |
showGameTooltip(editBoxFrame.parent) |
end) |
editBox:SetScript("OnLeave", function() |
GameTooltip:Hide() |
end) |
editBoxFrame:SetScript("OnKeyDown", function(this, a1) |
if not editBox.keybinding then |
return |
end |
local arg1 = a1 or arg1 |
local screenshotKey = GetBindingKey("SCREENSHOT") |
if screenshotKey and arg1 == screenshotKey then |
Screenshot() |
return |
end |
|
if arg1 == "LeftButton" then |
arg1 = "BUTTON1" |
elseif arg1 == "RightButton" then |
arg1 = "BUTTON2" |
elseif arg1 == "MiddleButton" then |
arg1 = "BUTTON3" |
elseif arg1 == "Button4" then |
arg1 = "BUTTON4" |
elseif arg1 == "Button5" then |
arg1 = "BUTTON5" |
end |
if arg1 == "UNKNOWN" then |
return |
elseif arg1 == "SHIFT" or arg1 == "CTRL" or arg1 == "ALT" then |
return |
elseif arg1 == "ENTER" then |
if editBox.keybindingOnly and not editBox.keybindingOnly[editBox.realText] then |
return editBox:GetScript("OnEscapePressed")() |
elseif editBox.keybindingExcept and editBox.keybindingExcept[editBox.realText] then |
return editBox:GetScript("OnEscapePressed")() |
else |
return editBox:GetScript("OnEnterPressed")() |
end |
elseif arg1 == "ESCAPE" then |
if editBox.realText == "NONE" then |
return editBox:GetScript("OnEscapePressed")() |
else |
editBox:SpecialSetText(NONE or "NONE") |
editBox.realText = "NONE" |
return |
end |
elseif editBox.keybindingOnly and not editBox.keybindingOnly[arg1] then |
return |
elseif editBox.keybindingExcept and editBox.keybindingExcept[arg1] then |
return |
end |
local s = GetBindingText(arg1, "KEY_") |
if s == "BUTTON1" then |
s = KEY_BUTTON1 |
elseif s == "BUTTON2" then |
s = KEY_BUTTON2 |
end |
local real = arg1 |
if IsShiftKeyDown() then |
s = "Shift-" .. s |
real = "SHIFT-" .. real |
end |
if IsControlKeyDown() then |
s = "Ctrl-" .. s |
real = "CTRL-" .. real |
end |
if IsAltKeyDown() then |
s = "Alt-" .. s |
real = "ALT-" .. real |
end |
if editBox:GetText() ~= s then |
editBox:SpecialSetText("-") |
editBox:SpecialSetText(s) |
editBox.realText = real |
return editBox:GetScript("OnTextChanged")() |
end |
end) |
editBoxFrame:SetScript("OnMouseDown", editBoxFrame:GetScript("OnKeyDown")) |
editBox:SetScript("OnMouseDown", function(this, ...) |
if GetCursorInfo and (CursorHasItem() or CursorHasSpell()) then |
return editBox:GetScript("OnReceiveDrag")(this, ...) |
end |
return editBoxFrame:GetScript("OnKeyDown")(this, ...) |
end) |
editBoxFrame:SetScript("OnMouseWheel", function(t, a1) |
local arg1 = a1 or arg1 |
local up = arg1 > 0 |
arg1 = up and "MOUSEWHEELUP" or "MOUSEWHEELDOWN" |
return editBoxFrame:GetScript("OnKeyDown")(t or this, arg1) |
end) |
editBox:SetScript("OnMouseWheel", editBoxFrame:GetScript("OnMouseWheel")) |
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.realText = nil |
editBoxFrame:SetClampedToScreen(false) |
|
editBoxFrame.editBox:SpecialSetText("") |
if parent.editBoxIsKeybinding then |
local s = parent.editBoxText |
if s == "" then |
s = "NONE" |
end |
editBoxFrame.editBox.realText = s |
if s and s ~= "NONE" then |
local alpha,bravo = s:match("^(.+)%-(.+)$") |
if not bravo then |
alpha = nil |
bravo = s |
end |
bravo = GetBindingText(bravo, "KEY_") |
if alpha then |
editBoxFrame.editBox:SpecialSetText(alpha:upper() .. "-" .. bravo) |
else |
editBoxFrame.editBox:SpecialSetText(bravo) |
end |
else |
editBoxFrame.editBox:SpecialSetText(NONE or "NONE") |
end |
else |
editBoxFrame.editBox:SpecialSetText(parent.editBoxText) |
end |
|
editBoxFrame.editBox.keybinding = parent.editBoxIsKeybinding |
editBoxFrame.editBox.keybindingOnly = parent.editBoxKeybindingOnly |
editBoxFrame.editBox.keybindingExcept = parent.editBoxKeybindingExcept |
editBoxFrame.editBox:EnableKeyboard(not parent.editBoxIsKeybinding) |
editBoxFrame:EnableKeyboard(parent.editBoxIsKeybinding) |
|
if parent.arrow then |
-- parent.arrow:SetVertexColor(0.2, 0.6, 0) |
-- parent.arrow:SetHeight(24) |
-- parent.arrow:SetWidth(24) |
parent.selected = true |
parent.highlight:Show() |
end |
|
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 |
editBoxFrame:SetClampedToScreen(true) |
end |
|
function Dewdrop:EncodeKeybinding(text) |
if text == nil or text == "NONE" then |
return nil |
end |
text = tostring(text):upper() |
local shift, ctrl, alt |
local modifier |
while true do |
if text == "-" then |
break |
end |
modifier, text = strsplit('-', text, 2) |
if text then |
if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then |
return false |
end |
if modifier == "SHIFT" then |
if shift then |
return false |
end |
shift = true |
end |
if modifier == "CTRL" then |
if ctrl then |
return false |
end |
ctrl = true |
end |
if modifier == "ALT" then |
if alt then |
return false |
end |
alt = true |
end |
else |
text = modifier |
break |
end |
end |
if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:len() == 0 or text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] and text ~= "BUTTON1" and text ~= "BUTTON2" then |
return false |
end |
local s = GetBindingText(text, "KEY_") |
if s == "BUTTON1" then |
s = KEY_BUTTON1 |
elseif s == "BUTTON2" then |
s = KEY_BUTTON2 |
end |
if shift then |
s = "Shift-" .. s |
end |
if ctrl then |
s = "Ctrl-" .. s |
end |
if alt then |
s = "Alt-" .. s |
end |
return s |
end |
|
function Dewdrop:IsOpen(parent) |
self:argCheck(parent, 2, "table", "string", "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 |
if type(parent) == "table" then |
parent:GetCenter() |
end |
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 |
-- levels[level].parentText = parent.text and parent.text:GetText() or nil |
-- levels[level].parentTooltipTitle = parent.tooltipTitle |
-- levels[level].parentTooltipText = parent.tooltipText |
-- levels[level].parentTooltipFunc = parent.tooltipFunc |
if type(parent) == "table" and parent.arrow then |
-- parent.arrow:SetVertexColor(0.2, 0.6, 0) |
-- parent.arrow:SetHeight(24) |
-- parent.arrow:SetWidth(24) |
parent.selected = true |
parent.highlight:Show() |
end |
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, type(parent) == "table" and parent or UIParent, 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, type(parent) == "table" and parent or UIParent, 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, type(parent) == "table" and parent or UIParent, 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, type(parent) == "table" and parent or UIParent, 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) |
frame:SetClampedToScreen(true) |
frame:SetClampedToScreen(false) |
StartCounting(self, level) |
end |
|
function Dewdrop:IsRegistered(parent) |
self:argCheck(parent, 2, "table", "string") |
return not not self.registry[parent] |
end |
|
function Dewdrop:Register(parent, ...) |
self:argCheck(parent, 2, "table", "string") |
if self.registry[parent] then |
self:Unregister(parent) |
end |
local info = new(...) |
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] and type(parent) == "table" then |
if parent:HasScript("OnMouseUp") then |
local script = parent:GetScript("OnMouseUp") |
parent:SetScript("OnMouseUp", function(this, ...) |
if script then |
script(this, ...) |
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(this, ...) |
if script then |
script(this, ...) |
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", "string") |
self.registry[parent] = nil |
end |
|
function Dewdrop:Open(parent, ...) |
self:argCheck(parent, 2, "table", "string") |
local info |
local k1 = ... |
if type(k1) == "table" and k1[0] and k1.IsFrameType and self.registry[k1] then |
info = tmp(select(2, ...)) |
for k,v in pairs(self.registry[k1]) do |
if info[k] == nil then |
info[k] = v |
end |
end |
else |
info = tmp(...) |
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 = #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 level > 1 and levels[level-1].buttons then |
local buttons = levels[level-1].buttons |
for _,button in ipairs(buttons) do |
-- button.arrow:SetWidth(16) |
-- button.arrow:SetHeight(16) |
button.selected = nil |
button.highlight:Hide() |
-- button.arrow:SetVertexColor(1, 1, 1) |
end |
end |
if sliderFrame and sliderFrame.level >= level then |
sliderFrame:Hide() |
end |
if editBoxFrame and editBoxFrame.level >= level then |
editBoxFrame:Hide() |
end |
for i = level, #levels do |
Clear(self, levels[level]) |
levels[i]:Hide() |
levels[i]:ClearAllPoints() |
levels[i]:SetPoint("CENTER", UIParent, "CENTER") |
levels[i].value = nil |
end |
end |
|
function Dewdrop:AddSeparator(level) |
level = levels[level or currentLevel] |
if not level or not level.buttons then return; end |
|
local prevbutton = level.buttons[#level.buttons] |
if not prevbutton then return; end |
|
if prevbutton.disabled and prevbutton.text:GetText() == "" then |
return |
end |
self:AddLine("text", "", "disabled", true) |
end |
|
function Dewdrop:AddLine(...) |
local info = tmp(...) |
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 or (self.combat and info.secure) |
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.mouseoverUnderline = info.mouseoverUnderline |
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) |
elseif info.icon then |
button.check:Show() |
button.check:SetTexture(info.icon) |
if info.iconWidth and info.iconHeight then |
button.check:SetWidth(info.iconWidth) |
button.check:SetHeight(info.iconHeight) |
else |
button.check:SetWidth(16) |
button.check:SetHeight(16) |
end |
if info.iconCoordLeft and info.iconCoordRight and info.iconCoordTop and info.iconCoordBottom then |
button.check:SetTexCoord(info.iconCoordLeft, info.iconCoordRight, info.iconCoordTop, info.iconCoordBottom) |
elseif info.icon:find("^Interface\\Icons\\") then |
button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95) |
else |
button.check:SetTexCoord(0, 1, 0, 1) |
end |
button.check:SetVertexColor(1, 1, 1, 1) |
else |
if button.checked then |
if info.checkIcon then |
button.check:SetWidth(16) |
button.check:SetHeight(16) |
button.check:SetTexture(info.checkIcon) |
if info.checkIcon:find("^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 |
button.secure = info.secure |
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:SetVertexColor(button.r, button.g, button.b) |
button.checked = false |
button.func = nil |
button.colorFunc = info.colorFunc |
local i = 1 |
while true do |
local k = "colorArg" .. i |
local x = info[k] |
if x == nil then |
break |
end |
button[k] = x |
i = i + 1 |
end |
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.sliderBigStep = info.sliderBigStep or button.sliderStep |
if button.sliderBigStep < button.sliderStep then |
button.sliderBigStep = button.sliderStep |
end |
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.fromAceOptions = info.fromAceOptions |
local i = 1 |
while true do |
local k = "sliderArg" .. i |
local x = info[k] |
if x == nil then |
break |
end |
button[k] = x |
i = i + 1 |
end |
elseif info.hasEditBox then |
button.hasEditBox = true |
button.editBoxText = info.editBoxText or "" |
button.editBoxFunc = info.editBoxFunc |
local i = 1 |
while true do |
local k = "editBoxArg" .. i |
local x = info[k] |
if x == nil then |
break |
end |
button[k] = x |
i = i + 1 |
end |
button.editBoxChangeFunc = info.editBoxChangeFunc |
local i = 1 |
while true do |
local k = "editBoxChangeArg" .. i |
local x = info[k] |
if x == nil then |
break |
end |
button[k] = x |
i = i + 1 |
end |
button.editBoxValidateFunc = info.editBoxValidateFunc |
local i = 1 |
while true do |
local k = "editBoxValidateArg" .. i |
local x = info[k] |
if x == nil then |
break |
end |
button[k] = x |
i = i + 1 |
end |
button.editBoxIsKeybinding = info.editBoxIsKeybinding |
button.editBoxKeybindingOnly = info.editBoxKeybindingOnly |
button.editBoxKeybindingExcept = info.editBoxKeybindingExcept |
else |
button.value = info.value |
local l = levels[level+1] |
if l and info.value == l.value then |
-- button.arrow:SetWidth(24) |
-- button.arrow:SetHeight(24) |
button.selected = true |
button.highlight:Show() |
end |
end |
else |
button.arrow:SetAlpha(0) |
end |
local i = 1 |
while true do |
local k = "arg" .. i |
local x = info[k] |
if x == nil then |
break |
end |
button[k] = x |
i = i + 1 |
end |
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 |
local i = 1 |
while true do |
local k = "tooltipArg" .. i |
local x = info[k] |
if x == nil then |
break |
end |
button[k] = x |
i = i + 1 |
end |
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 |
if type(button.arg1) ~= "table" then |
self:error("Cannot call method %q on a non-table", button.func) |
end |
if type(button.arg1[button.func]) ~= "function" then |
self:error("Method %q nonexistant.", button.func) |
end |
end |
end |
|
function Dewdrop:InjectAceOptionsTable(handler, options) |
self:argCheck(handler, 2, "table") |
self:argCheck(options, 3, "table") |
if tostring(options.type):lower() ~= "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 |
if Rock then |
-- possible Rock object |
for mixin in Rock:IterateObjectMixins(handler) 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 |
else |
-- Ace2 object |
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 |
end |
return options |
end |
|
function Dewdrop:OnTooltipHide() |
if lastSetFont then |
if lastSetFont == normalFont then |
lastSetFont = nil |
return |
end |
fillRegionTmp(GameTooltip:GetRegions()) |
for i,v in ipairs(regionTmp) do |
if v.GetFont then |
local font,size,outline = v:GetFont() |
if font == lastSetFont then |
v:SetFont(normalFont, size, outline) |
end |
end |
regionTmp[i] = nil |
end |
lastSetFont = nil |
end |
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(this, ...) |
oldX,oldY = GetCursorPosition() |
clickTime = GetTime() |
if WorldFrame_OnMouseDown then |
WorldFrame_OnMouseDown(this, ...) |
end |
end) |
|
WorldFrame:SetScript("OnMouseUp", function(this, ...) |
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(this, ...) |
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(this, ...) |
end |
end) |
|
hooksecurefunc(DropDownList1, "Show", function() |
if levels[1] and levels[1]:IsVisible() then |
self:Close() |
end |
end) |
|
hooksecurefunc("HideDropDownMenu", function() |
if levels[1] and levels[1]:IsVisible() then |
self:Close() |
end |
end) |
|
hooksecurefunc("CloseDropDownMenus", function() |
if levels[1] and levels[1]:IsVisible() then |
local stack = debugstack() |
if not stack:find("`TargetFrame_OnHide'") then |
self:Close() |
end |
end |
end) |
end |
self.frame = oldLib and oldLib.frame or CreateFrame("Frame") |
self.frame:UnregisterAllEvents() |
self.frame:RegisterEvent("PLAYER_REGEN_ENABLED") |
self.frame:RegisterEvent("PLAYER_REGEN_DISABLED") |
self.frame:Hide() |
self.frame:SetScript("OnEvent", function(this, event) |
this:Show() |
if event=="PLAYER_REGEN_ENABLED" then -- track combat state for secure frame operations |
self.combat = false |
elseif event=="PLAYER_REGEN_DISABLED" then |
self.combat = true |
end |
end) |
self.frame:SetScript("OnUpdate", function(this) |
this:Hide() |
self:Refresh(1) |
end) |
self.hookedTooltip = true |
if not oldLib or not oldLib.hookedTooltip then |
local OnTooltipHide = GameTooltip:GetScript("OnHide") |
GameTooltip:SetScript("OnHide", function(this, ...) |
if OnTooltipHide then |
OnTooltipHide(this, ...) |
end |
if type(self.OnTooltipHide) == "function" then |
self:OnTooltipHide() |
end |
end) |
end |
levels = {} |
buttons = {} |
|
if oldDeactivate then |
oldDeactivate(oldLib) |
end |
end |
|
local function external(lib, major, instance) |
if major == "LibSharedMedia-3.0" then |
SharedMedia = instance |
end |
end |
|
AceLibrary:Register(Dewdrop, MAJOR_VERSION, MINOR_VERSION, activate, nil, external) |