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