comparison libs/Dewdrop-2.0/Dewdrop-2.0.lua @ 1:c11ca1d8ed91

Version 0.1
author Flick <flickerstreak@gmail.com>
date Tue, 20 Mar 2007 21:03:57 +0000
parents
children
comparison
equal deleted inserted replaced
0:4e2ce2894c21 1:c11ca1d8ed91
1 --[[
2 Name: Dewdrop-2.0
3 Revision: $Rev: 19976 $
4 Author(s): ckknight (ckknight@gmail.com)
5 Website: http://ckknight.wowinterface.com/
6 Documentation: http://wiki.wowace.com/index.php/Dewdrop-2.0
7 SVN: http://svn.wowace.com/root/trunk/DewdropLib/Dewdrop-2.0
8 Description: A library to provide a clean dropdown menu interface.
9 Dependencies: AceLibrary
10 ]]
11
12 local MAJOR_VERSION = "Dewdrop-2.0"
13 local MINOR_VERSION = "$Revision: 19976 $"
14
15 if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
16 if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
17
18 local Dewdrop = {}
19
20 local CLOSE = "Close"
21 local CLOSE_DESC = "Close the menu."
22 local VALIDATION_ERROR = "Validation error."
23 local RESET_KEYBINDING_DESC = "Hit escape to clear the keybinding."
24
25 if GetLocale() == "deDE" then
26 -- VALIDATION_ERROR = "some message here..."
27 end
28
29 local function new(...)
30 local t = {}
31 for i = 1, select('#', ...), 2 do
32 local k = select(i, ...)
33 if k then
34 t[k] = select(i+1, ...)
35 else
36 break
37 end
38 end
39 return t
40 end
41
42 local tmp
43 do
44 local t = {}
45 function tmp(...)
46 for k in pairs(t) do
47 t[k] = nil
48 end
49 for i = 1, select('#', ...), 2 do
50 local k = select(i, ...)
51 if k then
52 t[k] = select(i+1, ...)
53 else
54 break
55 end
56 end
57 return t
58 end
59 end
60 local tmp2
61 do
62 local t = {}
63 function tmp2(...)
64 for k in pairs(t) do
65 t[k] = nil
66 end
67 for i = 1, select('#', ...), 2 do
68 local k = select(i, ...)
69 if k then
70 t[k] = select(i+1, ...)
71 else
72 break
73 end
74 end
75 return t
76 end
77 end
78 local levels
79 local buttons
80
81 local function GetScaledCursorPosition()
82 local x, y = GetCursorPosition()
83 local scale = UIParent:GetEffectiveScale()
84 return x / scale, y / scale
85 end
86
87 local function StartCounting(self, levelNum)
88 for i = levelNum, #levels do
89 if levels[i] then
90 levels[i].count = 3
91 end
92 end
93 end
94
95 local function StopCounting(self, level)
96 for i = level, 1, -1 do
97 if levels[i] then
98 levels[i].count = nil
99 end
100 end
101 end
102
103 local function OnUpdate(self, arg1)
104 for _,level in ipairs(levels) do
105 if level.count then
106 level.count = level.count - arg1
107 if level.count < 0 then
108 level.count = nil
109 self:Close(level.num)
110 end
111 end
112 end
113 end
114
115 local function CheckDualMonitor(self, frame)
116 local ratio = GetScreenWidth() / GetScreenHeight()
117 if ratio >= 2.4 and frame:GetRight() > GetScreenWidth() / 2 and frame:GetLeft() < GetScreenWidth() / 2 then
118 local offsetx
119 if GetCursorPosition() / GetScreenHeight() * 768 < GetScreenWidth() / 2 then
120 offsetx = GetScreenWidth() / 2 - frame:GetRight()
121 else
122 offsetx = GetScreenWidth() / 2 - frame:GetLeft()
123 end
124 local point, parent, relativePoint, x, y = frame:GetPoint(1)
125 frame:SetPoint(point, parent, relativePoint, (x or 0) + offsetx, y or 0)
126 end
127 end
128
129 local function CheckSize(self, level)
130 if not level.buttons then
131 return
132 end
133 local height = 20
134 for _, button in ipairs(level.buttons) do
135 height = height + button:GetHeight()
136 end
137 level:SetHeight(height)
138 local width = 160
139 for _, button in ipairs(level.buttons) do
140 local extra = 1
141 if button.hasArrow or button.hasColorSwatch then
142 extra = extra + 16
143 end
144 if not button.notCheckable then
145 extra = extra + 24
146 end
147 button.text:SetFont(STANDARD_TEXT_FONT, button.textHeight)
148 if button.text:GetWidth() + extra > width then
149 width = button.text:GetWidth() + extra
150 end
151 end
152 level:SetWidth(width + 20)
153 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
154 level:ClearAllPoints()
155 if level.lastDirection == "RIGHT" then
156 if level.lastVDirection == "DOWN" then
157 level:SetPoint("TOPLEFT", level.parent or level:GetParent(), "TOPRIGHT", 5, 10)
158 else
159 level:SetPoint("BOTTOMLEFT", level.parent or level:GetParent(), "BOTTOMRIGHT", 5, -10)
160 end
161 else
162 if level.lastVDirection == "DOWN" then
163 level:SetPoint("TOPRIGHT", level.parent or level:GetParent(), "TOPLEFT", -5, 10)
164 else
165 level:SetPoint("BOTTOMRIGHT", level.parent or level:GetParent(), "BOTTOMLEFT", -5, -10)
166 end
167 end
168 end
169 local dirty = false
170 if not level:GetRight() then
171 self:Close()
172 return
173 end
174 if level:GetRight() > GetScreenWidth() and level.lastDirection == "RIGHT" then
175 level.lastDirection = "LEFT"
176 dirty = true
177 elseif level:GetLeft() < 0 and level.lastDirection == "LEFT" then
178 level.lastDirection = "RIGHT"
179 dirty = true
180 end
181 if level:GetTop() > GetScreenHeight() and level.lastVDirection == "UP" then
182 level.lastVDirection = "DOWN"
183 dirty = true
184 elseif level:GetBottom() < 0 and level.lastVDirection == "DOWN" then
185 level.lastVDirection = "UP"
186 dirty = true
187 end
188 if dirty then
189 level:ClearAllPoints()
190 if level.lastDirection == "RIGHT" then
191 if level.lastVDirection == "DOWN" then
192 level:SetPoint("TOPLEFT", level.parent or level:GetParent(), "TOPRIGHT", 5, 10)
193 else
194 level:SetPoint("BOTTOMLEFT", level.parent or level:GetParent(), "BOTTOMRIGHT", 5, -10)
195 end
196 else
197 if level.lastVDirection == "DOWN" then
198 level:SetPoint("TOPRIGHT", level.parent or level:GetParent(), "TOPLEFT", -5, 10)
199 else
200 level:SetPoint("BOTTOMRIGHT", level.parent or level:GetParent(), "BOTTOMLEFT", -5, -10)
201 end
202 end
203 end
204 if level:GetTop() > GetScreenHeight() then
205 local top = level:GetTop()
206 local point, parent, relativePoint, x, y = level:GetPoint(1)
207 level:ClearAllPoints()
208 level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) + GetScreenHeight() - top)
209 elseif level:GetBottom() < 0 then
210 local bottom = level:GetBottom()
211 local point, parent, relativePoint, x, y = level:GetPoint(1)
212 level:ClearAllPoints()
213 level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) - bottom)
214 end
215 CheckDualMonitor(self, level)
216 if mod(level.num, 5) == 0 then
217 local left, bottom = level:GetLeft(), level:GetBottom()
218 level:ClearAllPoints()
219 level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
220 end
221 end
222
223 local Open
224 local OpenSlider
225 local OpenEditBox
226 local Refresh
227 local Clear
228 local function ReleaseButton(self, level, index)
229 if not level.buttons then
230 return
231 end
232 if not level.buttons[index] then
233 return
234 end
235 local button = level.buttons[index]
236 button:Hide()
237 if button.highlight then
238 button.highlight:Hide()
239 end
240 -- button.arrow:SetVertexColor(1, 1, 1)
241 -- button.arrow:SetHeight(16)
242 -- button.arrow:SetWidth(16)
243 table.remove(level.buttons, index)
244 table.insert(buttons, button)
245 for k in pairs(button) do
246 if k ~= 0 and k ~= "text" and k ~= "check" and k ~= "arrow" and k ~= "colorSwatch" and k ~= "highlight" and k ~= "radioHighlight" then
247 button[k] = nil
248 end
249 end
250 return true
251 end
252
253 local function Scroll(self, level, down)
254 if down then
255 if level:GetBottom() < 0 then
256 local point, parent, relativePoint, x, y = level:GetPoint(1)
257 level:SetPoint(point, parent, relativePoint, x, y + 50)
258 if level:GetBottom() > 0 then
259 level:SetPoint(point, parent, relativePoint, x, y + 50 - level:GetBottom())
260 end
261 end
262 else
263 if level:GetTop() > GetScreenHeight() then
264 local point, parent, relativePoint, x, y = level:GetPoint(1)
265 level:SetPoint(point, parent, relativePoint, x, y - 50)
266 if level:GetTop() < GetScreenHeight() then
267 level:SetPoint(point, parent, relativePoint, x, y - 50 + GetScreenHeight() - level:GetTop())
268 end
269 end
270 end
271 end
272
273 local sliderFrame
274 local editBoxFrame
275
276 local function showGameTooltip(this)
277 if this.tooltipTitle or this.tooltipText then
278 GameTooltip_SetDefaultAnchor(GameTooltip, this)
279 local disabled = not this.isTitle and this.disabled
280 if this.tooltipTitle then
281 if disabled then
282 GameTooltip:SetText(this.tooltipTitle, 0.5, 0.5, 0.5, 1)
283 else
284 GameTooltip:SetText(this.tooltipTitle, 1, 1, 1, 1)
285 end
286 if this.tooltipText then
287 if disabled then
288 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)
289 else
290 GameTooltip:AddLine(this.tooltipText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
291 end
292 end
293 else
294 if disabled then
295 GameTooltip:SetText(this.tooltipText, 0.5, 0.5, 0.5, 1)
296 else
297 GameTooltip:SetText(this.tooltipText, 1, 1, 1, 1)
298 end
299 end
300 GameTooltip:Show()
301 end
302 if this.tooltipFunc then
303 GameTooltip:SetOwner(this, "ANCHOR_NONE")
304 GameTooltip:SetPoint("TOPLEFT", this, "TOPRIGHT", 5, 0)
305 this.tooltipFunc(this.tooltipArg1, this.tooltipArg2, this.tooltipArg3, this.tooltipArg4)
306 GameTooltip:Show()
307 end
308 end
309
310 local numButtons = 0
311 local function AcquireButton(self, level)
312 if not levels[level] then
313 return
314 end
315 level = levels[level]
316 if not level.buttons then
317 level.buttons = {}
318 end
319 local button
320 if #buttons == 0 then
321 numButtons = numButtons + 1
322 button = CreateFrame("Button", "Dewdrop20Button" .. numButtons, nil)
323 button:SetFrameStrata("FULLSCREEN_DIALOG")
324 button:SetHeight(16)
325 local highlight = button:CreateTexture(nil, "BACKGROUND")
326 highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
327 button.highlight = highlight
328 highlight:SetBlendMode("ADD")
329 highlight:SetAllPoints(button)
330 highlight:Hide()
331 local check = button:CreateTexture(nil, "ARTWORK")
332 button.check = check
333 check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
334 check:SetPoint("CENTER", button, "LEFT", 12, 0)
335 check:SetWidth(24)
336 check:SetHeight(24)
337 local radioHighlight = button:CreateTexture(nil, "ARTWORK")
338 button.radioHighlight = radioHighlight
339 radioHighlight:SetTexture("Interface\\Buttons\\UI-RadioButton")
340 radioHighlight:SetAllPoints(check)
341 radioHighlight:SetBlendMode("ADD")
342 radioHighlight:SetTexCoord(0.5, 0.75, 0, 1)
343 radioHighlight:Hide()
344 button:SetScript("OnEnter", function()
345 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
346 for i = 1, this.level.num do
347 Refresh(self, levels[i])
348 end
349 return
350 end
351 self:Close(this.level.num + 1)
352 if not this.disabled then
353 if this.hasSlider then
354 OpenSlider(self, this)
355 elseif this.hasEditBox then
356 OpenEditBox(self, this)
357 elseif this.hasArrow then
358 Open(self, this, nil, this.level.num + 1, this.value)
359 end
360 end
361 if not this.level then -- button reclaimed
362 return
363 end
364 StopCounting(self, this.level.num + 1)
365 if not this.disabled then
366 highlight:Show()
367 if this.isRadio then
368 button.radioHighlight:Show()
369 end
370 end
371 showGameTooltip(this)
372 end)
373 button:SetScript("OnLeave", function()
374 if not this.selected then
375 highlight:Hide()
376 end
377 button.radioHighlight:Hide()
378 if this.level then
379 StartCounting(self, this.level.num)
380 end
381 GameTooltip:Hide()
382 end)
383 button:SetScript("OnClick", function()
384 if not this.disabled then
385 if this.hasColorSwatch then
386 local func = button.colorFunc
387 local a1,a2,a3,a4 = button.colorArg1, button.colorArg2, button.colorArg3, button.colorArg4
388 local hasOpacity = this.hasOpacity
389 ColorPickerFrame.func = function()
390 if func then
391 local r,g,b = ColorPickerFrame:GetColorRGB()
392 local a = hasOpacity and 1 - OpacitySliderFrame:GetValue() or nil
393 if a1 == nil then
394 func(r, g, b, a)
395 elseif a2 == nil then
396 func(a1, r, g, b, a)
397 elseif a3 == nil then
398 func(a1, a2, r, g, b, a)
399 elseif a4 == nil then
400 func(a1, a2, a3, r, g, b, a)
401 else
402 func(a1, a2, a3, a4, r, g, b, a)
403 end
404 end
405 end
406 ColorPickerFrame.hasOpacity = this.hasOpacity
407 ColorPickerFrame.opacityFunc = ColorPickerFrame.func
408 ColorPickerFrame.opacity = 1 - this.opacity
409 ColorPickerFrame:SetColorRGB(this.r, this.g, this.b)
410 local r, g, b, a = this.r, this.g, this.b, this.opacity
411 ColorPickerFrame.cancelFunc = function()
412 if a1 == nil then
413 func(r, g, b, a)
414 elseif a2 == nil then
415 func(a1, r, g, b, a)
416 elseif a3 == nil then
417 func(a1, a2, r, g, b, a)
418 else
419 func(a1, a2, a3, r, g, b, a)
420 end
421 end
422 self:Close(1)
423 ShowUIPanel(ColorPickerFrame)
424 elseif this.func then
425 local level = button.level
426 if type(this.func) == "string" then
427 self:assert(type(this.arg1[this.func]) == "function", "Cannot call method " .. this.func)
428 this.arg1[this.func](this.arg1, this.arg2, this.arg3, this.arg4)
429 else
430 this.func(this.arg1, this.arg2, this.arg3, this.arg4)
431 end
432 if this.closeWhenClicked then
433 self:Close()
434 elseif level:IsShown() then
435 for i = 1, level.num do
436 Refresh(self, levels[i])
437 end
438 end
439 elseif this.closeWhenClicked then
440 self:Close()
441 end
442 end
443 end)
444 local text = button:CreateFontString(nil, "ARTWORK")
445 button.text = text
446 text:SetFontObject(GameFontHighlightSmall)
447 button.text:SetFont(STANDARD_TEXT_FONT, UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT)
448 button:SetScript("OnMouseDown", function()
449 if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then
450 text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 1 or 25, -1)
451 end
452 end)
453 button:SetScript("OnMouseUp", function()
454 if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then
455 text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 0 or 24, 0)
456 end
457 end)
458 local arrow = button:CreateTexture(nil, "ARTWORK")
459 button.arrow = arrow
460 arrow:SetPoint("LEFT", button, "RIGHT", -16, 0)
461 arrow:SetWidth(16)
462 arrow:SetHeight(16)
463 arrow:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow")
464 local colorSwatch = button:CreateTexture(nil, "OVERLAY")
465 button.colorSwatch = colorSwatch
466 colorSwatch:SetWidth(20)
467 colorSwatch:SetHeight(20)
468 colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
469 local texture = button:CreateTexture(nil, "OVERLAY")
470 colorSwatch.texture = texture
471 texture:SetTexture(1, 1, 1)
472 texture:SetWidth(11.5)
473 texture:SetHeight(11.5)
474 texture:Show()
475 texture:SetPoint("CENTER", colorSwatch, "CENTER")
476 colorSwatch:SetPoint("RIGHT", button, "RIGHT", 0, 0)
477 else
478 button = table.remove(buttons)
479 end
480 button:ClearAllPoints()
481 button:SetParent(level)
482 button:SetFrameStrata(level:GetFrameStrata())
483 button:SetFrameLevel(level:GetFrameLevel() + 1)
484 button:SetPoint("LEFT", level, "LEFT", 10, 0)
485 button:SetPoint("RIGHT", level, "RIGHT", -10, 0)
486 if #level.buttons == 0 then
487 button:SetPoint("TOP", level, "TOP", 0, -10)
488 else
489 button:SetPoint("TOP", level.buttons[#level.buttons], "BOTTOM", 0, 0)
490 end
491 button.text:SetPoint("LEFT", button, "LEFT", 24, 0)
492 button:Show()
493 button.level = level
494 table.insert(level.buttons, button)
495 if not level.parented then
496 level.parented = true
497 level:ClearAllPoints()
498 if level.num == 1 then
499 if level.parent ~= UIParent then
500 level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT")
501 else
502 level:SetPoint("CENTER", level.parent, "CENTER")
503 end
504 else
505 if level.lastDirection == "RIGHT" then
506 if level.lastVDirection == "DOWN" then
507 level:SetPoint("TOPLEFT", level.parent, "TOPRIGHT", 5, 10)
508 else
509 level:SetPoint("BOTTOMLEFT", level.parent, "BOTTOMRIGHT", 5, -10)
510 end
511 else
512 if level.lastVDirection == "DOWN" then
513 level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT", -5, 10)
514 else
515 level:SetPoint("BOTTOMRIGHT", level.parent, "BOTTOMLEFT", -5, -10)
516 end
517 end
518 end
519 level:SetFrameStrata("FULLSCREEN_DIALOG")
520 end
521 button:SetAlpha(1)
522 return button
523 end
524
525 local numLevels = 0
526 local function AcquireLevel(self, level)
527 if not levels[level] then
528 for i = #levels + 1, level, -1 do
529 local i = i
530 numLevels = numLevels + 1
531 local frame = CreateFrame("Button", "Dewdrop20Level" .. numLevels, nil)
532 if i == 1 then
533 local old_CloseSpecialWindows = CloseSpecialWindows
534 function CloseSpecialWindows()
535 local found = old_CloseSpecialWindows()
536 if levels[1]:IsShown() then
537 self:Close()
538 return 1
539 end
540 return found
541 end
542 end
543 levels[i] = frame
544 frame.num = i
545 frame:SetParent(UIParent)
546 frame:SetFrameStrata("FULLSCREEN_DIALOG")
547 frame:Hide()
548 frame:SetWidth(180)
549 frame:SetHeight(10)
550 frame:SetFrameLevel(i * 3)
551 frame:SetScript("OnHide", function()
552 self:Close(level + 1)
553 end)
554 if frame.SetTopLevel then
555 frame:SetTopLevel(true)
556 end
557 frame:EnableMouse(true)
558 frame:EnableMouseWheel(true)
559 local backdrop = CreateFrame("Frame", nil, frame)
560 backdrop:SetAllPoints(frame)
561 backdrop:SetBackdrop(tmp(
562 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
563 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
564 'tile', true,
565 'insets', tmp2(
566 'left', 5,
567 'right', 5,
568 'top', 5,
569 'bottom', 5
570 ),
571 'tileSize', 16,
572 'edgeSize', 16
573 ))
574 backdrop:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
575 backdrop:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
576 frame:SetScript("OnClick", function()
577 self:Close(i)
578 end)
579 frame:SetScript("OnEnter", function()
580 StopCounting(self, i)
581 end)
582 frame:SetScript("OnLeave", function()
583 StartCounting(self, i)
584 end)
585 frame:SetScript("OnMouseWheel", function()
586 Scroll(self, frame, arg1 < 0)
587 end)
588 if i == 1 then
589 frame:SetScript("OnUpdate", function()
590 OnUpdate(self, arg1)
591 end)
592 levels[1].lastDirection = "RIGHT"
593 levels[1].lastVDirection = "DOWN"
594 else
595 levels[i].lastDirection = levels[i - 1].lastDirection
596 levels[i].lastVDirection = levels[i - 1].lastVDirection
597 end
598 end
599 end
600 local fullscreenFrame = GetFullScreenFrame()
601 local l = levels[level]
602 local strata, framelevel = l:GetFrameStrata(), l:GetFrameLevel()
603 if fullscreenFrame then
604 l:SetParent(fullscreenFrame)
605 else
606 l:SetParent(UIParent)
607 end
608 l:SetFrameStrata(strata)
609 l:SetFrameLevel(framelevel)
610 l:SetAlpha(1)
611 return l
612 end
613
614 local function checkValidate(validateFunc, func, arg1, arg2, arg3)
615 local text
616 if arg3 ~= nil then
617 text = arg3
618 elseif arg2 ~= nil then
619 text = arg2
620 else
621 text = arg1
622 end
623 if not validateFunc(text) then
624 DEFAULT_CHAT_FRAME:AddMessage("|cffffff7fValidation error: [|r" .. tostring(text) .. "|cffffff7f]|r")
625 else
626 func(arg1, arg2, arg3)
627 end
628 end
629
630 local function validateOptions(options, position, baseOptions, fromPass)
631 if not baseOptions then
632 baseOptions = options
633 end
634 if type(options) ~= "table" then
635 return "Options must be a table.", position
636 end
637 local kind = options.type
638 if type(kind) ~= "string" then
639 return '"type" must be a string.', position
640 elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "header" then
641 return '"type" must either be "range", "text", "group", "toggle", "execute", "color", or "header".', position
642 end
643 if options.aliases then
644 if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then
645 return '"alias" must be a table or string', position
646 end
647 end
648 if not fromPass then
649 if kind == "execute" then
650 if type(options.func) ~= "string" and type(options.func) ~= "function" then
651 return '"func" must be a string or function', position
652 end
653 elseif kind == "range" or kind == "text" or kind == "toggle" then
654 if type(options.set) ~= "string" and type(options.set) ~= "function" then
655 return '"set" must be a string or function', position
656 end
657 if kind == "text" and options.get == false then
658 elseif type(options.get) ~= "string" and type(options.get) ~= "function" then
659 return '"get" must be a string or function', position
660 end
661 elseif kind == "group" and options.pass then
662 if options.pass ~= true then
663 return '"pass" must be either nil, true, or false', position
664 end
665 if not options.func then
666 if type(options.set) ~= "string" and type(options.set) ~= "function" then
667 return '"set" must be a string or function', position
668 end
669 if type(options.get) ~= "string" and type(options.get) ~= "function" then
670 return '"get" must be a string or function', position
671 end
672 elseif type(options.func) ~= "string" and type(options.func) ~= "function" then
673 return '"func" must be a string or function', position
674 end
675 end
676 else
677 if kind == "group" then
678 return 'cannot have "type" = "group" as a subgroup of a passing group', position
679 end
680 end
681 if options ~= baseOptions then
682 if kind == "header" then
683 elseif type(options.desc) ~= "string" then
684 return '"desc" must be a string', position
685 elseif options.desc:len() == 0 then
686 return '"desc" cannot be a 0-length string', position
687 end
688 end
689 if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then
690 if options.type == "header" and not options.cmdName and not options.name then
691 elseif options.cmdName then
692 if type(options.cmdName) ~= "string" then
693 return '"cmdName" must be a string or nil', position
694 elseif options.cmdName:len() == 0 then
695 return '"cmdName" cannot be a 0-length string', position
696 end
697 if type(options.guiName) ~= "string" then
698 if not options.guiNameIsMap then
699 return '"guiName" must be a string or nil', position
700 end
701 elseif options.guiName:len() == 0 then
702 return '"guiName" cannot be a 0-length string', position
703 end
704 else
705 if type(options.name) ~= "string" then
706 return '"name" must be a string', position
707 elseif options.name:len() == 0 then
708 return '"name" cannot be a 0-length string', position
709 end
710 end
711 end
712 if options.guiNameIsMap then
713 if type(options.guiNameIsMap) ~= "boolean" then
714 return '"guiNameIsMap" must be a boolean or nil', position
715 elseif options.type ~= "toggle" then
716 return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position
717 elseif type(options.map) ~= "table" then
718 return '"map" must be a table', position
719 end
720 end
721 if options.message and type(options.message) ~= "string" then
722 return '"message" must be a string or nil', position
723 end
724 if options.error and type(options.error) ~= "string" then
725 return '"error" must be a string or nil', position
726 end
727 if options.current and type(options.current) ~= "string" then
728 return '"current" must be a string or nil', position
729 end
730 if options.order then
731 if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then
732 return '"order" must be a non-zero number or nil', position
733 end
734 end
735 if options.disabled then
736 if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then
737 return '"disabled" must be a function, string, or boolean', position
738 end
739 end
740 if options.cmdHidden then
741 if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then
742 return '"cmdHidden" must be a function, string, or boolean', position
743 end
744 end
745 if options.guiHidden then
746 if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then
747 return '"guiHidden" must be a function, string, or boolean', position
748 end
749 end
750 if options.hidden then
751 if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then
752 return '"hidden" must be a function, string, or boolean', position
753 end
754 end
755 if kind == "text" then
756 if type(options.validate) == "table" then
757 local t = options.validate
758 local iTable = nil
759 for k,v in pairs(t) do
760 if type(k) == "number" then
761 if iTable == nil then
762 iTable = true
763 elseif not iTable then
764 return '"validate" must either have all keys be indexed numbers or strings', position
765 elseif k < 1 or k > #t then
766 return '"validate" numeric keys must be indexed properly. >= 1 and <= #t', position
767 end
768 else
769 if iTable == nil then
770 iTable = false
771 elseif iTable then
772 return '"validate" must either have all keys be indexed numbers or strings', position
773 end
774 end
775 if type(v) ~= "string" then
776 return '"validate" values must all be strings', position
777 end
778 end
779 elseif options.validate == "keybinding" then
780 -- no other checks
781 else
782 if type(options.usage) ~= "string" then
783 return '"usage" must be a string', position
784 elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then
785 return '"validate" must be a string, function, or table', position
786 end
787 end
788 elseif kind == "range" then
789 if options.min or options.max then
790 if type(options.min) ~= "number" then
791 return '"min" must be a number', position
792 elseif type(options.max) ~= "number" then
793 return '"max" must be a number', position
794 elseif options.min >= options.max then
795 return '"min" must be less than "max"', position
796 end
797 end
798 if options.step then
799 if type(options.step) ~= "number" then
800 return '"step" must be a number', position
801 elseif options.step < 0 then
802 return '"step" must be nonnegative', position
803 end
804 end
805 if options.isPercent and options.isPercent ~= true then
806 return '"isPercent" must either be nil, true, or false', position
807 end
808 elseif kind == "toggle" then
809 if options.map then
810 if type(options.map) ~= "table" then
811 return '"map" must be a table', position
812 elseif type(options.map[true]) ~= "string" then
813 return '"map[true]" must be a string', position
814 elseif type(options.map[false]) ~= "string" then
815 return '"map[false]" must be a string', position
816 end
817 end
818 elseif kind == "color" then
819 if options.hasAlpha and options.hasAlpha ~= true then
820 return '"hasAlpha" must be nil, true, or false', position
821 end
822 elseif kind == "group" then
823 if options.pass and options.pass ~= true then
824 return '"pass" must be nil, true, or false', position
825 end
826 if type(options.args) ~= "table" then
827 return '"args" must be a table', position
828 end
829 for k,v in pairs(options.args) do
830 if type(k) ~= "string" then
831 return '"args" keys must be strings', position
832 elseif k:find("%s") then
833 return string.format('"args" keys must not include spaces. %q is not appropriate.', k), position
834 elseif k:len() == 0 then
835 return '"args" keys must not be 0-length strings.', position
836 end
837 if type(v) ~= "table" then
838 return '"args" values must be tables', position and position .. "." .. k or k
839 end
840 local newposition
841 if position then
842 newposition = position .. ".args." .. k
843 else
844 newposition = "args." .. k
845 end
846 local err, pos = validateOptions(v, newposition, baseOptions, options.pass)
847 if err then
848 return err, pos
849 end
850 end
851 end
852 if options.icon and type(options.icon) ~= "string" then
853 return'"icon" must be a string', position
854 end
855 if options.iconWidth or options.iconHeight then
856 if type(options.iconWidth) ~= "number" or type(options.iconHeight) ~= "number" then
857 return '"iconHeight" and "iconWidth" must be numbers', position
858 end
859 end
860 if options.iconCoordLeft or options.iconCoordRight or options.iconCoordTop or options.iconCoordBottom then
861 if type(options.iconCoordLeft) ~= "number" or type(options.iconCoordRight) ~= "number" or type(options.iconCoordTop) ~= "number" or type(options.iconCoordBottom) ~= "number" then
862 return '"iconCoordLeft", "iconCoordRight", "iconCoordTop", and "iconCoordBottom" must be numbers', position
863 end
864 end
865 end
866
867 local validatedOptions
868
869 local values
870 local mysort_args
871 local mysort
872 local othersort
873 local othersort_validate
874
875 local baseFunc, currentLevel
876
877 function Dewdrop:FeedAceOptionsTable(options, difference)
878 self:argCheck(options, 2, "table")
879 self:argCheck(difference, 3, "nil", "number")
880 self:assert(currentLevel, "Cannot call `FeedAceOptionsTable' outside of a Dewdrop declaration")
881 if not difference then
882 difference = 0
883 end
884 if not validatedOptions then
885 validatedOptions = {}
886 end
887 if not validatedOptions[options] then
888 local err, position = validateOptions(options)
889
890 if err then
891 if position then
892 Dewdrop:error(position .. ": " .. err)
893 else
894 Dewdrop:error(err)
895 end
896 end
897
898 validatedOptions[options] = true
899 end
900 local level = levels[currentLevel]
901 self:assert(level, "Improper level given")
902 if not values then
903 values = {}
904 else
905 for k,v in pairs(values) do
906 values[k] = nil
907 end
908 end
909
910 local current = level
911 while current do
912 if current.num == difference + 1 then
913 break
914 end
915 table.insert(values, current.value)
916 current = levels[current.num - 1]
917 end
918
919 local realOptions = options
920 local handler = options.handler
921 local passTable
922 local passValue
923 while #values > 0 do
924 passTable = options.pass and current or nil
925 local value = table.remove(values)
926 options = options.args and options.args[value]
927 if not options then
928 return
929 end
930 handler = options.handler or handler
931 passValue = passTable and value or nil
932 end
933
934 if options.type == "group" then
935 for k in pairs(options.args) do
936 table.insert(values, k)
937 end
938 if not mysort then
939 mysort = function(a, b)
940 local alpha, bravo = mysort_args[a], mysort_args[b]
941 local alpha_order = alpha.order or 100
942 local bravo_order = bravo.order or 100
943 local alpha_name = alpha.guiName or alpha.name
944 local bravo_name = bravo.guiName or bravo.name
945 if alpha_order == bravo_order then
946 if not alpha_name then
947 return true
948 elseif not bravo_name then
949 return false
950 else
951 return alpha_name:upper() < bravo_name:upper()
952 end
953 else
954 if alpha_order < 0 then
955 if bravo_order > 0 then
956 return false
957 end
958 else
959 if bravo_order < 0 then
960 return true
961 end
962 end
963 return alpha_order < bravo_order
964 end
965 end
966 end
967 mysort_args = options.args
968 table.sort(values, mysort)
969 mysort_args = nil
970 local hasBoth = #values >= 1 and (options.args[values[1]].order or 100) > 0 and (options.args[values[#values]].order or 100) < 0
971 local last_order = 1
972 for _,k in ipairs(values) do
973 local v = options.args[k]
974 local handler = v.handler or handler
975 if hasBoth and last_order > 0 and (v.order or 100) < 0 then
976 hasBoth = false
977 self:AddLine()
978 end
979 local hidden, disabled = v.guiHidden or v.hidden, v.disabled
980 if type(hidden) == "function" then
981 hidden = hidden()
982 elseif type(hidden) == "string" then
983 local f = hidden
984 local neg = f:match("^~(.-)$")
985 if neg then
986 f = neg
987 end
988 hidden = handler[f](handler)
989 if neg then
990 hidden = not hidden
991 end
992 end
993 if not hidden then
994 if type(disabled) == "function" then
995 disabled = disabled()
996 elseif type(disabled) == "string" then
997 local f = disabled
998 local neg = f:match("^~(.-)$")
999 if neg then
1000 f = neg
1001 end
1002 disabled = handler[f](handler)
1003 if neg then
1004 disabled = not disabled
1005 end
1006 end
1007 local name = (v.guiIconOnly and v.icon) and "" or (v.guiName or v.name)
1008 local desc = v.desc
1009 local iconHeight = v.iconHeight or 16
1010 local iconWidth = v.iconWidth or 16
1011 local iconCoordLeft = v.iconCoordLeft
1012 local iconCoordRight = v.iconCoordRight
1013 local iconCoordBottom = v.iconCoordBottom
1014 local iconCoordTop = v.iconCoordTop
1015 local tooltipTitle, tooltipText
1016 tooltipTitle = name
1017 if name ~= desc then
1018 tooltipText = desc
1019 end
1020 if v.type == "toggle" then
1021 local checked
1022 local checked_arg
1023 if type(v.get) == "function" then
1024 checked = v.get(passValue)
1025 checked_arg = checked
1026 else
1027 local f = v.get
1028 local neg = f:match("^~(.-)$")
1029 if neg then
1030 f = neg
1031 end
1032 if not handler[f] then
1033 Dewdrop:error("Handler %q not available", f)
1034 end
1035 checked = handler[f](handler, passValue)
1036 checked_arg = checked
1037 if neg then
1038 checked = not checked
1039 end
1040 end
1041 local func, arg1, arg2, arg3
1042 if type(v.set) == "function" then
1043 func = v.set
1044 if passValue ~= nil then
1045 arg1 = passValue
1046 arg2 = not checked_arg
1047 else
1048 arg1 = not checked_arg
1049 end
1050 else
1051 if not handler[v.set] then
1052 Dewdrop:error("Handler %q not available", v.set)
1053 end
1054 func = handler[v.set]
1055 arg1 = handler
1056 if passValue ~= nil then
1057 arg2 = passValue
1058 arg3 = not checked_arg
1059 else
1060 arg2 = not checked_arg
1061 end
1062 end
1063 if v.guiNameIsMap then
1064 checked = checked and true or false
1065 name = tostring(v.map and v.map[checked]):gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1")
1066 checked = nil
1067 end
1068 self:AddLine(
1069 'text', name,
1070 'checked', checked,
1071 'isRadio', v.isRadio,
1072 'func', func,
1073 'arg1', arg1,
1074 'arg2', arg2,
1075 'arg3', arg3,
1076 'disabled', disabled,
1077 'tooltipTitle', tooltipTitle,
1078 'tooltipText', tooltipText
1079 )
1080 elseif v.type == "execute" then
1081 local func, arg1, arg2
1082 if type(v.func) == "function" then
1083 func = v.func
1084 arg1 = passValue
1085 else
1086 if not handler[v.func] then
1087 Dewdrop:error("Handler %q not available", v.func)
1088 end
1089 func = handler[v.func]
1090 arg1 = handler
1091 arg2 = passValue
1092 end
1093 self:AddLine(
1094 'text', name,
1095 'checked', checked,
1096 'func', func,
1097 'arg1', arg1,
1098 'arg2', arg2,
1099 'disabled', disabled,
1100 'tooltipTitle', tooltipTitle,
1101 'tooltipText', tooltipText,
1102 'icon', v.icon,
1103 'iconHeight', iconHeight,
1104 'iconWidth', iconWidth,
1105 'iconCoordLeft', iconCoordLeft,
1106 'iconCoordRight', iconCoordRight,
1107 'iconCoordTop', iconCoordTop,
1108 'iconCoordBottom', iconCoordBottom
1109 )
1110 elseif v.type == "range" then
1111 local sliderValue
1112 if type(v.get) == "function" then
1113 sliderValue = v.get(passValue)
1114 else
1115 if not handler[v.get] then
1116 Dewdrop:error("Handler %q not available", v.get)
1117 end
1118 sliderValue = handler[v.get](handler, passValue)
1119 end
1120 local sliderFunc, sliderArg1, sliderArg2
1121 if type(v.set) == "function" then
1122 sliderFunc = v.set
1123 sliderArg1 = passValue
1124 else
1125 if not handler[v.set] then
1126 Dewdrop:error("Handler %q not available", v.set)
1127 end
1128 sliderFunc = handler[v.set]
1129 sliderArg1 = handler
1130 sliderArg2 = passValue
1131 end
1132 self:AddLine(
1133 'text', name,
1134 'hasArrow', true,
1135 'hasSlider', true,
1136 'sliderMin', v.min or 0,
1137 'sliderMax', v.max or 1,
1138 'sliderStep', v.step or 0,
1139 'sliderIsPercent', v.isPercent or false,
1140 'sliderValue', sliderValue,
1141 'sliderFunc', sliderFunc,
1142 'sliderArg1', sliderArg1,
1143 'sliderArg2', sliderArg2,
1144 'disabled', disabled,
1145 'tooltipTitle', tooltipTitle,
1146 'tooltipText', tooltipText,
1147 'icon', v.icon,
1148 'iconHeight', iconHeight,
1149 'iconWidth', iconWidth,
1150 'iconCoordLeft', iconCoordLeft,
1151 'iconCoordRight', iconCoordRight,
1152 'iconCoordTop', iconCoordTop,
1153 'iconCoordBottom', iconCoordBottom
1154 )
1155 elseif v.type == "color" then
1156 local r,g,b,a
1157 if type(v.get) == "function" then
1158 r,g,b,a = v.get(passValue)
1159 else
1160 if not handler[v.get] then
1161 Dewdrop:error("Handler %q not available", v.get)
1162 end
1163 r,g,b,a = handler[v.get](handler, passValue)
1164 end
1165 local colorFunc, colorArg1, colorArg2
1166 if type(v.set) == "function" then
1167 colorFunc = v.set
1168 colorArg1 = passValue
1169 else
1170 if not handler[v.set] then
1171 Dewdrop:error("Handler %q not available", v.set)
1172 end
1173 colorFunc = handler[v.set]
1174 colorArg1 = handler
1175 colorArg2 = passValue
1176 end
1177 self:AddLine(
1178 'text', name,
1179 'hasArrow', true,
1180 'hasColorSwatch', true,
1181 'r', r,
1182 'g', g,
1183 'b', b,
1184 'opacity', v.hasAlpha and a or nil,
1185 'hasOpacity', v.hasAlpha,
1186 'colorFunc', colorFunc,
1187 'colorArg1', colorArg1,
1188 'colorArg2', colorArg2,
1189 'disabled', disabled,
1190 'tooltipTitle', tooltipTitle,
1191 'tooltipText', tooltipText
1192 )
1193 elseif v.type == "text" then
1194 if type(v.validate) == "table" then
1195 self:AddLine(
1196 'text', name,
1197 'hasArrow', true,
1198 'value', k,
1199 'disabled', disabled,
1200 'tooltipTitle', tooltipTitle,
1201 'tooltipText', tooltipText,
1202 'icon', v.icon,
1203 'iconHeight', iconHeight,
1204 'iconWidth', iconWidth,
1205 'iconCoordLeft', iconCoordLeft,
1206 'iconCoordRight', iconCoordRight,
1207 'iconCoordTop', iconCoordTop,
1208 'iconCoordBottom', iconCoordBottom
1209 )
1210 else
1211 local editBoxText
1212 if type(v.get) == "function" then
1213 editBoxText = v.get(passValue)
1214 elseif v.get == false then
1215 editBoxText = nil
1216 else
1217 if not handler[v.get] then
1218 Dewdrop:error("Handler %q not available", v.get)
1219 end
1220 editBoxText = handler[v.get](handler, passValue)
1221 end
1222 local editBoxFunc, editBoxArg1, editBoxArg2
1223 if type(v.set) == "function" then
1224 editBoxFunc = v.set
1225 editBoxArg1 = passValue
1226 else
1227 if not handler[v.set] then
1228 Dewdrop:error("Handler %q not available", v.set)
1229 end
1230 editBoxFunc = handler[v.set]
1231 editBoxArg1 = handler
1232 editBoxArg2 = passValue
1233 end
1234
1235 local editBoxValidateFunc, editBoxValidateArg1
1236
1237 if v.validate and v.validate ~= "keybinding" then
1238 if type(v.validate) == "function" then
1239 editBoxValidateFunc = v.validate
1240 else
1241 if not handler[v.validate] then
1242 Dewdrop:error("Handler %q not available", v.validate)
1243 end
1244 editBoxValidateFunc = handler[v.validate]
1245 editBoxValidateArg1 = handler
1246 end
1247 elseif v.validate then
1248 if tooltipText then
1249 tooltipText = tooltipText .. "\n\n" .. RESET_KEYBINDING_DESC
1250 else
1251 tooltipText = RESET_KEYBINDING_DESC
1252 end
1253 end
1254
1255 self:AddLine(
1256 'text', name,
1257 'hasArrow', true,
1258 'icon', v.icon,
1259 'iconHeight', iconHeight,
1260 'iconWidth', iconWidth,
1261 'iconCoordLeft', iconCoordLeft,
1262 'iconCoordRight', iconCoordRight,
1263 'iconCoordTop', iconCoordTop,
1264 'iconCoordBottom', iconCoordBottom,
1265 'hasEditBox', true,
1266 'editBoxText', editBoxText,
1267 'editBoxFunc', editBoxFunc,
1268 'editBoxArg1', editBoxArg1,
1269 'editBoxArg2', editBoxArg2,
1270 'editBoxValidateFunc', editBoxValidateFunc,
1271 'editBoxValidateArg1', editBoxValidateArg1,
1272 'editBoxIsKeybinding', v.validate == "keybinding",
1273 'disabled', disabled,
1274 'tooltipTitle', tooltipTitle,
1275 'tooltipText', tooltipText
1276 )
1277 end
1278 elseif v.type == "group" then
1279 self:AddLine(
1280 'text', name,
1281 'hasArrow', true,
1282 'value', k,
1283 'disabled', disabled,
1284 'tooltipTitle', tooltipTitle,
1285 'tooltipText', tooltipText,
1286 'icon', v.icon,
1287 'iconHeight', iconHeight,
1288 'iconWidth', iconWidth,
1289 'iconCoordLeft', iconCoordLeft,
1290 'iconCoordRight', iconCoordRight,
1291 'iconCoordTop', iconCoordTop,
1292 'iconCoordBottom', iconCoordBottom
1293 )
1294 elseif v.type == "header" then
1295 if name == "" or not name then
1296 self:AddLine(
1297 'isTitle', true,
1298 'icon', v.icon,
1299 'iconHeight', iconHeight,
1300 'iconWidth', iconWidth,
1301 'iconCoordLeft', iconCoordLeft,
1302 'iconCoordRight', iconCoordRight,
1303 'iconCoordTop', iconCoordTop,
1304 'iconCoordBottom', iconCoordBottom
1305 )
1306 else
1307 self:AddLine(
1308 'text', name,
1309 'isTitle', true,
1310 'icon', v.icon,
1311 'iconHeight', iconHeight,
1312 'iconWidth', iconWidth,
1313 'iconCoordLeft', iconCoordLeft,
1314 'iconCoordRight', iconCoordRight,
1315 'iconCoordTop', iconCoordTop,
1316 'iconCoordBottom', iconCoordBottom
1317 )
1318 end
1319 end
1320 end
1321 last_order = v.order or 100
1322 end
1323 elseif options.type == "text" and type(options.validate) == "table" then
1324 local current
1325 if type(options.get) == "function" then
1326 current = options.get(passValue)
1327 elseif options.get ~= false then
1328 if not handler[options.get] then
1329 Dewdrop:error("Handler %q not available", options.get)
1330 end
1331 current = handler[options.get](handler, passValue)
1332 end
1333 local indexed = true
1334 for k,v in pairs(options.validate) do
1335 if type(k) ~= "number" then
1336 indexed = false
1337 end
1338 table.insert(values, k)
1339 end
1340 if not indexed then
1341 if not othersort then
1342 othersort = function(alpha, bravo)
1343 return othersort_validate[alpha] < othersort_validate[bravo]
1344 end
1345 end
1346 othersort_validate = options.validate
1347 table.sort(values, othersort)
1348 othersort_validate = nil
1349 end
1350 for _,k in ipairs(values) do
1351 local v = options.validate[k]
1352 if type(k) == "number" then
1353 k = v
1354 end
1355 local func, arg1, arg2
1356 if type(options.set) == "function" then
1357 func = options.set
1358 if passValue ~= nil then
1359 arg1 = passValue
1360 arg2 = k
1361 else
1362 arg1 = k
1363 end
1364 else
1365 if not handler[options.set] then
1366 Dewdrop:error("Handler %q not available", options.set)
1367 end
1368 func = handler[options.set]
1369 arg1 = handler
1370 if passValue ~= nil then
1371 arg2 = passValue
1372 arg3 = k
1373 else
1374 arg2 = k
1375 end
1376 end
1377 local checked = (k == current or (type(k) == "string" and type(current) == "string" and k:lower() == current:lower()))
1378 self:AddLine(
1379 'text', v,
1380 'func', not checked and func or nil,
1381 'arg1', not checked and arg1 or nil,
1382 'arg2', not checked and arg2 or nil,
1383 'arg3', not checked and arg3 or nil,
1384 'isRadio', true,
1385 'checked', checked,
1386 'tooltipTitle', options.guiName or options.name,
1387 'tooltipText', v
1388 )
1389 end
1390 for k in pairs(values) do
1391 values[k] = nil
1392 end
1393 else
1394 return false
1395 end
1396 return true
1397 end
1398
1399 function Refresh(self, level)
1400 if type(level) == "number" then
1401 level = levels[level]
1402 end
1403 if not level then
1404 return
1405 end
1406 if baseFunc then
1407 Clear(self, level)
1408 currentLevel = level.num
1409 if type(baseFunc) == "table" then
1410 if currentLevel == 1 then
1411 local handler = baseFunc.handler
1412 if handler then
1413 local name = tostring(handler)
1414 if not name:find('^table:') then
1415 name = name:gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1")
1416 self:AddLine(
1417 'text', name,
1418 'isTitle', true
1419 )
1420 end
1421 end
1422 -- elseif level.parentText then
1423 -- self:AddLine(
1424 -- 'text', level.parentText,
1425 -- 'tooltipTitle', level.parentTooltipTitle,
1426 -- 'tooltipText', level.parentTooltipText,
1427 -- 'tooltipFunc', level.parentTooltipFunc,
1428 -- 'isTitle', true
1429 -- )
1430 end
1431 self:FeedAceOptionsTable(baseFunc)
1432 if currentLevel == 1 then
1433 self:AddLine(
1434 'text', CLOSE,
1435 'tooltipTitle', CLOSE,
1436 'tooltipText', CLOSE_DESC,
1437 'closeWhenClicked', true
1438 )
1439 end
1440 else
1441 -- if level.parentText then
1442 -- self:AddLine(
1443 -- 'text', level.parentText,
1444 -- 'tooltipTitle', level.parentTooltipTitle,
1445 -- 'tooltipText', level.parentTooltipText,
1446 -- 'tooltipFunc', level.parentTooltipFunc,
1447 -- 'isTitle', true
1448 -- )
1449 -- end
1450 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)
1451 end
1452 currentLevel = nil
1453 CheckSize(self, level)
1454 end
1455 end
1456
1457 function Dewdrop:Refresh(level)
1458 self:argCheck(level, 2, "number")
1459 Refresh(self, levels[level])
1460 end
1461
1462 function OpenSlider(self, parent)
1463 if not sliderFrame then
1464 sliderFrame = CreateFrame("Frame", nil, nil)
1465 sliderFrame:SetWidth(80)
1466 sliderFrame:SetHeight(170)
1467 sliderFrame:SetScale(UIParent:GetScale())
1468 sliderFrame:SetBackdrop(tmp(
1469 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
1470 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
1471 'tile', true,
1472 'insets', tmp2(
1473 'left', 5,
1474 'right', 5,
1475 'top', 5,
1476 'bottom', 5
1477 ),
1478 'tileSize', 16,
1479 'edgeSize', 16
1480 ))
1481 sliderFrame:SetFrameStrata("FULLSCREEN_DIALOG")
1482 if sliderFrame.SetTopLevel then
1483 sliderFrame:SetTopLevel(true)
1484 end
1485 sliderFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
1486 sliderFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
1487 sliderFrame:EnableMouse(true)
1488 sliderFrame:Hide()
1489 sliderFrame:SetPoint("CENTER", UIParent, "CENTER")
1490 local slider = CreateFrame("Slider", nil, sliderFrame)
1491 sliderFrame.slider = slider
1492 slider:SetOrientation("VERTICAL")
1493 slider:SetMinMaxValues(0, 1)
1494 slider:SetValueStep(0.01)
1495 slider:SetValue(0.5)
1496 slider:SetWidth(16)
1497 slider:SetHeight(128)
1498 slider:SetPoint("LEFT", sliderFrame, "LEFT", 15, 0)
1499 slider:SetBackdrop(tmp(
1500 'bgFile', "Interface\\Buttons\\UI-SliderBar-Background",
1501 'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border",
1502 'tile', true,
1503 'edgeSize', 8,
1504 'tileSize', 8,
1505 'insets', tmp2(
1506 'left', 3,
1507 'right', 3,
1508 'top', 3,
1509 'bottom', 3
1510 )
1511 ))
1512 local texture = slider:CreateTexture()
1513 slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
1514 local text = slider:CreateFontString(nil, "ARTWORK")
1515 sliderFrame.topText = text
1516 text:SetFontObject(GameFontGreenSmall)
1517 text:SetText("100%")
1518 text:SetPoint("BOTTOM", slider, "TOP")
1519 local text = slider:CreateFontString(nil, "ARTWORK")
1520 sliderFrame.bottomText = text
1521 text:SetFontObject(GameFontGreenSmall)
1522 text:SetText("0%")
1523 text:SetPoint("TOP", slider, "BOTTOM")
1524 local text = slider:CreateFontString(nil, "ARTWORK")
1525 sliderFrame.currentText = text
1526 text:SetFontObject(GameFontHighlightSmall)
1527 text:SetText("50%")
1528 text:SetPoint("LEFT", slider, "RIGHT")
1529 text:SetPoint("RIGHT", sliderFrame, "RIGHT", -6, 0)
1530 text:SetJustifyH("CENTER")
1531 local changed = false
1532 local inside = false
1533 slider:SetScript("OnValueChanged", function()
1534 if sliderFrame.changing then
1535 return
1536 end
1537 changed = true
1538 local done = false
1539 if sliderFrame.parent and sliderFrame.parent.sliderFunc then
1540 local min = sliderFrame.parent.sliderMin or 0
1541 local max = sliderFrame.parent.sliderMax or 1
1542 local step = sliderFrame.parent.sliderStep or (max - min) / 100
1543 local a1,a2,a3,a4 = sliderFrame.parent.sliderArg1, sliderFrame.parent.sliderArg2, sliderFrame.parent.sliderArg3, sliderFrame.parent.sliderArg4
1544 local value = (1 - slider:GetValue()) * (max - min) + min
1545 if step > 0 then
1546 value = math.floor((value - min) / step + 0.5) * step + min
1547 if value > max then
1548 value = max
1549 elseif value < min then
1550 value = min
1551 end
1552 end
1553 if value == sliderFrame.lastValue then
1554 return
1555 end
1556 sliderFrame.lastValue = value
1557 local text
1558 if a1 == nil then
1559 text = sliderFrame.parent.sliderFunc(value)
1560 elseif a2 == nil then
1561 text = sliderFrame.parent.sliderFunc(a1, value)
1562 elseif a3 == nil then
1563 text = sliderFrame.parent.sliderFunc(a1, a2, value)
1564 elseif a4 == nil then
1565 text = sliderFrame.parent.sliderFunc(a1, a2, a3, value)
1566 else
1567 text = sliderFrame.parent.sliderFunc(a1, a2, a3, a4, value)
1568 end
1569 if text then
1570 sliderFrame.currentText:SetText(text)
1571 done = true
1572 end
1573 end
1574 if not done then
1575 local min = sliderFrame.parent.sliderMin or 0
1576 local max = sliderFrame.parent.sliderMax or 1
1577 local step = sliderFrame.parent.sliderStep or (max - min) / 100
1578 local value = (1 - slider:GetValue()) * (max - min) + min
1579 if step > 0 then
1580 value = math.floor((value - min) / step + 0.5) * step + min
1581 if value > max then
1582 value = max
1583 elseif value < min then
1584 value = min
1585 end
1586 end
1587 if sliderFrame.parent.sliderIsPercent then
1588 sliderFrame.currentText:SetText(string.format("%.0f%%", value * 100))
1589 else
1590 if step < 0.1 then
1591 sliderFrame.currentText:SetText(string.format("%.2f", value))
1592 elseif step < 1 then
1593 sliderFrame.currentText:SetText(string.format("%.1f", value))
1594 else
1595 sliderFrame.currentText:SetText(string.format("%.0f", value))
1596 end
1597 end
1598 end
1599 end)
1600 sliderFrame:SetScript("OnEnter", function()
1601 StopCounting(self, sliderFrame.level)
1602 showGameTooltip(sliderFrame.parent)
1603 end)
1604 sliderFrame:SetScript("OnLeave", function()
1605 StartCounting(self, sliderFrame.level)
1606 GameTooltip:Hide()
1607 end)
1608 slider:SetScript("OnMouseDown", function()
1609 sliderFrame.mouseDown = true
1610 GameTooltip:Hide()
1611 end)
1612 slider:SetScript("OnMouseUp", function()
1613 sliderFrame.mouseDown = false
1614 if changed--[[ and not inside]] then
1615 local parent = sliderFrame.parent
1616 local sliderFunc = parent.sliderFunc
1617 for i = 1, sliderFrame.level - 1 do
1618 Refresh(self, levels[i])
1619 end
1620 local newParent
1621 for _,button in ipairs(levels[sliderFrame.level-1].buttons) do
1622 if button.sliderFunc == sliderFunc then
1623 newParent = button
1624 break
1625 end
1626 end
1627 if newParent then
1628 OpenSlider(self, newParent)
1629 else
1630 sliderFrame:Hide()
1631 end
1632 end
1633 if inside then
1634 showGameTooltip(sliderFrame.parent)
1635 end
1636 end)
1637 slider:SetScript("OnEnter", function()
1638 inside = true
1639 StopCounting(self, sliderFrame.level)
1640 showGameTooltip(sliderFrame.parent)
1641 end)
1642 slider:SetScript("OnLeave", function()
1643 inside = false
1644 StartCounting(self, sliderFrame.level)
1645 GameTooltip:Hide()
1646 if changed and not sliderFrame.mouseDown then
1647 local parent = sliderFrame.parent
1648 local sliderFunc = parent.sliderFunc
1649 for i = 1, sliderFrame.level - 1 do
1650 Refresh(self, levels[i])
1651 end
1652 local newParent
1653 for _,button in ipairs(levels[sliderFrame.level-1].buttons) do
1654 if button.sliderFunc == sliderFunc then
1655 newParent = button
1656 break
1657 end
1658 end
1659 if newParent then
1660 OpenSlider(self, newParent)
1661 else
1662 sliderFrame:Hide()
1663 end
1664 end
1665 end)
1666 end
1667 sliderFrame.parent = parent
1668 sliderFrame.level = parent.level.num + 1
1669 sliderFrame.parentValue = parent.level.value
1670 sliderFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3)
1671 sliderFrame.slider:SetFrameLevel(sliderFrame:GetFrameLevel() + 1)
1672 sliderFrame.changing = true
1673 if not parent.sliderMin or not parent.sliderMax then
1674 return
1675 end
1676
1677 if parent.arrow then
1678 -- parent.arrow:SetVertexColor(0.2, 0.6, 0)
1679 -- parent.arrow:SetHeight(24)
1680 -- parent.arrow:SetWidth(24)
1681 parent.selected = true
1682 parent.highlight:Show()
1683 end
1684
1685 sliderFrame:SetClampedToScreen(false)
1686 if not parent.sliderValue then
1687 parent.sliderValue = (parent.sliderMin + parent.sliderMax) / 2
1688 end
1689 sliderFrame.slider:SetValue(1 - (parent.sliderValue - parent.sliderMin) / (parent.sliderMax - parent.sliderMin))
1690 sliderFrame.changing = false
1691 sliderFrame.bottomText:SetText(parent.sliderMinText or "0")
1692 sliderFrame.topText:SetText(parent.sliderMaxText or "1")
1693 local text
1694 if parent.sliderFunc then
1695 local a1,a2,a3,a4 = parent.sliderArg1, parent.sliderArg2, parent.sliderArg3, parent.sliderArg4
1696 if a1 == nil then
1697 text = parent.sliderFunc(parent.sliderValue)
1698 elseif a2 == nil then
1699 text = parent.sliderFunc(a1, parent.sliderValue)
1700 elseif a3 == nil then
1701 text = parent.sliderFunc(a1, a2, parent.sliderValue)
1702 elseif a4 == nil then
1703 text = parent.sliderFunc(a1, a2, a3, parent.sliderValue)
1704 else
1705 text = parent.sliderFunc(a1, a2, a3, a4, parent.sliderValue)
1706 end
1707 end
1708 if text then
1709 sliderFrame.currentText:SetText(text)
1710 elseif parent.sliderIsPercent then
1711 sliderFrame.currentText:SetText(string.format("%.0f%%", parent.sliderValue * 100))
1712 else
1713 sliderFrame.currentText:SetText(parent.sliderValue)
1714 end
1715
1716 sliderFrame.lastValue = parent.sliderValue
1717
1718 local level = parent.level
1719 sliderFrame:Show()
1720 sliderFrame:ClearAllPoints()
1721 if level.lastDirection == "RIGHT" then
1722 if level.lastVDirection == "DOWN" then
1723 sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
1724 else
1725 sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
1726 end
1727 else
1728 if level.lastVDirection == "DOWN" then
1729 sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
1730 else
1731 sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
1732 end
1733 end
1734 local dirty
1735 if level.lastDirection == "RIGHT" then
1736 if sliderFrame:GetRight() > GetScreenWidth() then
1737 level.lastDirection = "LEFT"
1738 dirty = true
1739 end
1740 elseif sliderFrame:GetLeft() < 0 then
1741 level.lastDirection = "RIGHT"
1742 dirty = true
1743 end
1744 if level.lastVDirection == "DOWN" then
1745 if sliderFrame:GetBottom() < 0 then
1746 level.lastVDirection = "UP"
1747 dirty = true
1748 end
1749 elseif sliderFrame:GetTop() > GetScreenWidth() then
1750 level.lastVDirection = "DOWN"
1751 dirty = true
1752 end
1753 if dirty then
1754 sliderFrame:ClearAllPoints()
1755 if level.lastDirection == "RIGHT" then
1756 if level.lastVDirection == "DOWN" then
1757 sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
1758 else
1759 sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
1760 end
1761 else
1762 if level.lastVDirection == "DOWN" then
1763 sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
1764 else
1765 sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
1766 end
1767 end
1768 end
1769 local left, bottom = sliderFrame:GetLeft(), sliderFrame:GetBottom()
1770 sliderFrame:ClearAllPoints()
1771 sliderFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
1772 if mod(level.num, 5) == 0 then
1773 local left, bottom = level:GetLeft(), level:GetBottom()
1774 level:ClearAllPoints()
1775 level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
1776 end
1777 sliderFrame:SetClampedToScreen(true)
1778 end
1779
1780 function OpenEditBox(self, parent)
1781 if not editBoxFrame then
1782 editBoxFrame = CreateFrame("Frame", nil, nil)
1783 editBoxFrame:SetWidth(200)
1784 editBoxFrame:SetHeight(40)
1785 editBoxFrame:SetScale(UIParent:GetScale())
1786 editBoxFrame:SetBackdrop(tmp(
1787 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background",
1788 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border",
1789 'tile', true,
1790 'insets', tmp2(
1791 'left', 5,
1792 'right', 5,
1793 'top', 5,
1794 'bottom', 5
1795 ),
1796 'tileSize', 16,
1797 'edgeSize', 16
1798 ))
1799 editBoxFrame:SetFrameStrata("FULLSCREEN_DIALOG")
1800 if editBoxFrame.SetTopLevel then
1801 editBoxFrame:SetTopLevel(true)
1802 end
1803 editBoxFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
1804 editBoxFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
1805 editBoxFrame:EnableMouse(true)
1806 editBoxFrame:Hide()
1807 editBoxFrame:SetPoint("CENTER", UIParent, "CENTER")
1808
1809 local editBox = CreateFrame("EditBox", nil, editBoxFrame)
1810 editBoxFrame.editBox = editBox
1811 editBox:SetFontObject(ChatFontNormal)
1812 editBox:SetWidth(160)
1813 editBox:SetHeight(13)
1814 editBox:SetPoint("CENTER", editBoxFrame, "CENTER", 0, 0)
1815
1816 local left = editBox:CreateTexture(nil, "BACKGROUND")
1817 left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left")
1818 left:SetTexCoord(0, 100 / 256, 0, 1)
1819 left:SetWidth(100)
1820 left:SetHeight(32)
1821 left:SetPoint("LEFT", editBox, "LEFT", -10, 0)
1822 local right = editBox:CreateTexture(nil, "BACKGROUND")
1823 right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right")
1824 right:SetTexCoord(156/256, 1, 0, 1)
1825 right:SetWidth(100)
1826 right:SetHeight(32)
1827 right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0)
1828
1829 editBox:SetScript("OnEnterPressed", function()
1830 if editBoxFrame.parent and editBoxFrame.parent.editBoxValidateFunc then
1831 local a1,a2,a3,a4 = editBoxFrame.parent.editBoxValidateArg1, editBoxFrame.parent.editBoxValidateArg2, editBoxFrame.parent.editBoxValidateArg3, editBoxFrame.parent.editBoxValidateArg4
1832
1833 local t = editBox.realText or editBox:GetText() or ""
1834 local result
1835 if a1 == nil then
1836 result = editBoxFrame.parent.editBoxValidateFunc(t)
1837 elseif a2 == nil then
1838 result = editBoxFrame.parent.editBoxValidateFunc(a1, t)
1839 elseif a3 == nil then
1840 result = editBoxFrame.parent.editBoxValidateFunc(a1, a2, t)
1841 elseif a4 == nil then
1842 result = editBoxFrame.parent.editBoxValidateFunc(a1, a2, a3, t)
1843 else
1844 result = editBoxFrame.parent.editBoxValidateFunc(a1, a2, a3, a4, t)
1845 end
1846 if not result then
1847 UIErrorsFrame:AddMessage(VALIDATION_ERROR, 1, 0, 0)
1848 return
1849 end
1850 end
1851 if editBoxFrame.parent and editBoxFrame.parent.editBoxFunc then
1852 local a1,a2,a3,a4 = editBoxFrame.parent.editBoxArg1, editBoxFrame.parent.editBoxArg2, editBoxFrame.parent.editBoxArg3, editBoxFrame.parent.editBoxArg4
1853 local t
1854 if editBox.realText ~= "NONE" then
1855 t = editBox.realText or editBox:GetText() or ""
1856 end
1857 if a1 == nil then
1858 editBoxFrame.parent.editBoxFunc(t)
1859 elseif a2 == nil then
1860 editBoxFrame.parent.editBoxFunc(a1, t)
1861 elseif a3 == nil then
1862 editBoxFrame.parent.editBoxFunc(a1, a2, t)
1863 elseif a4 == nil then
1864 editBoxFrame.parent.editBoxFunc(a1, a2, a3, t)
1865 else
1866 editBoxFrame.parent.editBoxFunc(a1, a2, a3, a4, t)
1867 end
1868 end
1869 self:Close(editBoxFrame.level)
1870 for i = 1, editBoxFrame.level - 1 do
1871 Refresh(self, levels[i])
1872 end
1873 end)
1874 editBox:SetScript("OnEscapePressed", function()
1875 self:Close(editBoxFrame.level)
1876 end)
1877 local changing = false
1878 local skipNext = false
1879
1880 function editBox:SpecialSetText(text)
1881 local oldText = editBox:GetText() or ""
1882 if not text then
1883 text = ""
1884 end
1885 if text ~= oldText then
1886 changing = true
1887 self:SetText(text)
1888 changing = false
1889 skipNext = true
1890 end
1891 end
1892
1893 editBox:SetScript("OnTextChanged", function()
1894 if skipNext then
1895 skipNext = false
1896 elseif not changing and editBoxFrame.parent and editBoxFrame.parent.editBoxChangeFunc then
1897 local a1,a2,a3,a4 = editBoxFrame.parent.editBoxChangeArg1, editBoxFrame.parent.editBoxChangeArg2, editBoxFrame.parent.editBoxChangeArg3, editBoxFrame.parent.editBoxChangeArg4
1898 local t
1899 if editBox.realText ~= "NONE" then
1900 t = editBox.realText or editBox:GetText() or ""
1901 end
1902 local text
1903 if a1 == nil then
1904 text = editBoxFrame.parent.editBoxChangeFunc(t)
1905 elseif a2 == nil then
1906 text = editBoxFrame.parent.editBoxChangeFunc(a1, t)
1907 elseif a3 == nil then
1908 text = editBoxFrame.parent.editBoxChangeFunc(a1, a2, t)
1909 elseif a4 == nil then
1910 text = editBoxFrame.parent.editBoxChangeFunc(a1, a2, a3, t)
1911 else
1912 text = editBoxFrame.parent.editBoxChangeFunc(a1, a2, a3, a4, t)
1913 end
1914 if text then
1915 editBox:SpecialSetText(text)
1916 end
1917 end
1918 end)
1919 editBoxFrame:SetScript("OnEnter", function()
1920 StopCounting(self, editBoxFrame.level)
1921 showGameTooltip(editBoxFrame.parent)
1922 end)
1923 editBoxFrame:SetScript("OnLeave", function()
1924 StartCounting(self, editBoxFrame.level)
1925 GameTooltip:Hide()
1926 end)
1927 editBox:SetScript("OnEnter", function()
1928 StopCounting(self, editBoxFrame.level)
1929 showGameTooltip(editBoxFrame.parent)
1930 end)
1931 editBox:SetScript("OnLeave", function()
1932 StartCounting(self, editBoxFrame.level)
1933 GameTooltip:Hide()
1934 end)
1935 editBoxFrame:SetScript("OnKeyDown", function()
1936 if not editBox.keybinding then
1937 return
1938 end
1939 local arg1 = arg1
1940 local screenshotKey = GetBindingKey("SCREENSHOT")
1941 if screenshotKey and arg1 == screenshotKey then
1942 Screenshot()
1943 return
1944 end
1945
1946 if arg1 == "LeftButton" then
1947 arg1 = "BUTTON1"
1948 elseif arg1 == "RightButton" then
1949 arg1 = "BUTTON2"
1950 elseif arg1 == "MiddleButton" then
1951 arg1 = "BUTTON3"
1952 elseif arg1 == "Button4" then
1953 arg1 = "BUTTON4"
1954 elseif arg1 == "Button5" then
1955 arg1 = "BUTTON5"
1956 end
1957 if arg1 == "BUTTON1" or arg1 == "BUTTON2" or arg1 == "UNKNOWN" then
1958 return
1959 elseif arg1 == "SHIFT" or arg1 == "CTRL" or arg1 == "ALT" then
1960 return
1961 elseif arg1 == "ENTER" then
1962 return editBox:GetScript("OnEnterPressed")()
1963 elseif arg1 == "ESCAPE" then
1964 if editBox.realText == "NONE" then
1965 return editBox:GetScript("OnEscapePressed")()
1966 else
1967 editBox:SpecialSetText(NONE or "NONE")
1968 editBox.realText = "NONE"
1969 return
1970 end
1971 end
1972 local s = GetBindingText(arg1, "KEY_")
1973 local real = arg1
1974 if IsShiftKeyDown() then
1975 s = "SHIFT-" .. s
1976 real = "SHIFT-" .. real
1977 end
1978 if IsControlKeyDown() then
1979 s = "CTRL-" .. s
1980 real = "CTRL-" .. real
1981 end
1982 if IsAltKeyDown() then
1983 s = "ALT-" .. s
1984 real = "ALT-" .. real
1985 end
1986 if editBox:GetText() ~= s then
1987 editBox:SpecialSetText(s)
1988 editBox.realText = real
1989 return editBox:GetScript("OnTextChanged")()
1990 end
1991 end)
1992 editBoxFrame:SetScript("OnMouseDown", editBoxFrame:GetScript("OnKeyDown"))
1993 editBox:SetScript("OnMouseDown", editBoxFrame:GetScript("OnKeyDown"))
1994 end
1995 editBoxFrame.parent = parent
1996 editBoxFrame.level = parent.level.num + 1
1997 editBoxFrame.parentValue = parent.level.value
1998 editBoxFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3)
1999 editBoxFrame.editBox:SetFrameLevel(editBoxFrame:GetFrameLevel() + 1)
2000 editBoxFrame.editBox.realText = nil
2001 editBoxFrame:SetClampedToScreen(false)
2002
2003 if parent.editBoxIsKeybinding then
2004 local s = parent.editBoxText
2005 editBoxFrame.editBox.realText = s
2006 if s and s ~= "" then
2007 local alpha,bravo = s:match("^(.+)%-(.+)$")
2008 if not bravo then
2009 alpha = nil
2010 bravo = s
2011 end
2012 bravo = GetBindingText(bravo, "KEY_")
2013 if alpha then
2014 editBoxFrame.editBox:SpecialSetText(alpha:upper() .. "-" .. bravo)
2015 else
2016 editBoxFrame.editBox:SpecialSetText(bravo)
2017 end
2018 else
2019 editBoxFrame.editBox:SpecialSetText(NONE or "NONE")
2020 end
2021 else
2022 editBoxFrame.editBox:SpecialSetText(parent.editBoxText)
2023 end
2024
2025 editBoxFrame.editBox.keybinding = parent.editBoxIsKeybinding
2026 editBoxFrame.editBox:EnableKeyboard(not parent.editBoxIsKeybinding)
2027 editBoxFrame:EnableKeyboard(parent.editBoxIsKeybinding)
2028
2029 if parent.arrow then
2030 -- parent.arrow:SetVertexColor(0.2, 0.6, 0)
2031 -- parent.arrow:SetHeight(24)
2032 -- parent.arrow:SetWidth(24)
2033 parent.selected = true
2034 parent.highlight:Show()
2035 end
2036
2037 local level = parent.level
2038 editBoxFrame:Show()
2039 editBoxFrame:ClearAllPoints()
2040 if level.lastDirection == "RIGHT" then
2041 if level.lastVDirection == "DOWN" then
2042 editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
2043 else
2044 editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
2045 end
2046 else
2047 if level.lastVDirection == "DOWN" then
2048 editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
2049 else
2050 editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
2051 end
2052 end
2053 local dirty
2054 if level.lastDirection == "RIGHT" then
2055 if editBoxFrame:GetRight() > GetScreenWidth() then
2056 level.lastDirection = "LEFT"
2057 dirty = true
2058 end
2059 elseif editBoxFrame:GetLeft() < 0 then
2060 level.lastDirection = "RIGHT"
2061 dirty = true
2062 end
2063 if level.lastVDirection == "DOWN" then
2064 if editBoxFrame:GetBottom() < 0 then
2065 level.lastVDirection = "UP"
2066 dirty = true
2067 end
2068 elseif editBoxFrame:GetTop() > GetScreenWidth() then
2069 level.lastVDirection = "DOWN"
2070 dirty = true
2071 end
2072 if dirty then
2073 editBoxFrame:ClearAllPoints()
2074 if level.lastDirection == "RIGHT" then
2075 if level.lastVDirection == "DOWN" then
2076 editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10)
2077 else
2078 editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10)
2079 end
2080 else
2081 if level.lastVDirection == "DOWN" then
2082 editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10)
2083 else
2084 editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10)
2085 end
2086 end
2087 end
2088 local left, bottom = editBoxFrame:GetLeft(), editBoxFrame:GetBottom()
2089 editBoxFrame:ClearAllPoints()
2090 editBoxFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
2091 if mod(level.num, 5) == 0 then
2092 local left, bottom = level:GetLeft(), level:GetBottom()
2093 level:ClearAllPoints()
2094 level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom)
2095 end
2096 editBoxFrame:SetClampedToScreen(true)
2097 end
2098
2099 function Dewdrop:IsOpen(parent)
2100 self:argCheck(parent, 2, "table", "nil")
2101 return levels[1] and levels[1]:IsShown() and (not parent or parent == levels[1].parent or parent == levels[1]:GetParent())
2102 end
2103
2104 function Dewdrop:GetOpenedParent()
2105 return (levels[1] and levels[1]:IsShown()) and (levels[1].parent or levels[1]:GetParent())
2106 end
2107
2108 function Open(self, parent, func, level, value, point, relativePoint, cursorX, cursorY)
2109 self:Close(level)
2110 if DewdropLib then
2111 local d = DewdropLib:GetInstance('1.0')
2112 local ret, val = pcall(d, IsOpen, d)
2113 if ret and val then
2114 DewdropLib:GetInstance('1.0'):Close()
2115 end
2116 end
2117 parent:GetCenter()
2118 local frame = AcquireLevel(self, level)
2119 if level == 1 then
2120 frame.lastDirection = "RIGHT"
2121 frame.lastVDirection = "DOWN"
2122 else
2123 frame.lastDirection = levels[level - 1].lastDirection
2124 frame.lastVDirection = levels[level - 1].lastVDirection
2125 end
2126 frame:SetClampedToScreen(false)
2127 frame:SetFrameStrata("FULLSCREEN_DIALOG")
2128 frame:ClearAllPoints()
2129 frame.parent = parent
2130 frame:SetPoint("LEFT", UIParent, "RIGHT", 10000, 0)
2131 frame:Show()
2132 if level == 1 then
2133 baseFunc = func
2134 end
2135 levels[level].value = value
2136 -- levels[level].parentText = parent.text and parent.text:GetText() or nil
2137 -- levels[level].parentTooltipTitle = parent.tooltipTitle
2138 -- levels[level].parentTooltipText = parent.tooltipText
2139 -- levels[level].parentTooltipFunc = parent.tooltipFunc
2140 if parent.arrow then
2141 -- parent.arrow:SetVertexColor(0.2, 0.6, 0)
2142 -- parent.arrow:SetHeight(24)
2143 -- parent.arrow:SetWidth(24)
2144 parent.selected = true
2145 parent.highlight:Show()
2146 end
2147 relativePoint = relativePoint or point
2148 Refresh(self, levels[level])
2149 if point or (cursorX and cursorY) then
2150 frame:ClearAllPoints()
2151 if cursorX and cursorY then
2152 local curX, curY = GetScaledCursorPosition()
2153 if curY < GetScreenHeight() / 2 then
2154 point, relativePoint = "BOTTOM", "BOTTOM"
2155 else
2156 point, relativePoint = "TOP", "TOP"
2157 end
2158 if curX < GetScreenWidth() / 2 then
2159 point, relativePoint = point .. "LEFT", relativePoint .. "RIGHT"
2160 else
2161 point, relativePoint = point .. "RIGHT", relativePoint .. "LEFT"
2162 end
2163 end
2164 frame:SetPoint(point, parent, relativePoint)
2165 if cursorX and cursorY then
2166 local left = frame:GetLeft()
2167 local width = frame:GetWidth()
2168 local bottom = frame:GetBottom()
2169 local height = frame:GetHeight()
2170 local curX, curY = GetScaledCursorPosition()
2171 frame:ClearAllPoints()
2172 relativePoint = relativePoint or point
2173 if point == "BOTTOM" or point == "TOP" then
2174 if curX < GetScreenWidth() / 2 then
2175 point = point .. "LEFT"
2176 else
2177 point = point .. "RIGHT"
2178 end
2179 elseif point == "CENTER" then
2180 if curX < GetScreenWidth() / 2 then
2181 point = "LEFT"
2182 else
2183 point = "RIGHT"
2184 end
2185 end
2186 local xOffset, yOffset = 0, 0
2187 if curY > GetScreenHeight() / 2 then
2188 yOffset = -height
2189 end
2190 if curX > GetScreenWidth() / 2 then
2191 xOffset = -width
2192 end
2193 frame:SetPoint(point, parent, relativePoint, curX - left + xOffset, curY - bottom + yOffset)
2194 if level == 1 then
2195 frame.lastDirection = "RIGHT"
2196 end
2197 elseif cursorX then
2198 local left = frame:GetLeft()
2199 local width = frame:GetWidth()
2200 local curX, curY = GetScaledCursorPosition()
2201 frame:ClearAllPoints()
2202 relativePoint = relativePoint or point
2203 if point == "BOTTOM" or point == "TOP" then
2204 if curX < GetScreenWidth() / 2 then
2205 point = point .. "LEFT"
2206 else
2207 point = point .. "RIGHT"
2208 end
2209 elseif point == "CENTER" then
2210 if curX < GetScreenWidth() / 2 then
2211 point = "LEFT"
2212 else
2213 point = "RIGHT"
2214 end
2215 end
2216 frame:SetPoint(point, parent, relativePoint, curX - left - width / 2, 0)
2217 if level == 1 then
2218 frame.lastDirection = "RIGHT"
2219 end
2220 elseif cursorY then
2221 local bottom = frame:GetBottom()
2222 local height = frame:GetHeight()
2223 local curX, curY = GetScaledCursorPosition()
2224 frame:ClearAllPoints()
2225 relativePoint = relativePoint or point
2226 if point == "LEFT" or point == "RIGHT" then
2227 if curX < GetScreenHeight() / 2 then
2228 point = point .. "BOTTOM"
2229 else
2230 point = point .. "TOP"
2231 end
2232 elseif point == "CENTER" then
2233 if curX < GetScreenHeight() / 2 then
2234 point = "BOTTOM"
2235 else
2236 point = "TOP"
2237 end
2238 end
2239 frame:SetPoint(point, parent, relativePoint, 0, curY - bottom - height / 2)
2240 if level == 1 then
2241 frame.lastDirection = "DOWN"
2242 end
2243 end
2244 if (strsub(point, 1, 3) ~= strsub(relativePoint, 1, 3)) then
2245 if frame:GetBottom() < 0 then
2246 local point, parent, relativePoint, x, y = frame:GetPoint(1)
2247 local change = GetScreenHeight() - frame:GetTop()
2248 local otherChange = -frame:GetBottom()
2249 if otherChange < change then
2250 change = otherChange
2251 end
2252 frame:SetPoint(point, parent, relativePoint, x, y + change)
2253 elseif frame:GetTop() > GetScreenHeight() then
2254 local point, parent, relativePoint, x, y = frame:GetPoint(1)
2255 local change = GetScreenHeight() - frame:GetTop()
2256 local otherChange = -frame:GetBottom()
2257 if otherChange < change then
2258 change = otherChange
2259 end
2260 frame:SetPoint(point, parent, relativePoint, x, y + change)
2261 end
2262 end
2263 end
2264 CheckDualMonitor(self, frame)
2265 frame:SetClampedToScreen(true)
2266 StartCounting(self, level)
2267 end
2268
2269 function Dewdrop:IsRegistered(parent)
2270 self:argCheck(parent, 2, "table")
2271 return not not self.registry[parent]
2272 end
2273
2274 function Dewdrop:Register(parent, ...)
2275 self:argCheck(parent, 2, "table")
2276 if self.registry[parent] then
2277 self:Unregister(parent)
2278 end
2279 local info = new(...)
2280 if type(info.children) == "table" then
2281 local err, position = validateOptions(info.children)
2282
2283 if err then
2284 if position then
2285 Dewdrop:error(position .. ": " .. err)
2286 else
2287 Dewdrop:error(err)
2288 end
2289 end
2290 end
2291 self.registry[parent] = info
2292 if not info.dontHook and not self.onceRegistered[parent] then
2293 if parent:HasScript("OnMouseUp") then
2294 local script = parent:GetScript("OnMouseUp")
2295 parent:SetScript("OnMouseUp", function()
2296 if script then
2297 script()
2298 end
2299 if arg1 == "RightButton" and self.registry[parent] then
2300 if self:IsOpen(parent) then
2301 self:Close()
2302 else
2303 self:Open(parent)
2304 end
2305 end
2306 end)
2307 end
2308 if parent:HasScript("OnMouseDown") then
2309 local script = parent:GetScript("OnMouseDown")
2310 parent:SetScript("OnMouseDown", function()
2311 if script then
2312 script()
2313 end
2314 if self.registry[parent] then
2315 self:Close()
2316 end
2317 end)
2318 end
2319 end
2320 self.onceRegistered[parent] = true
2321 end
2322
2323 function Dewdrop:Unregister(parent)
2324 self:argCheck(parent, 2, "table")
2325 self.registry[parent] = nil
2326 end
2327
2328 function Dewdrop:Open(parent, ...)
2329 self:argCheck(parent, 2, "table")
2330 local info
2331 local k1 = ...
2332 if type(k1) == "table" and k1[0] and k1.IsFrameType and self.registry[k1] then
2333 info = tmp()
2334 for k,v in pairs(self.registry[k1]) do
2335 info[k] = v
2336 end
2337 else
2338 info = tmp(...)
2339 if self.registry[parent] then
2340 for k,v in pairs(self.registry[parent]) do
2341 if info[k] == nil then
2342 info[k] = v
2343 end
2344 end
2345 end
2346 end
2347 local point = info.point
2348 local relativePoint = info.relativePoint
2349 local cursorX = info.cursorX
2350 local cursorY = info.cursorY
2351 if type(point) == "function" then
2352 local b
2353 point, b = point(parent)
2354 if b then
2355 relativePoint = b
2356 end
2357 end
2358 if type(relativePoint) == "function" then
2359 relativePoint = relativePoint(parent)
2360 end
2361 Open(self, parent, info.children, 1, nil, point, relativePoint, cursorX, cursorY)
2362 end
2363
2364 function Clear(self, level)
2365 if level then
2366 if level.buttons then
2367 for i = #level.buttons, 1, -1 do
2368 ReleaseButton(self, level, i)
2369 end
2370 end
2371 end
2372 end
2373
2374 function Dewdrop:Close(level)
2375 if DropDownList1:IsShown() then
2376 DropDownList1:Hide()
2377 end
2378 if DewdropLib then
2379 local d = DewdropLib:GetInstance('1.0')
2380 local ret, val = pcall(d, IsOpen, d)
2381 if ret and val then
2382 DewdropLib:GetInstance('1.0'):Close()
2383 end
2384 end
2385 self:argCheck(level, 2, "number", "nil")
2386 if not level then
2387 level = 1
2388 end
2389 if level == 1 and levels[level] then
2390 levels[level].parented = false
2391 end
2392 if level > 1 and levels[level-1].buttons then
2393 local buttons = levels[level-1].buttons
2394 for _,button in ipairs(buttons) do
2395 -- button.arrow:SetWidth(16)
2396 -- button.arrow:SetHeight(16)
2397 button.selected = nil
2398 button.highlight:Hide()
2399 -- button.arrow:SetVertexColor(1, 1, 1)
2400 end
2401 end
2402 if sliderFrame and sliderFrame.level >= level then
2403 sliderFrame:Hide()
2404 end
2405 if editBoxFrame and editBoxFrame.level >= level then
2406 editBoxFrame:Hide()
2407 end
2408 for i = level, #levels do
2409 Clear(self, levels[level])
2410 levels[i]:Hide()
2411 levels[i]:ClearAllPoints()
2412 levels[i]:SetPoint("CENTER", UIParent, "CENTER")
2413 levels[i].value = nil
2414 end
2415 end
2416
2417 function Dewdrop:AddLine(...)
2418 local info = tmp(...)
2419 local level = info.level or currentLevel
2420 info.level = nil
2421 local button = AcquireButton(self, level)
2422 if not next(info) then
2423 info.disabled = true
2424 end
2425 button.disabled = info.isTitle or info.notClickable or info.disabled
2426 button.isTitle = info.isTitle
2427 button.notClickable = info.notClickable
2428 if button.isTitle then
2429 button.text:SetFontObject(GameFontNormalSmall)
2430 elseif button.notClickable then
2431 button.text:SetFontObject(GameFontHighlightSmall)
2432 elseif button.disabled then
2433 button.text:SetFontObject(GameFontDisableSmall)
2434 else
2435 button.text:SetFontObject(GameFontHighlightSmall)
2436 end
2437 if info.disabled then
2438 button.arrow:SetDesaturated(true)
2439 button.check:SetDesaturated(true)
2440 else
2441 button.arrow:SetDesaturated(false)
2442 button.check:SetDesaturated(false)
2443 end
2444 if info.textR and info.textG and info.textB then
2445 button.textR = info.textR
2446 button.textG = info.textG
2447 button.textB = info.textB
2448 button.text:SetTextColor(button.textR, button.textG, button.textB)
2449 else
2450 button.text:SetTextColor(button.text:GetFontObject():GetTextColor())
2451 end
2452 button.notCheckable = info.notCheckable
2453 button.text:SetPoint("LEFT", button, "LEFT", button.notCheckable and 0 or 24, 0)
2454 button.checked = not info.notCheckable and info.checked
2455 button.isRadio = not info.notCheckable and info.isRadio
2456 if info.isRadio then
2457 button.check:Show()
2458 button.check:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton")
2459 if button.checked then
2460 button.check:SetTexCoord(0.25, 0.5, 0, 1)
2461 button.check:SetVertexColor(1, 1, 1, 1)
2462 else
2463 button.check:SetTexCoord(0, 0.25, 0, 1)
2464 button.check:SetVertexColor(1, 1, 1, 0.5)
2465 end
2466 button.radioHighlight:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton")
2467 button.check:SetWidth(16)
2468 button.check:SetHeight(16)
2469 elseif info.icon then
2470 button.check:Show()
2471 button.check:SetTexture(info.icon)
2472 if info.iconWidth and info.iconHeight then
2473 button.check:SetWidth(info.iconWidth)
2474 button.check:SetHeight(info.iconHeight)
2475 else
2476 button.check:SetWidth(16)
2477 button.check:SetHeight(16)
2478 end
2479 if info.iconCoordLeft and info.iconCoordRight and info.iconCoordTop and info.iconCoordBottom then
2480 button.check:SetTexCoord(info.iconCoordLeft, info.iconCoordRight, info.iconCoordTop, info.iconCoordBottom)
2481 elseif info.icon:find("^Interface\\Icons\\") then
2482 button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95)
2483 else
2484 button.check:SetTexCoord(0, 1, 0, 1)
2485 end
2486 button.check:SetVertexColor(1, 1, 1, 1)
2487 else
2488 if button.checked then
2489 if info.checkIcon then
2490 button.check:SetWidth(16)
2491 button.check:SetHeight(16)
2492 button.check:SetTexture(info.checkIcon)
2493 if info.checkIcon:find("^Interface\\Icons\\") then
2494 button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95)
2495 else
2496 button.check:SetTexCoord(0, 1, 0, 1)
2497 end
2498 else
2499 button.check:SetWidth(24)
2500 button.check:SetHeight(24)
2501 button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
2502 button.check:SetTexCoord(0, 1, 0, 1)
2503 end
2504 button.check:SetVertexColor(1, 1, 1, 1)
2505 else
2506 button.check:SetVertexColor(1, 1, 1, 0)
2507 end
2508 end
2509 if not button.disabled then
2510 button.func = info.func
2511 end
2512 button.hasColorSwatch = info.hasColorSwatch
2513 if button.hasColorSwatch then
2514 button.colorSwatch:Show()
2515 button.colorSwatch.texture:Show()
2516 button.r = info.r or 1
2517 button.g = info.g or 1
2518 button.b = info.b or 1
2519 button.colorSwatch.texture:SetTexture(button.r, button.g, button.b)
2520 button.checked = false
2521 button.func = nil
2522 button.colorFunc = info.colorFunc
2523 button.colorArg1 = info.colorArg1
2524 button.colorArg2 = info.colorArg2
2525 button.colorArg3 = info.colorArg3
2526 button.colorArg4 = info.colorArg4
2527 button.hasOpacity = info.hasOpacity
2528 button.opacity = info.opacity or 1
2529 else
2530 button.colorSwatch:Hide()
2531 button.colorSwatch.texture:Hide()
2532 end
2533 button.hasArrow = not button.hasColorSwatch and (info.value or info.hasSlider or info.hasEditBox) and info.hasArrow
2534 if button.hasArrow then
2535 button.arrow:SetAlpha(1)
2536 if info.hasSlider then
2537 button.hasSlider = true
2538 button.sliderMin = info.sliderMin or 0
2539 button.sliderMax = info.sliderMax or 1
2540 button.sliderStep = info.sliderStep or 0
2541 button.sliderIsPercent = info.sliderIsPercent and true or false
2542 button.sliderMinText = info.sliderMinText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMin * 100) or button.sliderMin
2543 button.sliderMaxText = info.sliderMaxText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMax * 100) or button.sliderMax
2544 button.sliderFunc = info.sliderFunc
2545 button.sliderValue = info.sliderValue
2546 button.sliderArg1 = info.sliderArg1
2547 button.sliderArg2 = info.sliderArg2
2548 button.sliderArg3 = info.sliderArg3
2549 button.sliderArg4 = info.sliderArg4
2550 elseif info.hasEditBox then
2551 button.hasEditBox = true
2552 button.editBoxText = info.editBoxText or ""
2553 button.editBoxFunc = info.editBoxFunc
2554 button.editBoxArg1 = info.editBoxArg1
2555 button.editBoxArg2 = info.editBoxArg2
2556 button.editBoxArg3 = info.editBoxArg3
2557 button.editBoxArg4 = info.editBoxArg4
2558 button.editBoxChangeFunc = info.editBoxChangeFunc
2559 button.editBoxChangeArg1 = info.editBoxChangeArg1
2560 button.editBoxChangeArg2 = info.editBoxChangeArg2
2561 button.editBoxChangeArg3 = info.editBoxChangeArg3
2562 button.editBoxChangeArg4 = info.editBoxChangeArg4
2563 button.editBoxValidateFunc = info.editBoxValidateFunc
2564 button.editBoxValidateArg1 = info.editBoxValidateArg1
2565 button.editBoxValidateArg2 = info.editBoxValidateArg2
2566 button.editBoxValidateArg3 = info.editBoxValidateArg3
2567 button.editBoxValidateArg4 = info.editBoxValidateArg4
2568 button.editBoxIsKeybinding = info.editBoxIsKeybinding
2569 else
2570 button.value = info.value
2571 local l = levels[level+1]
2572 if l and info.value == l.value then
2573 -- button.arrow:SetWidth(24)
2574 -- button.arrow:SetHeight(24)
2575 button.selected = true
2576 button.highlight:Show()
2577 end
2578 end
2579 else
2580 button.arrow:SetAlpha(0)
2581 end
2582 button.arg1 = info.arg1
2583 button.arg2 = info.arg2
2584 button.arg3 = info.arg3
2585 button.arg4 = info.arg4
2586 button.closeWhenClicked = info.closeWhenClicked
2587 button.textHeight = info.textHeight or UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT or 10
2588 local font,_ = button.text:GetFont()
2589 button.text:SetFont(STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF", button.textHeight)
2590 button:SetHeight(button.textHeight + 6)
2591 button.text:SetPoint("RIGHT", button.arrow, (button.hasColorSwatch or button.hasArrow) and "LEFT" or "RIGHT")
2592 button.text:SetJustifyH(info.justifyH or "LEFT")
2593 button.text:SetText(info.text)
2594 button.tooltipTitle = info.tooltipTitle
2595 button.tooltipText = info.tooltipText
2596 button.tooltipFunc = info.tooltipFunc
2597 button.tooltipArg1 = info.tooltipArg1
2598 button.tooltipArg2 = info.tooltipArg2
2599 button.tooltipArg3 = info.tooltipArg3
2600 button.tooltipArg4 = info.tooltipArg4
2601 if not button.tooltipTitle and not button.tooltipText and not button.tooltipFunc and not info.isTitle then
2602 button.tooltipTitle = info.text
2603 end
2604 if type(button.func) == "string" then
2605 self:assert(type(button.arg1) == "table", "Cannot call method " .. button.func .. " on a non-table")
2606 self:assert(type(button.arg1[button.func]) == "function", "Method " .. button.func .. " nonexistant.")
2607 end
2608 end
2609
2610 function Dewdrop:InjectAceOptionsTable(handler, options)
2611 self:argCheck(handler, 2, "table")
2612 self:argCheck(options, 3, "table")
2613 if tostring(options.type):lower() ~= "group" then
2614 self:error('Cannot inject into options table argument #3 if its type is not "group"')
2615 end
2616 if options.handler ~= nil and options.handler ~= handler then
2617 self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2")
2618 end
2619 options.handler = handler
2620 local class = handler.class
2621 if not AceLibrary:HasInstance("AceOO-2.0") or not class then
2622 self:error("Cannot retrieve AceOptions tables from a non-object argument #2")
2623 end
2624 while class and class ~= AceLibrary("AceOO-2.0").Class do
2625 if type(class.GetAceOptionsDataTable) == "function" then
2626 local t = class:GetAceOptionsDataTable(handler)
2627 for k,v in pairs(t) do
2628 if type(options.args) ~= "table" then
2629 options.args = {}
2630 end
2631 if options.args[k] == nil then
2632 options.args[k] = v
2633 end
2634 end
2635 end
2636 local mixins = class.mixins
2637 if mixins then
2638 for mixin in pairs(mixins) do
2639 if type(mixin.GetAceOptionsDataTable) == "function" then
2640 local t = mixin:GetAceOptionsDataTable(handler)
2641 for k,v in pairs(t) do
2642 if type(options.args) ~= "table" then
2643 options.args = {}
2644 end
2645 if options.args[k] == nil then
2646 options.args[k] = v
2647 end
2648 end
2649 end
2650 end
2651 end
2652 class = class.super
2653 end
2654 return options
2655 end
2656
2657 local function activate(self, oldLib, oldDeactivate)
2658 Dewdrop = self
2659 if oldLib and oldLib.registry then
2660 self.registry = oldLib.registry
2661 self.onceRegistered = oldLib.onceRegistered
2662 else
2663 self.registry = {}
2664 self.onceRegistered = {}
2665
2666 local WorldFrame_OnMouseDown = WorldFrame:GetScript("OnMouseDown")
2667 local WorldFrame_OnMouseUp = WorldFrame:GetScript("OnMouseUp")
2668 local oldX, oldY, clickTime
2669 WorldFrame:SetScript("OnMouseDown", function()
2670 oldX,oldY = GetCursorPosition()
2671 clickTime = GetTime()
2672 if WorldFrame_OnMouseDown then
2673 WorldFrame_OnMouseDown()
2674 end
2675 end)
2676
2677 WorldFrame:SetScript("OnMouseUp", function()
2678 local x,y = GetCursorPosition()
2679 if not oldX or not oldY or not x or not y or not clickTime then
2680 self:Close()
2681 if WorldFrame_OnMouseUp then
2682 WorldFrame_OnMouseUp()
2683 end
2684 return
2685 end
2686 local d = math.abs(x - oldX) + math.abs(y - oldY)
2687 if d <= 5 and GetTime() - clickTime < 0.5 then
2688 self:Close()
2689 end
2690 if WorldFrame_OnMouseUp then
2691 WorldFrame_OnMouseUp()
2692 end
2693 end)
2694
2695 if hooksecurefunc then
2696 hooksecurefunc(DropDownList1, "Show", function()
2697 if levels[1] and levels[1]:IsVisible() then
2698 self:Close()
2699 end
2700 end)
2701 else
2702 local DropDownList1_Show = DropDownList1.Show
2703 function DropDownList1.Show(DropDownList1)
2704 if levels[1] and levels[1]:IsVisible() then
2705 self:Close()
2706 end
2707 DropDownList1_Show(DropDownList1)
2708 end
2709 end
2710
2711 if hooksecurefunc then
2712 hooksecurefunc("HideDropDownMenu", function()
2713 if levels[1] and levels[1]:IsVisible() then
2714 self:Close()
2715 end
2716 end)
2717 else
2718 local old_HideDropDownMenu = HideDropDownMenu
2719 function HideDropDownMenu(num)
2720 if levels[1] and levels[1]:IsVisible() then
2721 self:Close()
2722 end
2723 old_HideDropDownMenu(num)
2724 end
2725 end
2726
2727 if hooksecurefunc then
2728 hooksecurefunc("CloseDropDownMenus", function()
2729 if levels[1] and levels[1]:IsVisible() then
2730 self:Close()
2731 end
2732 end)
2733 else
2734 local old_CloseDropDownMenus = CloseDropDownMenus
2735 function CloseDropDownMenus(num)
2736 if levels[1] and levels[1]:IsVisible() then
2737 self:Close()
2738 end
2739 old_CloseDropDownMenus(num)
2740 end
2741 end
2742 end
2743 levels = {}
2744 buttons = {}
2745
2746 if oldDeactivate then
2747 oldDeactivate(oldLib)
2748 end
2749 end
2750
2751 AceLibrary:Register(Dewdrop, MAJOR_VERSION, MINOR_VERSION, activate)