vanilla-wow-addons – Blame information for rev 1

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