Mercurial > wow > reaction
comparison lib/Dewdrop-2.0/Dewdrop-2.0.lua @ 33:c54c481ad0ed
- Moved bar control frame from ConfigUI to Bar
- Added LICENSE.txt
- added profile management options
- other minor cleanup
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Thu, 03 Apr 2008 20:25:40 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
32:821b2b7edff1 | 33:c54c481ad0ed |
---|---|
1 --[[ | |
2 Name: Dewdrop-2.0 | |
3 Revision: $Rev: 48630 $ | |
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 License: LGPL v2.1 | |
11 ]] | |
12 | |
13 local MAJOR_VERSION = "Dewdrop-2.0" | |
14 local MINOR_VERSION = "$Revision: 48630 $" | |
15 | |
16 if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end | |
17 if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end | |
18 | |
19 local Dewdrop = {} | |
20 | |
21 local SharedMedia | |
22 | |
23 local CLOSE = "Close" | |
24 local CLOSE_DESC = "Close the menu." | |
25 local VALIDATION_ERROR = "Validation error." | |
26 local USAGE_TOOLTIP = "Usage: %s." | |
27 local RANGE_TOOLTIP = "Note that you can scroll your mouse wheel while over the slider to step by one." | |
28 local RESET_KEYBINDING_DESC = "Hit escape to clear the keybinding." | |
29 local KEY_BUTTON1 = "Left Mouse" | |
30 local KEY_BUTTON2 = "Right Mouse" | |
31 local DISABLED = "Disabled" | |
32 local DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" | |
33 | |
34 if GetLocale() == "deDE" then | |
35 CLOSE = "Schlie\195\159en" | |
36 CLOSE_DESC = "Men\195\188 schlie\195\159en." | |
37 VALIDATION_ERROR = "Validierungsfehler." | |
38 USAGE_TOOLTIP = "Benutzung: %s." | |
39 RANGE_TOOLTIP = "Beachte das du mit dem Mausrad scrollen kannst solange du \195\188ber dem Schieberegler bist, um 10er Spr\195\188nge zu machen." | |
40 RESET_KEYBINDING_DESC = "Escape dr\195\188cken, um die Tastenbelegung zu l\195\182schen." | |
41 KEY_BUTTON1 = "Linke Maustaste" | |
42 KEY_BUTTON2 = "Rechte Maustaste" | |
43 DISABLED = "Deaktiviert" | |
44 DEFAULT_CONFIRM_MESSAGE = "Bist du sicher das du `%s' machen willst?" | |
45 elseif GetLocale() == "koKR" then | |
46 CLOSE = "닫기" | |
47 CLOSE_DESC = "메뉴를 닫습니다." | |
48 VALIDATION_ERROR = "오류 확인." | |
49 USAGE_TOOLTIP = "사용법: %s." | |
50 RANGE_TOOLTIP = "알림 : 슬라이더 위에서 마우스 휠을 사용하면 한단계씩 조절할 수 있습니다." | |
51 RESET_KEYBINDING_DESC = "단축키를 해제하려면 ESC키를 누르세요." | |
52 KEY_BUTTON1 = "왼쪽 마우스" | |
53 KEY_BUTTON2 = "오른쪽 마우스" | |
54 DISABLED = "비활성화됨" | |
55 DEFAULT_CONFIRM_MESSAGE = "정말로 `%s' 실행을 하시겠습니까 ?" | |
56 elseif GetLocale() == "frFR" then | |
57 CLOSE = "Fermer" | |
58 CLOSE_DESC = "Ferme le menu." | |
59 VALIDATION_ERROR = "Erreur de validation." | |
60 USAGE_TOOLTIP = "Utilisation : %s." | |
61 RANGE_TOOLTIP = "Vous pouvez aussi utiliser la molette de la souris pour pour modifier progressivement." | |
62 RESET_KEYBINDING_DESC = "Appuyez sur la touche Echappement pour effacer le raccourci." | |
63 KEY_BUTTON1 = "Clic gauche" | |
64 KEY_BUTTON2 = "Clic droit" | |
65 DISABLED = "D\195\169sactiv\195\169" | |
66 DEFAULT_CONFIRM_MESSAGE = "\195\138tes-vous s\195\187r de vouloir effectuer '%s' ?" | |
67 elseif GetLocale() == "esES" then | |
68 CLOSE = "Cerrar" | |
69 CLOSE_DESC = "Cierra el menú." | |
70 VALIDATION_ERROR = "Error de validación." | |
71 USAGE_TOOLTIP = "Uso: %s." | |
72 RANGE_TOOLTIP = "Puedes desplazarte verticalmente con la rueda del ratón sobre el desplazador." | |
73 RESET_KEYBINDING_DESC = "Pulsa Escape para borrar la asignación de tecla." | |
74 KEY_BUTTON1 = "Clic Izquierdo" | |
75 KEY_BUTTON2 = "Clic Derecho" | |
76 DISABLED = "Desactivado" | |
77 DEFAULT_CONFIRM_MESSAGE = "¿Estás seguro de querer realizar `%s'?" | |
78 elseif GetLocale() == "zhTW" then | |
79 CLOSE = "關閉" | |
80 CLOSE_DESC = "關閉選單。" | |
81 VALIDATION_ERROR = "驗證錯誤。" | |
82 USAGE_TOOLTIP = "用法: %s。" | |
83 RANGE_TOOLTIP = "你可以在捲動條上使用滑鼠滾輪來捲動。" | |
84 RESET_KEYBINDING_DESC = "按Esc鍵清除快捷鍵。" | |
85 KEY_BUTTON1 = "滑鼠左鍵" | |
86 KEY_BUTTON2 = "滑鼠右鍵" | |
87 DISABLED = "停用" | |
88 DEFAULT_CONFIRM_MESSAGE = "是否執行「%s」?" | |
89 elseif GetLocale() == "zhCN" then | |
90 CLOSE = "关闭" | |
91 CLOSE_DESC = "关闭菜单" | |
92 VALIDATION_ERROR = "验证错误." | |
93 USAGE_TOOLTIP = "用法: %s." | |
94 RANGE_TOOLTIP = "你可以在滚动条上使用鼠标滚轮来翻页." | |
95 RESET_KEYBINDING_DESC = "按ESC键清除按键绑定" | |
96 KEY_BUTTON1 = "鼠标左键" | |
97 KEY_BUTTON2 = "鼠标右键" | |
98 DISABLED = "禁用" | |
99 DEFAULT_CONFIRM_MESSAGE = "是否执行'%s'?" | |
100 end | |
101 | |
102 Dewdrop.KEY_BUTTON1 = KEY_BUTTON1 | |
103 Dewdrop.KEY_BUTTON2 = KEY_BUTTON2 | |
104 | |
105 local function new(...) | |
106 local t = {} | |
107 for i = 1, select('#', ...), 2 do | |
108 local k = select(i, ...) | |
109 if k then | |
110 t[k] = select(i+1, ...) | |
111 else | |
112 break | |
113 end | |
114 end | |
115 return t | |
116 end | |
117 | |
118 local tmp | |
119 do | |
120 local t = {} | |
121 function tmp(...) | |
122 for k in pairs(t) do | |
123 t[k] = nil | |
124 end | |
125 for i = 1, select('#', ...), 2 do | |
126 local k = select(i, ...) | |
127 if k then | |
128 t[k] = select(i+1, ...) | |
129 else | |
130 break | |
131 end | |
132 end | |
133 return t | |
134 end | |
135 end | |
136 local tmp2 | |
137 do | |
138 local t = {} | |
139 function tmp2(...) | |
140 for k in pairs(t) do | |
141 t[k] = nil | |
142 end | |
143 for i = 1, select('#', ...), 2 do | |
144 local k = select(i, ...) | |
145 if k then | |
146 t[k] = select(i+1, ...) | |
147 else | |
148 break | |
149 end | |
150 end | |
151 return t | |
152 end | |
153 end | |
154 local levels | |
155 local buttons | |
156 | |
157 | |
158 -- Secure frame handling: | |
159 -- Rather than using secure buttons in the menu (has problems), we have one | |
160 -- master secureframe that we pop onto menu items on mouseover. This requires | |
161 -- some dark magic with OnLeave etc, but it's not too bad. | |
162 | |
163 local secureFrame = CreateFrame("Button", nil, nil, "SecureActionButtonTemplate") | |
164 secureFrame:Hide() | |
165 | |
166 local function secureFrame_Show(self) | |
167 local owner = self.owner | |
168 | |
169 if self.secure then -- Leftovers from previos owner, clean up! ("Shouldn't" happen but does..) | |
170 for k,v in pairs(self.secure) do | |
171 self:SetAttribute(k, nil) | |
172 end | |
173 end | |
174 self.secure = owner.secure; -- Grab hold of new secure data | |
175 | |
176 local scale = owner:GetEffectiveScale() | |
177 | |
178 self:SetPoint("TOPLEFT", nil, "BOTTOMLEFT", owner:GetLeft() * scale, owner:GetTop() * scale) | |
179 self:SetPoint("BOTTOMRIGHT", nil, "BOTTOMLEFT", owner:GetRight() * scale, owner:GetBottom() * scale) | |
180 self:EnableMouse(true) | |
181 for k,v in pairs(self.secure) do | |
182 self:SetAttribute(k, v) | |
183 end | |
184 | |
185 secureFrame:SetFrameStrata(owner:GetFrameStrata()) | |
186 secureFrame:SetFrameLevel(owner:GetFrameLevel()+1) | |
187 | |
188 self:Show() | |
189 end | |
190 | |
191 local function secureFrame_Hide(self) | |
192 self:Hide() | |
193 if self.secure then | |
194 for k,v in pairs(self.secure) do | |
195 self:SetAttribute(k, nil) | |
196 end | |
197 end | |
198 self.secure = nil | |
199 end | |
200 | |
201 secureFrame:SetScript("OnEvent", | |
202 function() | |
203 if event=="PLAYER_REGEN_ENABLED" then | |
204 this.combat = false | |
205 if not this:IsShown() and this.owner then | |
206 secureFrame_Show(this) | |
207 end | |
208 elseif event=="PLAYER_REGEN_DISABLED" then | |
209 this.combat = true | |
210 if this:IsShown() then | |
211 secureFrame_Hide(this) | |
212 end | |
213 end | |
214 end | |
215 ) | |
216 secureFrame:RegisterEvent("PLAYER_REGEN_ENABLED") | |
217 secureFrame:RegisterEvent("PLAYER_REGEN_DISABLED") | |
218 | |
219 secureFrame:SetScript("OnLeave", | |
220 function() | |
221 local owner=this.owner | |
222 this:Deactivate() | |
223 owner:GetScript("OnLeave")() | |
224 end | |
225 ) | |
226 | |
227 secureFrame:HookScript("OnClick", | |
228 function() | |
229 local realthis = this | |
230 this = this.owner | |
231 this:GetScript("OnClick")() | |
232 end | |
233 ) | |
234 | |
235 function secureFrame:IsOwnedBy(frame) | |
236 return self.owner == frame | |
237 end | |
238 | |
239 function secureFrame:Activate(owner) | |
240 if self.owner then -- "Shouldn't" happen but apparently it does and I cba to troubleshoot... | |
241 if not self.combat then | |
242 secureFrame_Hide(self) | |
243 end | |
244 end | |
245 self.owner = owner | |
246 if not self.combat then | |
247 secureFrame_Show(self) | |
248 end | |
249 end | |
250 | |
251 function secureFrame:Deactivate() | |
252 if not self.combat then | |
253 secureFrame_Hide(self) | |
254 end | |
255 self.owner = nil | |
256 end | |
257 | |
258 -- END secure frame utilities | |
259 | |
260 | |
261 -- Underline on mouseover - use a single global underline that we move around, no point in creating lots of copies | |
262 local underlineFrame = CreateFrame("Frame", nil) | |
263 underlineFrame.tx = underlineFrame:CreateTexture() | |
264 underlineFrame.tx:SetTexture(1,1,0.5,0.75) | |
265 underlineFrame:SetScript("OnHide", function(this) this:Hide(); end) | |
266 underlineFrame:SetScript("OnShow", function(this) -- change sizing on the fly to catch runtime uiscale changes | |
267 underlineFrame.tx:SetPoint("TOPLEFT", -1, -2/this:GetEffectiveScale()) | |
268 underlineFrame.tx:SetPoint("RIGHT", 1,0) | |
269 underlineFrame.tx:SetHeight(0.6 / this:GetEffectiveScale()); | |
270 end) | |
271 underlineFrame:SetHeight(1) | |
272 | |
273 -- END underline on mouseover | |
274 | |
275 | |
276 local function GetScaledCursorPosition() | |
277 local x, y = GetCursorPosition() | |
278 local scale = UIParent:GetEffectiveScale() | |
279 return x / scale, y / scale | |
280 end | |
281 | |
282 local function StartCounting(self, level) | |
283 for i = level, 1, -1 do | |
284 if levels[i] then | |
285 levels[i].count = 3 | |
286 end | |
287 end | |
288 end | |
289 | |
290 local function StopCounting(self, level) | |
291 for i = level, 1, -1 do | |
292 if levels[i] then | |
293 levels[i].count = nil | |
294 end | |
295 end | |
296 end | |
297 | |
298 local function OnUpdate(self, elapsed) | |
299 for _,level in ipairs(levels) do | |
300 local count = level.count | |
301 if count then | |
302 count = count - elapsed | |
303 if count < 0 then | |
304 level.count = nil | |
305 self:Close(level.num) | |
306 else | |
307 level.count = count | |
308 end | |
309 end | |
310 end | |
311 end | |
312 | |
313 local function CheckDualMonitor(self, frame) | |
314 local ratio = GetScreenWidth() / GetScreenHeight() | |
315 if ratio >= 2.4 and frame:GetRight() > GetScreenWidth() / 2 and frame:GetLeft() < GetScreenWidth() / 2 then | |
316 local offsetx | |
317 if GetCursorPosition() / GetScreenHeight() * 768 < GetScreenWidth() / 2 then | |
318 offsetx = GetScreenWidth() / 2 - frame:GetRight() | |
319 else | |
320 offsetx = GetScreenWidth() / 2 - frame:GetLeft() | |
321 end | |
322 local point, parent, relativePoint, x, y = frame:GetPoint(1) | |
323 frame:SetPoint(point, parent, relativePoint, (x or 0) + offsetx, y or 0) | |
324 end | |
325 end | |
326 | |
327 local function CheckSize(self, level) | |
328 if not level.buttons then | |
329 return | |
330 end | |
331 local height = 20 | |
332 for _, button in ipairs(level.buttons) do | |
333 height = height + button:GetHeight() | |
334 end | |
335 level:SetHeight(height) | |
336 local width = 160 | |
337 for _, button in ipairs(level.buttons) do | |
338 local extra = 1 | |
339 if button.hasArrow or button.hasColorSwatch then | |
340 extra = extra + 16 | |
341 end | |
342 if not button.notCheckable then | |
343 extra = extra + 24 | |
344 end | |
345 button.text:SetFont(STANDARD_TEXT_FONT, button.textHeight) | |
346 if button.text:GetWidth() + extra > width then | |
347 width = button.text:GetWidth() + extra | |
348 end | |
349 end | |
350 level:SetWidth(width + 20) | |
351 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 | |
352 level:ClearAllPoints() | |
353 local parent = level.parent or level:GetParent() | |
354 if type(parent) ~= "table" then | |
355 parent = UIParent | |
356 end | |
357 if level.lastDirection == "RIGHT" then | |
358 if level.lastVDirection == "DOWN" then | |
359 level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) | |
360 else | |
361 level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) | |
362 end | |
363 else | |
364 if level.lastVDirection == "DOWN" then | |
365 level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) | |
366 else | |
367 level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) | |
368 end | |
369 end | |
370 end | |
371 local dirty = false | |
372 if not level:GetRight() then | |
373 self:Close() | |
374 return | |
375 end | |
376 if level:GetRight() > GetScreenWidth() and level.lastDirection == "RIGHT" then | |
377 level.lastDirection = "LEFT" | |
378 dirty = true | |
379 elseif level:GetLeft() < 0 and level.lastDirection == "LEFT" then | |
380 level.lastDirection = "RIGHT" | |
381 dirty = true | |
382 end | |
383 if level:GetTop() > GetScreenHeight() and level.lastVDirection == "UP" then | |
384 level.lastVDirection = "DOWN" | |
385 dirty = true | |
386 elseif level:GetBottom() < 0 and level.lastVDirection == "DOWN" then | |
387 level.lastVDirection = "UP" | |
388 dirty = true | |
389 end | |
390 if dirty then | |
391 level:ClearAllPoints() | |
392 local parent = level.parent or level:GetParent() | |
393 if type(parent) ~= "table" then | |
394 parent = UIParent | |
395 end | |
396 if level.lastDirection == "RIGHT" then | |
397 if level.lastVDirection == "DOWN" then | |
398 level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) | |
399 else | |
400 level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) | |
401 end | |
402 else | |
403 if level.lastVDirection == "DOWN" then | |
404 level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) | |
405 else | |
406 level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) | |
407 end | |
408 end | |
409 end | |
410 if level:GetTop() > GetScreenHeight() then | |
411 local top = level:GetTop() | |
412 local point, parent, relativePoint, x, y = level:GetPoint(1) | |
413 level:ClearAllPoints() | |
414 level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) + GetScreenHeight() - top) | |
415 elseif level:GetBottom() < 0 then | |
416 local bottom = level:GetBottom() | |
417 local point, parent, relativePoint, x, y = level:GetPoint(1) | |
418 level:ClearAllPoints() | |
419 level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) - bottom) | |
420 end | |
421 CheckDualMonitor(self, level) | |
422 if mod(level.num, 5) == 0 then | |
423 local left, bottom = level:GetLeft(), level:GetBottom() | |
424 level:ClearAllPoints() | |
425 level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) | |
426 end | |
427 end | |
428 | |
429 local Open | |
430 local OpenSlider | |
431 local OpenEditBox | |
432 local Refresh | |
433 local Clear | |
434 local function ReleaseButton(self, level, index) | |
435 if not level.buttons then | |
436 return | |
437 end | |
438 if not level.buttons[index] then | |
439 return | |
440 end | |
441 local button = level.buttons[index] | |
442 button:Hide() | |
443 if button.highlight then | |
444 button.highlight:Hide() | |
445 end | |
446 -- button.arrow:SetVertexColor(1, 1, 1) | |
447 -- button.arrow:SetHeight(16) | |
448 -- button.arrow:SetWidth(16) | |
449 table.remove(level.buttons, index) | |
450 table.insert(buttons, button) | |
451 for k in pairs(button) do | |
452 if k ~= 0 and k ~= "text" and k ~= "check" and k ~= "arrow" and k ~= "colorSwatch" and k ~= "highlight" and k ~= "radioHighlight" then | |
453 button[k] = nil | |
454 end | |
455 end | |
456 return true | |
457 end | |
458 | |
459 local function Scroll(self, level, down) | |
460 if down then | |
461 if level:GetBottom() < 0 then | |
462 local point, parent, relativePoint, x, y = level:GetPoint(1) | |
463 level:SetPoint(point, parent, relativePoint, x, y + 50) | |
464 if level:GetBottom() > 0 then | |
465 level:SetPoint(point, parent, relativePoint, x, y + 50 - level:GetBottom()) | |
466 end | |
467 end | |
468 else | |
469 if level:GetTop() > GetScreenHeight() then | |
470 local point, parent, relativePoint, x, y = level:GetPoint(1) | |
471 level:SetPoint(point, parent, relativePoint, x, y - 50) | |
472 if level:GetTop() < GetScreenHeight() then | |
473 level:SetPoint(point, parent, relativePoint, x, y - 50 + GetScreenHeight() - level:GetTop()) | |
474 end | |
475 end | |
476 end | |
477 end | |
478 | |
479 local function getArgs(t, str, num, ...) | |
480 local x = t[str .. num] | |
481 if x == nil then | |
482 return ... | |
483 else | |
484 return x, getArgs(t, str, num + 1, ...) | |
485 end | |
486 end | |
487 | |
488 local sliderFrame | |
489 local editBoxFrame | |
490 | |
491 local normalFont | |
492 local lastSetFont | |
493 local justSetFont = false | |
494 local regionTmp = {} | |
495 local function fillRegionTmp(...) | |
496 for i = 1, select('#', ...) do | |
497 regionTmp[i] = select(i, ...) | |
498 end | |
499 end | |
500 | |
501 local function showGameTooltip(this) | |
502 if this.tooltipTitle or this.tooltipText then | |
503 GameTooltip_SetDefaultAnchor(GameTooltip, this) | |
504 local disabled = not this.isTitle and this.disabled | |
505 local font | |
506 if this.tooltipTitle then | |
507 if SharedMedia and SharedMedia:IsValid("font", this.tooltipTitle) then | |
508 font = SharedMedia:Fetch("font", this.tooltipTitle) | |
509 end | |
510 if disabled then | |
511 GameTooltip:SetText(this.tooltipTitle, 0.5, 0.5, 0.5, 1) | |
512 else | |
513 GameTooltip:SetText(this.tooltipTitle, 1, 1, 1, 1) | |
514 end | |
515 if this.tooltipText then | |
516 if not font and SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then | |
517 font = SharedMedia:Fetch("font", this.tooltipText) | |
518 end | |
519 if disabled then | |
520 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) | |
521 else | |
522 GameTooltip:AddLine(this.tooltipText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1) | |
523 end | |
524 end | |
525 else | |
526 if SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then | |
527 font = SharedMedia:Fetch("font", this.tooltipText) | |
528 end | |
529 if disabled then | |
530 GameTooltip:SetText(this.tooltipText, 0.5, 0.5, 0.5, 1) | |
531 else | |
532 GameTooltip:SetText(this.tooltipText, 1, 1, 1, 1) | |
533 end | |
534 end | |
535 if font then | |
536 fillRegionTmp(GameTooltip:GetRegions()) | |
537 lastSetFont = font | |
538 justSetFont = true | |
539 for i,v in ipairs(regionTmp) do | |
540 if v.SetFont then | |
541 local norm,size,outline = v:GetFont() | |
542 v:SetFont(font, size, outline) | |
543 if not normalFont then | |
544 normalFont = norm | |
545 end | |
546 end | |
547 regionTmp[i] = nil | |
548 end | |
549 elseif not normalFont then | |
550 fillRegionTmp(GameTooltip:GetRegions()) | |
551 for i,v in ipairs(regionTmp) do | |
552 if v.GetFont and not normalFont then | |
553 normalFont = v:GetFont() | |
554 end | |
555 regionTmp[i] = nil | |
556 end | |
557 end | |
558 GameTooltip:Show() | |
559 end | |
560 if this.tooltipFunc then | |
561 GameTooltip:SetOwner(this, "ANCHOR_NONE") | |
562 GameTooltip:SetPoint("TOPLEFT", this, "TOPRIGHT", 5, 0) | |
563 this.tooltipFunc(getArgs(this, 'tooltipArg', 1)) | |
564 GameTooltip:Show() | |
565 end | |
566 end | |
567 | |
568 local tmpt = setmetatable({}, {mode='v'}) | |
569 local numButtons = 0 | |
570 local function AcquireButton(self, level) | |
571 if not levels[level] then | |
572 return | |
573 end | |
574 level = levels[level] | |
575 if not level.buttons then | |
576 level.buttons = {} | |
577 end | |
578 local button | |
579 if #buttons == 0 then | |
580 numButtons = numButtons + 1 | |
581 button = CreateFrame("Button", "Dewdrop20Button" .. numButtons, nil) | |
582 button:SetFrameStrata("FULLSCREEN_DIALOG") | |
583 button:SetHeight(16) | |
584 local highlight = button:CreateTexture(nil, "BACKGROUND") | |
585 highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") | |
586 button.highlight = highlight | |
587 highlight:SetBlendMode("ADD") | |
588 highlight:SetAllPoints(button) | |
589 highlight:Hide() | |
590 local check = button:CreateTexture(nil, "ARTWORK") | |
591 button.check = check | |
592 check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") | |
593 check:SetPoint("CENTER", button, "LEFT", 12, 0) | |
594 check:SetWidth(24) | |
595 check:SetHeight(24) | |
596 local radioHighlight = button:CreateTexture(nil, "ARTWORK") | |
597 button.radioHighlight = radioHighlight | |
598 radioHighlight:SetTexture("Interface\\Buttons\\UI-RadioButton") | |
599 radioHighlight:SetAllPoints(check) | |
600 radioHighlight:SetBlendMode("ADD") | |
601 radioHighlight:SetTexCoord(0.5, 0.75, 0, 1) | |
602 radioHighlight:Hide() | |
603 button:SetScript("OnEnter", function() | |
604 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 | |
605 for i = 1, this.level.num do | |
606 Refresh(self, levels[i]) | |
607 end | |
608 return | |
609 end | |
610 self:Close(this.level.num + 1) | |
611 if not this.disabled then | |
612 if this.secure then | |
613 secureFrame:Activate(this) | |
614 elseif this.hasSlider then | |
615 OpenSlider(self, this) | |
616 elseif this.hasEditBox then | |
617 OpenEditBox(self, this) | |
618 elseif this.hasArrow then | |
619 Open(self, this, nil, this.level.num + 1, this.value) | |
620 end | |
621 end | |
622 if not this.level then -- button reclaimed | |
623 return | |
624 end | |
625 StopCounting(self, this.level.num + 1) | |
626 if not this.disabled then | |
627 highlight:Show() | |
628 if this.isRadio then | |
629 button.radioHighlight:Show() | |
630 end | |
631 if this.mouseoverUnderline then | |
632 underlineFrame:SetParent(this) | |
633 underlineFrame:SetPoint("BOTTOMLEFT",this.text,0,0) | |
634 underlineFrame:SetWidth(this.text:GetWidth()) | |
635 underlineFrame:Show() | |
636 end | |
637 end | |
638 showGameTooltip(this) | |
639 end) | |
640 button:SetScript("OnHide", function() | |
641 if this.secure and secureFrame:IsOwnedBy(this) then | |
642 secureFrame:Deactivate() | |
643 end | |
644 end) | |
645 button:SetScript("OnLeave", function() | |
646 if this.secure and secureFrame:IsShown() then | |
647 return; -- it's ok, we didn't actually mouse out of the button, only onto the secure frame on top of it | |
648 end | |
649 underlineFrame:Hide() | |
650 if not this.selected then | |
651 highlight:Hide() | |
652 end | |
653 button.radioHighlight:Hide() | |
654 if this.level then | |
655 StartCounting(self, this.level.num) | |
656 end | |
657 GameTooltip:Hide() | |
658 end) | |
659 local first = true | |
660 button:SetScript("OnClick", function() | |
661 if not this.disabled then | |
662 if this.hasColorSwatch then | |
663 local func = button.colorFunc | |
664 local hasOpacity = this.hasOpacity | |
665 local this = this | |
666 for k in pairs(tmpt) do | |
667 tmpt[k] = nil | |
668 end | |
669 for i = 1, 1000 do | |
670 local x = this['colorArg'..i] | |
671 if x == nil then | |
672 break | |
673 else | |
674 tmpt[i] = x | |
675 end | |
676 end | |
677 ColorPickerFrame.func = function() | |
678 if func then | |
679 local r,g,b = ColorPickerFrame:GetColorRGB() | |
680 local a = hasOpacity and 1 - OpacitySliderFrame:GetValue() or nil | |
681 local n = #tmpt | |
682 tmpt[n+1] = r | |
683 tmpt[n+2] = g | |
684 tmpt[n+3] = b | |
685 tmpt[n+4] = a | |
686 func(unpack(tmpt)) | |
687 tmpt[n+1] = nil | |
688 tmpt[n+2] = nil | |
689 tmpt[n+3] = nil | |
690 tmpt[n+4] = nil | |
691 end | |
692 end | |
693 ColorPickerFrame.hasOpacity = this.hasOpacity | |
694 ColorPickerFrame.opacityFunc = ColorPickerFrame.func | |
695 ColorPickerFrame.opacity = 1 - this.opacity | |
696 ColorPickerFrame:SetColorRGB(this.r, this.g, this.b) | |
697 local r, g, b, a = this.r, this.g, this.b, this.opacity | |
698 ColorPickerFrame.cancelFunc = function() | |
699 if func then | |
700 local n = #tmpt | |
701 tmpt[n+1] = r | |
702 tmpt[n+2] = g | |
703 tmpt[n+3] = b | |
704 tmpt[n+4] = a | |
705 func(unpack(tmpt)) | |
706 for i = 1, n+4 do | |
707 tmpt[i] = nil | |
708 end | |
709 end | |
710 end | |
711 self:Close(1) | |
712 ShowUIPanel(ColorPickerFrame) | |
713 elseif this.func then | |
714 local level = this.level | |
715 if type(this.func) == "string" then | |
716 if type(this.arg1[this.func]) ~= "function" then | |
717 self:error("Cannot call method %q", this.func) | |
718 end | |
719 this.arg1[this.func](this.arg1, getArgs(this, 'arg', 2)) | |
720 else | |
721 this.func(getArgs(this, 'arg', 1)) | |
722 end | |
723 if this.closeWhenClicked then | |
724 self:Close() | |
725 elseif level:IsShown() then | |
726 for i = 1, level.num do | |
727 Refresh(self, levels[i]) | |
728 end | |
729 local value = levels[level.num].value | |
730 for i = level.num-1, 1, -1 do | |
731 local level = levels[i] | |
732 local good = false | |
733 for _,button in ipairs(level.buttons) do | |
734 if button.value == value then | |
735 good = true | |
736 break | |
737 end | |
738 end | |
739 if not good then | |
740 Dewdrop:Close(i+1) | |
741 end | |
742 value = levels[i].value | |
743 end | |
744 end | |
745 elseif this.closeWhenClicked then | |
746 self:Close() | |
747 end | |
748 end | |
749 end) | |
750 local text = button:CreateFontString(nil, "ARTWORK") | |
751 button.text = text | |
752 text:SetFontObject(GameFontHighlightSmall) | |
753 button.text:SetFont(STANDARD_TEXT_FONT, UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT) | |
754 button:SetScript("OnMouseDown", function() | |
755 if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then | |
756 text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 1 or 25, -1) | |
757 end | |
758 end) | |
759 button:SetScript("OnMouseUp", function() | |
760 if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then | |
761 text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 0 or 24, 0) | |
762 end | |
763 end) | |
764 local arrow = button:CreateTexture(nil, "ARTWORK") | |
765 button.arrow = arrow | |
766 arrow:SetPoint("LEFT", button, "RIGHT", -16, 0) | |
767 arrow:SetWidth(16) | |
768 arrow:SetHeight(16) | |
769 arrow:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow") | |
770 local colorSwatch = button:CreateTexture(nil, "ARTWORK") | |
771 button.colorSwatch = colorSwatch | |
772 colorSwatch:SetWidth(20) | |
773 colorSwatch:SetHeight(20) | |
774 colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch") | |
775 local texture = button:CreateTexture(nil, "OVERLAY") | |
776 colorSwatch.texture = texture | |
777 texture:SetTexture("Interface\\Buttons\\WHITE8X8") | |
778 texture:SetWidth(11.5) | |
779 texture:SetHeight(11.5) | |
780 texture:Show() | |
781 texture:SetPoint("CENTER", colorSwatch, "CENTER") | |
782 colorSwatch:SetPoint("RIGHT", button, "RIGHT", 0, 0) | |
783 else | |
784 button = table.remove(buttons) | |
785 end | |
786 button:ClearAllPoints() | |
787 button:SetParent(level) | |
788 button:SetFrameStrata(level:GetFrameStrata()) | |
789 button:SetFrameLevel(level:GetFrameLevel() + 1) | |
790 button:SetPoint("LEFT", level, "LEFT", 10, 0) | |
791 button:SetPoint("RIGHT", level, "RIGHT", -10, 0) | |
792 if #level.buttons == 0 then | |
793 button:SetPoint("TOP", level, "TOP", 0, -10) | |
794 else | |
795 button:SetPoint("TOP", level.buttons[#level.buttons], "BOTTOM", 0, 0) | |
796 end | |
797 button.text:SetPoint("LEFT", button, "LEFT", 24, 0) | |
798 button:Show() | |
799 button.level = level | |
800 table.insert(level.buttons, button) | |
801 if not level.parented then | |
802 level.parented = true | |
803 level:ClearAllPoints() | |
804 if level.num == 1 then | |
805 if level.parent ~= UIParent and type(level.parent) == "table" then | |
806 level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT") | |
807 else | |
808 level:SetPoint("CENTER", UIParent, "CENTER") | |
809 end | |
810 else | |
811 if level.lastDirection == "RIGHT" then | |
812 if level.lastVDirection == "DOWN" then | |
813 level:SetPoint("TOPLEFT", level.parent, "TOPRIGHT", 5, 10) | |
814 else | |
815 level:SetPoint("BOTTOMLEFT", level.parent, "BOTTOMRIGHT", 5, -10) | |
816 end | |
817 else | |
818 if level.lastVDirection == "DOWN" then | |
819 level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT", -5, 10) | |
820 else | |
821 level:SetPoint("BOTTOMRIGHT", level.parent, "BOTTOMLEFT", -5, -10) | |
822 end | |
823 end | |
824 end | |
825 level:SetFrameStrata("FULLSCREEN_DIALOG") | |
826 end | |
827 button:SetAlpha(1) | |
828 return button | |
829 end | |
830 | |
831 local numLevels = 0 | |
832 local function AcquireLevel(self, level) | |
833 if not levels[level] then | |
834 for i = #levels + 1, level, -1 do | |
835 local i = i | |
836 numLevels = numLevels + 1 | |
837 local frame = CreateFrame("Button", "Dewdrop20Level" .. numLevels, nil) | |
838 if i == 1 then | |
839 local old_CloseSpecialWindows = CloseSpecialWindows | |
840 function CloseSpecialWindows() | |
841 local found = old_CloseSpecialWindows() | |
842 if levels[1]:IsShown() then | |
843 self:Close() | |
844 return 1 | |
845 end | |
846 return found | |
847 end | |
848 end | |
849 levels[i] = frame | |
850 frame.num = i | |
851 frame:SetParent(UIParent) | |
852 frame:SetFrameStrata("FULLSCREEN_DIALOG") | |
853 frame:Hide() | |
854 frame:SetWidth(180) | |
855 frame:SetHeight(10) | |
856 frame:SetFrameLevel(i * 3) | |
857 frame:SetScript("OnHide", function() | |
858 self:Close(level + 1) | |
859 end) | |
860 if frame.SetTopLevel then | |
861 frame:SetTopLevel(true) | |
862 end | |
863 frame:EnableMouse(true) | |
864 frame:EnableMouseWheel(true) | |
865 local backdrop = CreateFrame("Frame", nil, frame) | |
866 backdrop:SetAllPoints(frame) | |
867 backdrop:SetBackdrop(tmp( | |
868 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", | |
869 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", | |
870 'tile', true, | |
871 'insets', tmp2( | |
872 'left', 5, | |
873 'right', 5, | |
874 'top', 5, | |
875 'bottom', 5 | |
876 ), | |
877 'tileSize', 16, | |
878 'edgeSize', 16 | |
879 )) | |
880 backdrop:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) | |
881 backdrop:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) | |
882 frame:SetScript("OnClick", function() | |
883 self:Close(i) | |
884 end) | |
885 frame:SetScript("OnEnter", function() | |
886 StopCounting(self, i) | |
887 end) | |
888 frame:SetScript("OnLeave", function() | |
889 StartCounting(self, i) | |
890 end) | |
891 frame:SetScript("OnMouseWheel", function() | |
892 Scroll(self, frame, arg1 < 0) | |
893 end) | |
894 if i == 1 then | |
895 frame:SetScript("OnUpdate", function(this, arg1) | |
896 OnUpdate(self, arg1) | |
897 end) | |
898 levels[1].lastDirection = "RIGHT" | |
899 levels[1].lastVDirection = "DOWN" | |
900 else | |
901 levels[i].lastDirection = levels[i - 1].lastDirection | |
902 levels[i].lastVDirection = levels[i - 1].lastVDirection | |
903 end | |
904 end | |
905 end | |
906 local fullscreenFrame = GetUIPanel("fullscreen") | |
907 local l = levels[level] | |
908 local strata, framelevel = l:GetFrameStrata(), l:GetFrameLevel() | |
909 if fullscreenFrame then | |
910 l:SetParent(fullscreenFrame) | |
911 else | |
912 l:SetParent(UIParent) | |
913 end | |
914 l:SetFrameStrata(strata) | |
915 l:SetFrameLevel(framelevel) | |
916 l:SetAlpha(1) | |
917 return l | |
918 end | |
919 | |
920 local function validateOptions(options, position, baseOptions, fromPass) | |
921 if not baseOptions then | |
922 baseOptions = options | |
923 end | |
924 if type(options) ~= "table" then | |
925 return "Options must be a table.", position | |
926 end | |
927 local kind = options.type | |
928 if type(kind) ~= "string" then | |
929 return '"type" must be a string.', position | |
930 elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "dragLink" and kind ~= "header" then | |
931 return '"type" must either be "range", "text", "group", "toggle", "execute", "color", "dragLink", or "header".', position | |
932 end | |
933 if options.aliases then | |
934 if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then | |
935 return '"alias" must be a table or string', position | |
936 end | |
937 end | |
938 if not fromPass then | |
939 if kind == "execute" then | |
940 if type(options.func) ~= "string" and type(options.func) ~= "function" then | |
941 return '"func" must be a string or function', position | |
942 end | |
943 elseif kind == "range" or kind == "text" or kind == "toggle" then | |
944 if type(options.set) ~= "string" and type(options.set) ~= "function" then | |
945 return '"set" must be a string or function', position | |
946 end | |
947 if kind == "text" and options.get == false then | |
948 elseif type(options.get) ~= "string" and type(options.get) ~= "function" then | |
949 return '"get" must be a string or function', position | |
950 end | |
951 elseif kind == "group" and options.pass then | |
952 if options.pass ~= true then | |
953 return '"pass" must be either nil, true, or false', position | |
954 end | |
955 if not options.func then | |
956 if type(options.set) ~= "string" and type(options.set) ~= "function" then | |
957 return '"set" must be a string or function', position | |
958 end | |
959 if type(options.get) ~= "string" and type(options.get) ~= "function" then | |
960 return '"get" must be a string or function', position | |
961 end | |
962 elseif type(options.func) ~= "string" and type(options.func) ~= "function" then | |
963 return '"func" must be a string or function', position | |
964 end | |
965 end | |
966 end | |
967 if options ~= baseOptions then | |
968 if kind == "header" then | |
969 elseif type(options.desc) ~= "string" then | |
970 return '"desc" must be a string', position | |
971 elseif options.desc:len() == 0 then | |
972 return '"desc" cannot be a 0-length string', position | |
973 end | |
974 end | |
975 if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then | |
976 if options.type == "header" and not options.cmdName and not options.name then | |
977 elseif options.cmdName then | |
978 if type(options.cmdName) ~= "string" then | |
979 return '"cmdName" must be a string or nil', position | |
980 elseif options.cmdName:len() == 0 then | |
981 return '"cmdName" cannot be a 0-length string', position | |
982 end | |
983 if type(options.guiName) ~= "string" then | |
984 if not options.guiNameIsMap then | |
985 return '"guiName" must be a string or nil', position | |
986 end | |
987 elseif options.guiName:len() == 0 then | |
988 return '"guiName" cannot be a 0-length string', position | |
989 end | |
990 else | |
991 if type(options.name) ~= "string" then | |
992 return '"name" must be a string', position | |
993 elseif options.name:len() == 0 then | |
994 return '"name" cannot be a 0-length string', position | |
995 end | |
996 end | |
997 end | |
998 if options.guiNameIsMap then | |
999 if type(options.guiNameIsMap) ~= "boolean" then | |
1000 return '"guiNameIsMap" must be a boolean or nil', position | |
1001 elseif options.type ~= "toggle" then | |
1002 return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position | |
1003 elseif type(options.map) ~= "table" then | |
1004 return '"map" must be a table', position | |
1005 end | |
1006 end | |
1007 if options.message and type(options.message) ~= "string" then | |
1008 return '"message" must be a string or nil', position | |
1009 end | |
1010 if options.error and type(options.error) ~= "string" then | |
1011 return '"error" must be a string or nil', position | |
1012 end | |
1013 if options.current and type(options.current) ~= "string" then | |
1014 return '"current" must be a string or nil', position | |
1015 end | |
1016 if options.order then | |
1017 if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then | |
1018 return '"order" must be a non-zero number or nil', position | |
1019 end | |
1020 end | |
1021 if options.disabled then | |
1022 if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then | |
1023 return '"disabled" must be a function, string, or boolean', position | |
1024 end | |
1025 end | |
1026 if options.cmdHidden then | |
1027 if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then | |
1028 return '"cmdHidden" must be a function, string, or boolean', position | |
1029 end | |
1030 end | |
1031 if options.guiHidden then | |
1032 if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then | |
1033 return '"guiHidden" must be a function, string, or boolean', position | |
1034 end | |
1035 end | |
1036 if options.hidden then | |
1037 if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then | |
1038 return '"hidden" must be a function, string, or boolean', position | |
1039 end | |
1040 end | |
1041 if kind == "text" then | |
1042 if type(options.validate) == "table" then | |
1043 local t = options.validate | |
1044 local iTable = nil | |
1045 for k,v in pairs(t) do | |
1046 if type(k) == "number" then | |
1047 if iTable == nil then | |
1048 iTable = true | |
1049 elseif not iTable then | |
1050 return '"validate" must either have all keys be indexed numbers or strings', position | |
1051 elseif k < 1 or k > #t then | |
1052 return '"validate" numeric keys must be indexed properly. >= 1 and <= #t', position | |
1053 end | |
1054 else | |
1055 if iTable == nil then | |
1056 iTable = false | |
1057 elseif iTable then | |
1058 return '"validate" must either have all keys be indexed numbers or strings', position | |
1059 end | |
1060 end | |
1061 if type(v) ~= "string" then | |
1062 return '"validate" values must all be strings', position | |
1063 end | |
1064 end | |
1065 if options.multiToggle and options.multiToggle ~= true then | |
1066 return '"multiToggle" must be a boolean or nil if "validate" is a table', position | |
1067 end | |
1068 elseif options.validate == "keybinding" then | |
1069 -- no other checks | |
1070 else | |
1071 if type(options.usage) ~= "string" then | |
1072 return '"usage" must be a string', position | |
1073 elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then | |
1074 return '"validate" must be a string, function, or table', position | |
1075 end | |
1076 end | |
1077 if options.multiToggle and type(options.validate) ~= "table" then | |
1078 return '"validate" must be a table if "multiToggle" is true', position | |
1079 end | |
1080 elseif kind == "range" then | |
1081 if options.min or options.max then | |
1082 if type(options.min) ~= "number" then | |
1083 return '"min" must be a number', position | |
1084 elseif type(options.max) ~= "number" then | |
1085 return '"max" must be a number', position | |
1086 elseif options.min >= options.max then | |
1087 return '"min" must be less than "max"', position | |
1088 end | |
1089 end | |
1090 if options.step then | |
1091 if type(options.step) ~= "number" then | |
1092 return '"step" must be a number', position | |
1093 elseif options.step < 0 then | |
1094 return '"step" must be nonnegative', position | |
1095 end | |
1096 end | |
1097 if options.bigStep then | |
1098 if type(options.bigStep) ~= "number" then | |
1099 return '"bigStep" must be a number', position | |
1100 elseif options.bigStep < 0 then | |
1101 return '"bigStep" must be nonnegative', position | |
1102 end | |
1103 end | |
1104 if options.isPercent and options.isPercent ~= true then | |
1105 return '"isPercent" must either be nil, true, or false', position | |
1106 end | |
1107 elseif kind == "toggle" then | |
1108 if options.map then | |
1109 if type(options.map) ~= "table" then | |
1110 return '"map" must be a table', position | |
1111 elseif type(options.map[true]) ~= "string" then | |
1112 return '"map[true]" must be a string', position | |
1113 elseif type(options.map[false]) ~= "string" then | |
1114 return '"map[false]" must be a string', position | |
1115 end | |
1116 end | |
1117 elseif kind == "color" then | |
1118 if options.hasAlpha and options.hasAlpha ~= true then | |
1119 return '"hasAlpha" must be nil, true, or false', position | |
1120 end | |
1121 elseif kind == "group" then | |
1122 if options.pass and options.pass ~= true then | |
1123 return '"pass" must be nil, true, or false', position | |
1124 end | |
1125 if type(options.args) ~= "table" then | |
1126 return '"args" must be a table', position | |
1127 end | |
1128 for k,v in pairs(options.args) do | |
1129 if type(k) ~= "number" then | |
1130 if type(k) ~= "string" then | |
1131 return '"args" keys must be strings or numbers', position | |
1132 elseif k:len() == 0 then | |
1133 return '"args" keys must not be 0-length strings.', position | |
1134 end | |
1135 end | |
1136 if type(v) ~= "table" then | |
1137 return '"args" values must be tables', position and position .. "." .. k or k | |
1138 end | |
1139 local newposition | |
1140 if position then | |
1141 newposition = position .. ".args." .. k | |
1142 else | |
1143 newposition = "args." .. k | |
1144 end | |
1145 local err, pos = validateOptions(v, newposition, baseOptions, options.pass) | |
1146 if err then | |
1147 return err, pos | |
1148 end | |
1149 end | |
1150 elseif kind == "execute" then | |
1151 if type(options.confirm) ~= "string" and type(options.confirm) ~= "boolean" and type(options.confirm) ~= "nil" then | |
1152 return '"confirm" must be a string, boolean, or nil', position | |
1153 end | |
1154 end | |
1155 if options.icon and type(options.icon) ~= "string" then | |
1156 return'"icon" must be a string', position | |
1157 end | |
1158 if options.iconWidth or options.iconHeight then | |
1159 if type(options.iconWidth) ~= "number" or type(options.iconHeight) ~= "number" then | |
1160 return '"iconHeight" and "iconWidth" must be numbers', position | |
1161 end | |
1162 end | |
1163 if options.iconCoordLeft or options.iconCoordRight or options.iconCoordTop or options.iconCoordBottom then | |
1164 if type(options.iconCoordLeft) ~= "number" or type(options.iconCoordRight) ~= "number" or type(options.iconCoordTop) ~= "number" or type(options.iconCoordBottom) ~= "number" then | |
1165 return '"iconCoordLeft", "iconCoordRight", "iconCoordTop", and "iconCoordBottom" must be numbers', position | |
1166 end | |
1167 end | |
1168 end | |
1169 | |
1170 local validatedOptions | |
1171 | |
1172 local values | |
1173 local mysort_args | |
1174 local mysort | |
1175 local othersort | |
1176 local othersort_validate | |
1177 | |
1178 local baseFunc, currentLevel | |
1179 | |
1180 local function confirmPopup(message, func, ...) | |
1181 if not StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] then | |
1182 StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] = {} | |
1183 end | |
1184 local t = StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] | |
1185 for k in pairs(t) do | |
1186 t[k] = nil | |
1187 end | |
1188 t.text = message | |
1189 t.button1 = ACCEPT or "Accept" | |
1190 t.button2 = CANCEL or "Cancel" | |
1191 t.OnAccept = function() | |
1192 func(unpack(t)) | |
1193 end | |
1194 for i = 1, select('#', ...) do | |
1195 t[i] = select(i, ...) | |
1196 end | |
1197 t.timeout = 0 | |
1198 t.whileDead = 1 | |
1199 t.hideOnEscape = 1 | |
1200 | |
1201 Dewdrop:Close() | |
1202 StaticPopup_Show("DEWDROP20_CONFIRM_DIALOG") | |
1203 end | |
1204 | |
1205 | |
1206 local function getMethod(settingname, handler, v, methodName, ...) -- "..." is simply returned straight out cause you can't do "a,b,c = 111,f(),222" | |
1207 assert(v and type(v)=="table") | |
1208 assert(methodName and type(methodName)=="string") | |
1209 | |
1210 local method = v[methodName] | |
1211 if type(method)=="function" then | |
1212 return method, ... | |
1213 elseif type(method)=="string" then | |
1214 if not handler then | |
1215 Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method) | |
1216 elseif not handler[method] then | |
1217 Dewdrop:error("[%s] 'handler' method %q not defined", tostring(settingname), method) | |
1218 end | |
1219 return handler[method], handler, ... | |
1220 end | |
1221 | |
1222 Dewdrop:error("[%s] Missing %q directive", tostring(settingname), methodName) | |
1223 end | |
1224 | |
1225 local function callMethod(settingname, handler, v, methodName, ...) | |
1226 assert(v and type(v)=="table") | |
1227 assert(methodName and type(methodName)=="string") | |
1228 | |
1229 local method = v[methodName] | |
1230 if type(method)=="function" then | |
1231 local success, ret,ret2,ret3,ret4 = pcall(v[methodName], ...) | |
1232 if not success then | |
1233 geterrorhandler()(ret) | |
1234 return nil | |
1235 end | |
1236 return ret,ret2,ret3,ret4 | |
1237 | |
1238 elseif type(method)=="string" then | |
1239 | |
1240 local neg = method:match("^~(.-)$") | |
1241 if neg then | |
1242 method = neg | |
1243 end | |
1244 if not handler then | |
1245 Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method) | |
1246 elseif not handler[method] then | |
1247 Dewdrop:error("[%s] 'handler' (%q) method %q not defined", tostring(settingname), handler.name or "(unnamed)", method) | |
1248 end | |
1249 local success, ret,ret2,ret3,ret4 = pcall(handler[method], handler, ...) | |
1250 if not success then | |
1251 geterrorhandler()(ret) | |
1252 return nil | |
1253 end | |
1254 if neg then | |
1255 return not ret | |
1256 end | |
1257 return ret,ret2,ret3,ret4 | |
1258 elseif method == false then | |
1259 return nil | |
1260 end | |
1261 | |
1262 Dewdrop:error("[%s] Missing %q directive in %q", tostring(settingname), methodName, v.name or "(unnamed)") | |
1263 end | |
1264 | |
1265 local function skip1Nil(...) | |
1266 if select(1,...)==nil then | |
1267 return select(2,...) | |
1268 end | |
1269 return ... | |
1270 end | |
1271 | |
1272 function Dewdrop:FeedAceOptionsTable(options, difference) | |
1273 self:argCheck(options, 2, "table") | |
1274 self:argCheck(difference, 3, "nil", "number") | |
1275 if not currentLevel then | |
1276 self:error("Cannot call `FeedAceOptionsTable' outside of a Dewdrop declaration") | |
1277 end | |
1278 if not difference then | |
1279 difference = 0 | |
1280 end | |
1281 if not validatedOptions then | |
1282 validatedOptions = {} | |
1283 end | |
1284 if not validatedOptions[options] then | |
1285 local err, position = validateOptions(options) | |
1286 | |
1287 if err then | |
1288 if position then | |
1289 Dewdrop:error(position .. ": " .. err) | |
1290 else | |
1291 Dewdrop:error(err) | |
1292 end | |
1293 end | |
1294 | |
1295 validatedOptions[options] = true | |
1296 end | |
1297 local level = levels[currentLevel] | |
1298 if not level then | |
1299 self:error("Improper level given") | |
1300 end | |
1301 if not values then | |
1302 values = {} | |
1303 else | |
1304 for k,v in pairs(values) do | |
1305 values[k] = nil | |
1306 end | |
1307 end | |
1308 | |
1309 local current = level | |
1310 while current do -- this traverses from higher level numbers to lower, building "values" with leaf nodes first and trunk nodes later | |
1311 if current.num == difference + 1 then | |
1312 break | |
1313 end | |
1314 table.insert(values, current.value) | |
1315 current = levels[current.num - 1] | |
1316 end | |
1317 | |
1318 local realOptions = options | |
1319 local handler = options.handler | |
1320 local passTable | |
1321 local passValue | |
1322 while #values > 0 do -- This loop traverses values from the END (trunk nodes first, then onto leaf nodes) | |
1323 if options.pass then | |
1324 if options.get and options.set then | |
1325 passTable = options | |
1326 elseif not passTable then | |
1327 passTable = options | |
1328 end | |
1329 else | |
1330 passTable = nil | |
1331 end | |
1332 local value = table.remove(values) | |
1333 options = options.args and options.args[value] | |
1334 if not options then | |
1335 return | |
1336 end | |
1337 handler = options.handler or handler | |
1338 passValue = passTable and value or nil | |
1339 end | |
1340 | |
1341 if options.type == "group" then | |
1342 local hidden = options.hidden | |
1343 if type(hidden) == "function" or type(hidden) == "string" then | |
1344 hidden = callMethod(options.name or "(options root)", handler, options, "hidden", options.passValue) or false | |
1345 end | |
1346 if hidden then | |
1347 return | |
1348 end | |
1349 local disabled = options.disabled | |
1350 if type(disabled) == "function" or type(disabled) == "string" then | |
1351 disabled = callMethod(options.name or "(options root)", handler, options, "disabled", options.passValue) or false | |
1352 end | |
1353 if disabled then | |
1354 self:AddLine( | |
1355 'text', DISABLED, | |
1356 'disabled', true | |
1357 ) | |
1358 return | |
1359 end | |
1360 for k in pairs(options.args) do | |
1361 table.insert(values, k) | |
1362 end | |
1363 if options.pass then | |
1364 if options.get and options.set then | |
1365 passTable = options | |
1366 elseif not passTable then | |
1367 passTable = options | |
1368 end | |
1369 else | |
1370 passTable = nil | |
1371 end | |
1372 if not mysort then | |
1373 mysort = function(a, b) | |
1374 local alpha, bravo = mysort_args[a], mysort_args[b] | |
1375 local alpha_order = alpha.order or 100 | |
1376 local bravo_order = bravo.order or 100 | |
1377 local alpha_name = alpha.guiName or alpha.name | |
1378 local bravo_name = bravo.guiName or bravo.name | |
1379 if alpha_order == bravo_order then | |
1380 if not alpha_name then | |
1381 return bravo_name | |
1382 elseif not bravo_name then | |
1383 return false | |
1384 else | |
1385 return alpha_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < bravo_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() | |
1386 end | |
1387 else | |
1388 if alpha_order < 0 then | |
1389 if bravo_order > 0 then | |
1390 return false | |
1391 end | |
1392 else | |
1393 if bravo_order < 0 then | |
1394 return true | |
1395 end | |
1396 end | |
1397 return alpha_order < bravo_order | |
1398 end | |
1399 end | |
1400 end | |
1401 mysort_args = options.args | |
1402 table.sort(values, mysort) | |
1403 mysort_args = nil | |
1404 local hasBoth = #values >= 1 and (options.args[values[1]].order or 100) > 0 and (options.args[values[#values]].order or 100) < 0 | |
1405 local last_order = 1 | |
1406 for _,k in ipairs(values) do | |
1407 local v = options.args[k] | |
1408 local handler = v.handler or handler | |
1409 if hasBoth and last_order > 0 and (v.order or 100) < 0 then | |
1410 hasBoth = false | |
1411 self:AddLine() | |
1412 end | |
1413 local hidden, disabled = v.guiHidden or v.hidden, v.disabled | |
1414 | |
1415 if type(hidden) == "function" or type(hidden) == "string" then | |
1416 hidden = callMethod(k, handler, v, "hidden", v.passValue) or false | |
1417 end | |
1418 if not hidden then | |
1419 if type(disabled) == "function" or type(disabled) == "string" then | |
1420 disabled = callMethod(k, handler, v, "disabled", v.passValue) or false | |
1421 end | |
1422 local name = (v.guiIconOnly and v.icon) and "" or (v.guiName or v.name) | |
1423 local desc = v.guiDesc or v.desc | |
1424 local iconHeight = v.iconHeight or 16 | |
1425 local iconWidth = v.iconWidth or 16 | |
1426 local iconCoordLeft = v.iconCoordLeft | |
1427 local iconCoordRight = v.iconCoordRight | |
1428 local iconCoordBottom = v.iconCoordBottom | |
1429 local iconCoordTop = v.iconCoordTop | |
1430 local tooltipTitle, tooltipText | |
1431 tooltipTitle = name | |
1432 if name ~= desc then | |
1433 tooltipText = desc | |
1434 end | |
1435 if type(v.usage) == "string" and v.usage:trim():len() > 0 then | |
1436 if tooltipText then | |
1437 tooltipText = tooltipText .. "\n\n" .. USAGE_TOOLTIP:format(v.usage) | |
1438 else | |
1439 tooltipText = USAGE_TOOLTIP:format(v.usage) | |
1440 end | |
1441 end | |
1442 local v_p = passTable | |
1443 if not v_p or (v.type ~= "execute" and v.get and v.set) or (v.type == "execute" and v.func) then | |
1444 v_p = v | |
1445 end | |
1446 local passValue = v.passValue or (v_p~=v and k) or nil | |
1447 if v.type == "toggle" then | |
1448 local checked = callMethod(name, handler, v_p, "get", passValue) or false | |
1449 local checked_arg = checked | |
1450 if type(v_p.get)=="string" and v_p.get:match("^~") then | |
1451 checked_arg = not checked | |
1452 end | |
1453 local func, arg1, arg2, arg3 = getMethod(name, handler, v_p, "set", skip1Nil(passValue, not checked_arg)) | |
1454 if v.guiNameIsMap then | |
1455 checked = checked and true or false | |
1456 name = tostring(v.map and v.map[checked]):gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") | |
1457 tooltipTitle = name | |
1458 checked = true--nil | |
1459 end | |
1460 self:AddLine( | |
1461 'text', name, | |
1462 'checked', checked, | |
1463 'isRadio', v.isRadio, | |
1464 'func', func, | |
1465 'arg1', arg1, | |
1466 'arg2', arg2, | |
1467 'arg3', arg3, | |
1468 'disabled', disabled, | |
1469 'tooltipTitle', tooltipTitle, | |
1470 'tooltipText', tooltipText | |
1471 ) | |
1472 elseif v.type == "execute" then | |
1473 local func, arg1, arg2, arg3, arg4 | |
1474 local confirm = v.confirm | |
1475 if confirm == true then | |
1476 confirm = DEFAULT_CONFIRM_MESSAGE:format(tooltipText or tooltipTitle) | |
1477 func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue) | |
1478 elseif type(confirm) == "string" then | |
1479 func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue) | |
1480 else | |
1481 func,arg1,arg2 = getMethod(name, handler, v_p, "func", passValue) | |
1482 end | |
1483 self:AddLine( | |
1484 'text', name, | |
1485 'checked', checked, | |
1486 'func', func, | |
1487 'arg1', arg1, | |
1488 'arg2', arg2, | |
1489 'arg3', arg3, | |
1490 'arg4', arg4, | |
1491 'disabled', disabled, | |
1492 'tooltipTitle', tooltipTitle, | |
1493 'tooltipText', tooltipText, | |
1494 'icon', v.icon, | |
1495 'iconHeight', iconHeight, | |
1496 'iconWidth', iconWidth, | |
1497 'iconCoordLeft', iconCoordLeft, | |
1498 'iconCoordRight', iconCoordRight, | |
1499 'iconCoordTop', iconCoordTop, | |
1500 'iconCoordBottom', iconCoordBottom | |
1501 ) | |
1502 elseif v.type == "range" then | |
1503 local sliderValue | |
1504 sliderValue = callMethod(name, handler, v_p, "get", passValue) or 0 | |
1505 local sliderFunc, sliderArg1, sliderArg2 = getMethod(name, handler, v_p, "set", passValue) | |
1506 if tooltipText then | |
1507 tooltipText = format("%s\n\n%s", tooltipText, RANGE_TOOLTIP) | |
1508 else | |
1509 tooltipText = RANGE_TOOLTIP | |
1510 end | |
1511 self:AddLine( | |
1512 'text', name, | |
1513 'hasArrow', true, | |
1514 'hasSlider', true, | |
1515 'sliderMin', v.min or 0, | |
1516 'sliderMax', v.max or 1, | |
1517 'sliderStep', v.step or 0, | |
1518 'sliderBigStep', v.bigStep or nil, | |
1519 'sliderIsPercent', v.isPercent or false, | |
1520 'sliderValue', sliderValue, | |
1521 'sliderFunc', sliderFunc, | |
1522 'sliderArg1', sliderArg1, | |
1523 'sliderArg2', sliderArg2, | |
1524 'fromAceOptions', true, | |
1525 'disabled', disabled, | |
1526 'tooltipTitle', tooltipTitle, | |
1527 'tooltipText', tooltipText, | |
1528 'icon', v.icon, | |
1529 'iconHeight', iconHeight, | |
1530 'iconWidth', iconWidth, | |
1531 'iconCoordLeft', iconCoordLeft, | |
1532 'iconCoordRight', iconCoordRight, | |
1533 'iconCoordTop', iconCoordTop, | |
1534 'iconCoordBottom', iconCoordBottom | |
1535 ) | |
1536 elseif v.type == "color" then | |
1537 local r,g,b,a = callMethod(name, handler, v_p, "get", passValue) | |
1538 if not r then | |
1539 r,g,b,a = 0,0,0,0 | |
1540 end | |
1541 local colorFunc, colorArg1, colorArg2 = getMethod(name, handler, v_p, "set", passValue) | |
1542 self:AddLine( | |
1543 'text', name, | |
1544 'hasArrow', true, | |
1545 'hasColorSwatch', true, | |
1546 'r', r, | |
1547 'g', g, | |
1548 'b', b, | |
1549 'opacity', v.hasAlpha and a or nil, | |
1550 'hasOpacity', v.hasAlpha, | |
1551 'colorFunc', colorFunc, | |
1552 'colorArg1', colorArg1, | |
1553 'colorArg2', colorArg2, | |
1554 'disabled', disabled, | |
1555 'tooltipTitle', tooltipTitle, | |
1556 'tooltipText', tooltipText | |
1557 ) | |
1558 elseif v.type == "text" then | |
1559 if type(v.validate) == "table" then | |
1560 local func,arg1,arg2 | |
1561 if v.onClick then | |
1562 func,arg1,arg2 = getMethod(name, handler, v, "onClick", passValue) | |
1563 end | |
1564 local checked | |
1565 if v.isChecked then | |
1566 checked = callMethod(name, handler, v, "isChecked", passValue) or false | |
1567 end | |
1568 self:AddLine( | |
1569 'text', name, | |
1570 'hasArrow', true, | |
1571 'value', k, | |
1572 'func', func, | |
1573 'arg1', arg1, | |
1574 'arg2', arg2, | |
1575 'mouseoverUnderline', func and true or nil, | |
1576 'disabled', disabled, | |
1577 'checked', checked, | |
1578 'tooltipTitle', tooltipTitle, | |
1579 'tooltipText', tooltipText, | |
1580 'icon', v.icon, | |
1581 'iconHeight', iconHeight, | |
1582 'iconWidth', iconWidth, | |
1583 'iconCoordLeft', iconCoordLeft, | |
1584 'iconCoordRight', iconCoordRight, | |
1585 'iconCoordTop', iconCoordTop, | |
1586 'iconCoordBottom', iconCoordBottom | |
1587 ) | |
1588 else | |
1589 local editBoxText | |
1590 editBoxText = callMethod(name, handler, v_p, "get", passValue) or "" | |
1591 local editBoxFunc, editBoxArg1, editBoxArg2 = getMethod(name, handler, v_p, "set", passValue) | |
1592 | |
1593 local editBoxValidateFunc, editBoxValidateArg1 | |
1594 | |
1595 if v.validate and v.validate ~= "keybinding" then | |
1596 if v.validate == "keybinding" then | |
1597 if tooltipText then | |
1598 tooltipText = format("%s\n\n%s", tooltipText, RESET_KEYBINDING_DESC) | |
1599 else | |
1600 tooltipText = RESET_KEYBINDING_DESC | |
1601 end | |
1602 else | |
1603 editBoxValidateFunc, editBoxValidateArg1 = getMethod(name, handler, v, "validate") -- no passvalue! | |
1604 end | |
1605 end | |
1606 | |
1607 self:AddLine( | |
1608 'text', name, | |
1609 'hasArrow', true, | |
1610 'icon', v.icon, | |
1611 'iconHeight', iconHeight, | |
1612 'iconWidth', iconWidth, | |
1613 'iconCoordLeft', iconCoordLeft, | |
1614 'iconCoordRight', iconCoordRight, | |
1615 'iconCoordTop', iconCoordTop, | |
1616 'iconCoordBottom', iconCoordBottom, | |
1617 'hasEditBox', true, | |
1618 'editBoxText', editBoxText, | |
1619 'editBoxFunc', editBoxFunc, | |
1620 'editBoxArg1', editBoxArg1, | |
1621 'editBoxArg2', editBoxArg2, | |
1622 'editBoxValidateFunc', editBoxValidateFunc, | |
1623 'editBoxValidateArg1', editBoxValidateArg1, | |
1624 'editBoxIsKeybinding', v.validate == "keybinding", | |
1625 'editBoxKeybindingOnly', v.keybindingOnly, | |
1626 'editBoxKeybindingExcept', v.keybindingExcept, | |
1627 'disabled', disabled, | |
1628 'tooltipTitle', tooltipTitle, | |
1629 'tooltipText', tooltipText | |
1630 ) | |
1631 end | |
1632 elseif v.type == "group" then | |
1633 local func,arg1,arg2 | |
1634 if v.onClick then | |
1635 func,arg1,arg2 = getMethod(name, handler, v, "onClick", passValue) | |
1636 end | |
1637 local checked | |
1638 if v.isChecked then | |
1639 checked = callMethod(name, handler, v, "isChecked", passValue) or false | |
1640 end | |
1641 self:AddLine( | |
1642 'text', name, | |
1643 'hasArrow', true, | |
1644 'value', k, | |
1645 'func', func, | |
1646 'arg1', arg1, | |
1647 'arg2', arg2, | |
1648 'mouseoverUnderline', func and true or nil, | |
1649 'disabled', disabled, | |
1650 'checked', checked, | |
1651 'tooltipTitle', tooltipTitle, | |
1652 'tooltipText', tooltipText, | |
1653 'icon', v.icon, | |
1654 'iconHeight', iconHeight, | |
1655 'iconWidth', iconWidth, | |
1656 'iconCoordLeft', iconCoordLeft, | |
1657 'iconCoordRight', iconCoordRight, | |
1658 'iconCoordTop', iconCoordTop, | |
1659 'iconCoordBottom', iconCoordBottom | |
1660 ) | |
1661 elseif v.type == "header" then | |
1662 if name == "" or not name then | |
1663 self:AddLine( | |
1664 'isTitle', true, | |
1665 'icon', v.icon, | |
1666 'iconHeight', iconHeight, | |
1667 'iconWidth', iconWidth, | |
1668 'iconCoordLeft', iconCoordLeft, | |
1669 'iconCoordRight', iconCoordRight, | |
1670 'iconCoordTop', iconCoordTop, | |
1671 'iconCoordBottom', iconCoordBottom | |
1672 ) | |
1673 else | |
1674 self:AddLine( | |
1675 'text', name, | |
1676 'isTitle', true, | |
1677 'icon', v.icon, | |
1678 'iconHeight', iconHeight, | |
1679 'iconWidth', iconWidth, | |
1680 'iconCoordLeft', iconCoordLeft, | |
1681 'iconCoordRight', iconCoordRight, | |
1682 'iconCoordTop', iconCoordTop, | |
1683 'iconCoordBottom', iconCoordBottom | |
1684 ) | |
1685 end | |
1686 end | |
1687 end | |
1688 last_order = v.order or 100 | |
1689 end | |
1690 elseif options.type == "text" and type(options.validate) == "table" then | |
1691 local current | |
1692 local options_p = passTable | |
1693 if not options_p or (options.get and options.set) then | |
1694 options_p = options | |
1695 passTable = nil | |
1696 passValue = nil | |
1697 end | |
1698 local multiToggle = options.multiToggle | |
1699 local passValue = options.passValue or passValue | |
1700 if not multiToggle then | |
1701 current = callMethod(k, handler, options_p, "get", passValue) | |
1702 end | |
1703 local indexed = true | |
1704 for k,v in pairs(options.validate) do | |
1705 if type(k) ~= "number" then | |
1706 indexed = false | |
1707 end | |
1708 table.insert(values, k) | |
1709 end | |
1710 if not indexed then | |
1711 if not othersort then | |
1712 othersort = function(alpha, bravo) | |
1713 return othersort_validate[alpha]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < othersort_validate[bravo]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() | |
1714 end | |
1715 end | |
1716 othersort_validate = options.validate | |
1717 table.sort(values, othersort) | |
1718 othersort_validate = nil | |
1719 end | |
1720 for _,k in ipairs(values) do | |
1721 local v = options.validate[k] | |
1722 if type(k) == "number" then | |
1723 k = v | |
1724 end | |
1725 local func, arg1, arg2, arg3, arg4 = getMethod(k, handler, options_p, "set", skip1Nil(passValue, k)) | |
1726 local checked | |
1727 if multiToggle then | |
1728 checked = callMethod(k, handler, options_p, "get", skip1Nil(passValue, k)) or false | |
1729 if arg2 == nil then | |
1730 arg2 = not checked | |
1731 elseif arg3 == nil then | |
1732 arg3 = not checked | |
1733 else | |
1734 arg4 = not checked | |
1735 end | |
1736 else | |
1737 checked = (k == current or (type(k) == "string" and type(current) == "string" and k:lower() == current:lower())) | |
1738 if checked then | |
1739 func, arg1, arg2, arg3, arg4 = nil, nil, nil, nil, nil | |
1740 end | |
1741 end | |
1742 local tooltipTitle | |
1743 local tooltipText | |
1744 if options.validateDesc then | |
1745 tooltipTitle = v | |
1746 tooltipText = options.validateDesc[k] | |
1747 else | |
1748 tooltipTitle = options.guiName or options.name | |
1749 tooltipText = v | |
1750 end | |
1751 self:AddLine( | |
1752 'text', v, | |
1753 'func', func, | |
1754 'arg1', arg1, | |
1755 'arg2', arg2, | |
1756 'arg3', arg3, | |
1757 'arg4', arg4, | |
1758 'isRadio', not multiToggle, | |
1759 'checked', checked, | |
1760 'tooltipTitle', tooltipTitle, | |
1761 'tooltipText', tooltipText | |
1762 ) | |
1763 end | |
1764 for k in pairs(values) do | |
1765 values[k] = nil | |
1766 end | |
1767 else | |
1768 return false | |
1769 end | |
1770 return true | |
1771 end | |
1772 | |
1773 function Dewdrop:FeedTable(s, difference) | |
1774 self:argCheck(s, 2, "table") | |
1775 self:argCheck(difference, 3, "nil", "number") | |
1776 if not currentLevel then | |
1777 self:error("Cannot call `FeedTable' outside of a Dewdrop declaration") | |
1778 end | |
1779 if not difference then | |
1780 difference = 0 | |
1781 end | |
1782 local level = levels[currentLevel] | |
1783 if not level then | |
1784 self:error("Improper level given") | |
1785 end | |
1786 if not values then | |
1787 values = {} | |
1788 else | |
1789 for k,v in pairs(values) do | |
1790 values[k] = nil | |
1791 end | |
1792 end | |
1793 local t = s.subMenu and s or {subMenu = s} | |
1794 local current = level | |
1795 while current do | |
1796 if current.num == difference + 1 then | |
1797 break | |
1798 end | |
1799 table.insert(values, current.value) | |
1800 current = levels[current.num - 1] | |
1801 end | |
1802 | |
1803 while #values > 0 do | |
1804 local value = table.remove(values) | |
1805 t = t.subMenu and t.subMenu[value] | |
1806 if not t then | |
1807 return | |
1808 end | |
1809 end | |
1810 | |
1811 if t.subMenu or current.num == 1 then | |
1812 for k in pairs(t.subMenu) do | |
1813 table.insert(values, k) | |
1814 end | |
1815 table.sort(values) | |
1816 for _,k in ipairs(values) do | |
1817 local argTable = {"value", k} | |
1818 for key, val in pairs(t.subMenu[k]) do | |
1819 table.insert(argTable, key) | |
1820 table.insert(argTable, val) | |
1821 end | |
1822 self:AddLine(unpack(argTable)) | |
1823 end | |
1824 for k in pairs(values) do | |
1825 values[k] = nil | |
1826 end | |
1827 return false | |
1828 end | |
1829 return true | |
1830 end | |
1831 | |
1832 function Refresh(self, level) | |
1833 if type(level) == "number" then | |
1834 level = levels[level] | |
1835 end | |
1836 if not level then | |
1837 return | |
1838 end | |
1839 if baseFunc then | |
1840 Clear(self, level) | |
1841 currentLevel = level.num | |
1842 if type(baseFunc) == "table" then | |
1843 if currentLevel == 1 then | |
1844 local handler = baseFunc.handler | |
1845 if handler then | |
1846 local name = tostring(handler) | |
1847 if not name:find('^table:') and not handler.hideMenuTitle then | |
1848 name = name:gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") | |
1849 self:AddLine( | |
1850 'text', name, | |
1851 'isTitle', true | |
1852 ) | |
1853 end | |
1854 end | |
1855 -- elseif level.parentText then | |
1856 -- self:AddLine( | |
1857 -- 'text', level.parentText, | |
1858 -- 'tooltipTitle', level.parentTooltipTitle, | |
1859 -- 'tooltipText', level.parentTooltipText, | |
1860 -- 'tooltipFunc', level.parentTooltipFunc, | |
1861 -- 'isTitle', true | |
1862 -- ) | |
1863 end | |
1864 self:FeedAceOptionsTable(baseFunc) | |
1865 if currentLevel == 1 then | |
1866 self:AddLine( | |
1867 'text', CLOSE, | |
1868 'tooltipTitle', CLOSE, | |
1869 'tooltipText', CLOSE_DESC, | |
1870 'closeWhenClicked', true | |
1871 ) | |
1872 end | |
1873 else | |
1874 -- if level.parentText then | |
1875 -- self:AddLine( | |
1876 -- 'text', level.parentText, | |
1877 -- 'tooltipTitle', level.parentTooltipTitle, | |
1878 -- 'tooltipText', level.parentTooltipText, | |
1879 -- 'tooltipFunc', level.parentTooltipFunc, | |
1880 -- 'isTitle', true | |
1881 -- ) | |
1882 -- end | |
1883 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) | |
1884 end | |
1885 currentLevel = nil | |
1886 CheckSize(self, level) | |
1887 end | |
1888 end | |
1889 | |
1890 function Dewdrop:Refresh(level) | |
1891 self:argCheck(level, 2, "number", "nil") | |
1892 if not level then | |
1893 for k,v in pairs(levels) do | |
1894 Refresh(self, v) | |
1895 end | |
1896 else | |
1897 Refresh(self, levels[level]) | |
1898 end | |
1899 end | |
1900 | |
1901 function OpenSlider(self, parent) | |
1902 if not sliderFrame then | |
1903 sliderFrame = CreateFrame("Frame", nil, nil) | |
1904 sliderFrame:SetWidth(100) | |
1905 sliderFrame:SetHeight(170) | |
1906 sliderFrame:SetScale(UIParent:GetScale()) | |
1907 sliderFrame:SetBackdrop(tmp( | |
1908 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", | |
1909 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", | |
1910 'tile', true, | |
1911 'insets', tmp2( | |
1912 'left', 5, | |
1913 'right', 5, | |
1914 'top', 5, | |
1915 'bottom', 5 | |
1916 ), | |
1917 'tileSize', 16, | |
1918 'edgeSize', 16 | |
1919 )) | |
1920 sliderFrame:SetFrameStrata("FULLSCREEN_DIALOG") | |
1921 if sliderFrame.SetTopLevel then | |
1922 sliderFrame:SetTopLevel(true) | |
1923 end | |
1924 sliderFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) | |
1925 sliderFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) | |
1926 sliderFrame:EnableMouse(true) | |
1927 sliderFrame:EnableMouseWheel(true) | |
1928 sliderFrame:Hide() | |
1929 sliderFrame:SetPoint("CENTER", UIParent, "CENTER") | |
1930 local slider = CreateFrame("Slider", nil, sliderFrame) | |
1931 sliderFrame.slider = slider | |
1932 slider:SetOrientation("VERTICAL") | |
1933 slider:SetMinMaxValues(0, 1) | |
1934 slider:SetValueStep(0.000000001) | |
1935 slider:SetValue(0.5) | |
1936 slider:SetWidth(16) | |
1937 slider:SetHeight(128) | |
1938 slider:SetPoint("LEFT", sliderFrame, "LEFT", 15, 0) | |
1939 slider:SetBackdrop(tmp( | |
1940 'bgFile', "Interface\\Buttons\\UI-SliderBar-Background", | |
1941 'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border", | |
1942 'tile', true, | |
1943 'edgeSize', 8, | |
1944 'tileSize', 8, | |
1945 'insets', tmp2( | |
1946 'left', 3, | |
1947 'right', 3, | |
1948 'top', 3, | |
1949 'bottom', 3 | |
1950 ) | |
1951 )) | |
1952 local texture = slider:CreateTexture() | |
1953 slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical") | |
1954 local text = slider:CreateFontString(nil, "ARTWORK") | |
1955 sliderFrame.topText = text | |
1956 text:SetFontObject(GameFontGreenSmall) | |
1957 text:SetText("100%") | |
1958 text:SetPoint("BOTTOM", slider, "TOP") | |
1959 local text = slider:CreateFontString(nil, "ARTWORK") | |
1960 sliderFrame.bottomText = text | |
1961 text:SetFontObject(GameFontGreenSmall) | |
1962 text:SetText("0%") | |
1963 text:SetPoint("TOP", slider, "BOTTOM") | |
1964 local editBox = CreateFrame("EditBox", nil, sliderFrame) | |
1965 sliderFrame.currentText = editBox | |
1966 editBox:SetFontObject(ChatFontNormal) | |
1967 editBox:SetHeight(13) | |
1968 editBox:SetPoint("RIGHT", sliderFrame, "RIGHT", -16, 0) | |
1969 editBox:SetPoint("LEFT", slider, "RIGHT", 12, 0) | |
1970 editBox:SetText("50%") | |
1971 editBox:SetJustifyH("CENTER") | |
1972 | |
1973 local width = editBox:GetWidth()/2 + 10 | |
1974 local left = editBox:CreateTexture(nil, "BACKGROUND") | |
1975 left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left") | |
1976 left:SetTexCoord(0, width / 256, 0, 1) | |
1977 left:SetWidth(width) | |
1978 left:SetHeight(32) | |
1979 left:SetPoint("LEFT", editBox, "LEFT", -10, 0) | |
1980 local right = editBox:CreateTexture(nil, "BACKGROUND") | |
1981 right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right") | |
1982 right:SetTexCoord(1 - width / 256, 1, 0, 1) | |
1983 right:SetWidth(width) | |
1984 right:SetHeight(32) | |
1985 right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0) | |
1986 | |
1987 local changed = false | |
1988 local inside = false | |
1989 slider:SetScript("OnValueChanged", function() | |
1990 if sliderFrame.changing then | |
1991 return | |
1992 end | |
1993 changed = true | |
1994 local done = false | |
1995 if sliderFrame.parent and sliderFrame.parent.sliderFunc then | |
1996 local min = sliderFrame.parent.sliderMin or 0 | |
1997 local max = sliderFrame.parent.sliderMax or 1 | |
1998 local step | |
1999 if sliderFrame.fineStep then | |
2000 step = sliderFrame.parent.sliderStep or (max - min) / 100 | |
2001 else | |
2002 step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100 | |
2003 end | |
2004 local value = (1 - slider:GetValue()) * (max - min) + min | |
2005 if step > 0 then | |
2006 value = math.floor((value - min) / step + 0.5) * step + min | |
2007 if value > max then | |
2008 value = max | |
2009 elseif value < min then | |
2010 value = min | |
2011 end | |
2012 end | |
2013 if value == sliderFrame.lastValue then | |
2014 return | |
2015 end | |
2016 sliderFrame.lastValue = value | |
2017 local text = sliderFrame.parent.sliderFunc(getArgs(sliderFrame.parent, 'sliderArg', 1, value)) | |
2018 if sliderFrame.parent.fromAceOptions then | |
2019 text = nil | |
2020 elseif type(text) == "string" or type(text) == "number" then | |
2021 sliderFrame.currentText:SetText(text) | |
2022 done = true | |
2023 end | |
2024 end | |
2025 if not done then | |
2026 local min = sliderFrame.parent.sliderMin or 0 | |
2027 local max = sliderFrame.parent.sliderMax or 1 | |
2028 local step | |
2029 if sliderFrame.fineStep then | |
2030 step = sliderFrame.parent.sliderStep or (max - min) / 100 | |
2031 else | |
2032 step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100 | |
2033 end | |
2034 local value = (1 - slider:GetValue()) * (max - min) + min | |
2035 if step > 0 then | |
2036 value = math.floor((value - min) / step + 0.5) * step + min | |
2037 if value > max then | |
2038 value = max | |
2039 elseif value < min then | |
2040 value = min | |
2041 end | |
2042 end | |
2043 if sliderFrame.parent.sliderIsPercent then | |
2044 sliderFrame.currentText:SetText(string.format("%.0f%%", value * 100)) | |
2045 else | |
2046 if step < 0.1 then | |
2047 sliderFrame.currentText:SetText(string.format("%.2f", value)) | |
2048 elseif step < 1 then | |
2049 sliderFrame.currentText:SetText(string.format("%.1f", value)) | |
2050 else | |
2051 sliderFrame.currentText:SetText(string.format("%.0f", value)) | |
2052 end | |
2053 end | |
2054 end | |
2055 end) | |
2056 local function onEnter() | |
2057 StopCounting(self, sliderFrame.level) | |
2058 showGameTooltip(sliderFrame.parent) | |
2059 end | |
2060 local function onLeave() | |
2061 GameTooltip:Hide() | |
2062 end | |
2063 sliderFrame:SetScript("OnEnter", onEnter) | |
2064 sliderFrame:SetScript("OnLeave", function() | |
2065 GameTooltip:Hide() | |
2066 if changed then | |
2067 local parent = sliderFrame.parent | |
2068 local sliderFunc = parent.sliderFunc | |
2069 for i = 1, sliderFrame.level - 1 do | |
2070 Refresh(self, levels[i]) | |
2071 end | |
2072 local newParent | |
2073 for _,button in ipairs(levels[sliderFrame.level-1].buttons) do | |
2074 if button.sliderFunc == sliderFunc then | |
2075 newParent = button | |
2076 break | |
2077 end | |
2078 end | |
2079 if newParent then | |
2080 OpenSlider(self, newParent) | |
2081 else | |
2082 sliderFrame:Hide() | |
2083 end | |
2084 end | |
2085 end) | |
2086 editBox:SetScript("OnEnter", onEnter) | |
2087 editBox:SetScript("OnLeave", onLeave) | |
2088 slider:SetScript("OnMouseDown", function() | |
2089 sliderFrame.mouseDown = true | |
2090 GameTooltip:Hide() | |
2091 end) | |
2092 slider:SetScript("OnMouseUp", function() | |
2093 sliderFrame.mouseDown = false | |
2094 if changed--[[ and not inside]] then | |
2095 local parent = sliderFrame.parent | |
2096 local sliderFunc = parent.sliderFunc | |
2097 for i = 1, sliderFrame.level - 1 do | |
2098 Refresh(self, levels[i]) | |
2099 end | |
2100 local newParent | |
2101 for _,button in ipairs(levels[sliderFrame.level-1].buttons) do | |
2102 if button.sliderFunc == sliderFunc then | |
2103 newParent = button | |
2104 break | |
2105 end | |
2106 end | |
2107 if newParent then | |
2108 OpenSlider(self, newParent) | |
2109 else | |
2110 sliderFrame:Hide() | |
2111 end | |
2112 end | |
2113 if inside then | |
2114 showGameTooltip(sliderFrame.parent) | |
2115 end | |
2116 end) | |
2117 slider:SetScript("OnEnter", function() | |
2118 inside = true | |
2119 StopCounting(self, sliderFrame.level) | |
2120 showGameTooltip(sliderFrame.parent) | |
2121 end) | |
2122 slider:SetScript("OnLeave", function() | |
2123 inside = false | |
2124 GameTooltip:Hide() | |
2125 if changed and not sliderFrame.mouseDown then | |
2126 local parent = sliderFrame.parent | |
2127 local sliderFunc = parent.sliderFunc | |
2128 for i = 1, sliderFrame.level - 1 do | |
2129 Refresh(self, levels[i]) | |
2130 end | |
2131 local newParent | |
2132 for _,button in ipairs(levels[sliderFrame.level-1].buttons) do | |
2133 if button.sliderFunc == sliderFunc then | |
2134 newParent = button | |
2135 break | |
2136 end | |
2137 end | |
2138 if newParent then | |
2139 OpenSlider(self, newParent) | |
2140 else | |
2141 sliderFrame:Hide() | |
2142 end | |
2143 | |
2144 changed = false | |
2145 end | |
2146 end) | |
2147 sliderFrame:SetScript("OnMouseWheel", function(t, a1) | |
2148 local arg1 = a1 or arg1 | |
2149 local up = arg1 > 0 | |
2150 | |
2151 local min = sliderFrame.parent.sliderMin or 0 | |
2152 local max = sliderFrame.parent.sliderMax or 1 | |
2153 local step = sliderFrame.parent.sliderStep or (max - min) / 100 | |
2154 if step <= 0 then | |
2155 step = (max - min) / 100 | |
2156 end | |
2157 | |
2158 local value = (1 - slider:GetValue()) * (max - min) + min | |
2159 if up then | |
2160 value = value + step | |
2161 else | |
2162 value = value - step | |
2163 end | |
2164 if value > max then | |
2165 value = max | |
2166 elseif value < min then | |
2167 value = min | |
2168 end | |
2169 sliderFrame.fineStep = true | |
2170 if max<=min then | |
2171 slider:SetValue(0) | |
2172 else | |
2173 slider:SetValue(1 - (value - min) / (max - min)) | |
2174 end | |
2175 sliderFrame.fineStep = nil | |
2176 end) | |
2177 slider:SetScript("OnMouseWheel", sliderFrame:GetScript("OnMouseWheel")) | |
2178 editBox:SetScript("OnEnterPressed", function(t, a1) | |
2179 local value = editBox:GetNumber() | |
2180 | |
2181 if sliderFrame.parent.sliderIsPercent then | |
2182 value = value / 100 | |
2183 end | |
2184 | |
2185 local min = sliderFrame.parent.sliderMin or 0 | |
2186 local max = sliderFrame.parent.sliderMax or 1 | |
2187 | |
2188 if value > max then | |
2189 value = max | |
2190 elseif value < min then | |
2191 value = min | |
2192 end | |
2193 sliderFrame.fineStep = true | |
2194 if max <= min then | |
2195 slider:SetValue(0) | |
2196 else | |
2197 slider:SetValue(1 - (value - min) / (max - min)) | |
2198 end | |
2199 sliderFrame.fineStep = nil | |
2200 | |
2201 StartCounting(self, sliderFrame.level) | |
2202 end) | |
2203 editBox:SetScript("OnEscapePressed", function() | |
2204 self:Close(sliderFrame.level) | |
2205 StartCounting(self, sliderFrame.level) | |
2206 end) | |
2207 editBox:SetAutoFocus(false) | |
2208 end | |
2209 sliderFrame.parent = parent | |
2210 sliderFrame.level = parent.level.num + 1 | |
2211 sliderFrame.parentValue = parent.level.value | |
2212 sliderFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3) | |
2213 sliderFrame.slider:SetFrameLevel(sliderFrame:GetFrameLevel() + 1) | |
2214 sliderFrame.currentText:SetFrameLevel(sliderFrame:GetFrameLevel() + 1) | |
2215 sliderFrame.currentText:ClearFocus() | |
2216 sliderFrame.changing = true | |
2217 if not parent.sliderMin or not parent.sliderMax then | |
2218 return | |
2219 end | |
2220 | |
2221 if parent.arrow then | |
2222 -- parent.arrow:SetVertexColor(0.2, 0.6, 0) | |
2223 -- parent.arrow:SetHeight(24) | |
2224 -- parent.arrow:SetWidth(24) | |
2225 parent.selected = true | |
2226 parent.highlight:Show() | |
2227 end | |
2228 | |
2229 sliderFrame:SetClampedToScreen(false) | |
2230 if not parent.sliderValue then | |
2231 parent.sliderValue = (parent.sliderMin + parent.sliderMax) / 2 | |
2232 end | |
2233 if parent.sliderMax <= parent.sliderMin then | |
2234 sliderFrame.slider:SetValue(0) | |
2235 else | |
2236 sliderFrame.slider:SetValue(1 - (parent.sliderValue - parent.sliderMin) / (parent.sliderMax - parent.sliderMin)) | |
2237 end | |
2238 sliderFrame.changing = false | |
2239 sliderFrame.bottomText:SetText(parent.sliderMinText or "0") | |
2240 sliderFrame.topText:SetText(parent.sliderMaxText or "1") | |
2241 local text | |
2242 if parent.sliderFunc and not parent.fromAceOptions then | |
2243 text = parent.sliderFunc(getArgs(parent, 'sliderArg', 1, parent.sliderValue)) | |
2244 end | |
2245 if type(text) == "number" or type(text) == "string" then | |
2246 sliderFrame.currentText:SetText(text) | |
2247 elseif parent.sliderIsPercent then | |
2248 sliderFrame.currentText:SetText(string.format("%.0f%%", parent.sliderValue * 100)) | |
2249 else | |
2250 if parent.sliderStep < 0.1 then | |
2251 sliderFrame.currentText:SetText(string.format("%.2f", parent.sliderValue)) | |
2252 elseif parent.sliderStep < 1 then | |
2253 sliderFrame.currentText:SetText(string.format("%.1f", parent.sliderValue)) | |
2254 else | |
2255 sliderFrame.currentText:SetText(string.format("%.0f", parent.sliderValue)) | |
2256 end | |
2257 end | |
2258 | |
2259 | |
2260 sliderFrame.lastValue = parent.sliderValue | |
2261 | |
2262 local level = parent.level | |
2263 sliderFrame:Show() | |
2264 sliderFrame:ClearAllPoints() | |
2265 if level.lastDirection == "RIGHT" then | |
2266 if level.lastVDirection == "DOWN" then | |
2267 sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) | |
2268 else | |
2269 sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) | |
2270 end | |
2271 else | |
2272 if level.lastVDirection == "DOWN" then | |
2273 sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) | |
2274 else | |
2275 sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) | |
2276 end | |
2277 end | |
2278 local dirty | |
2279 if level.lastDirection == "RIGHT" then | |
2280 if sliderFrame:GetRight() > GetScreenWidth() then | |
2281 level.lastDirection = "LEFT" | |
2282 dirty = true | |
2283 end | |
2284 elseif sliderFrame:GetLeft() < 0 then | |
2285 level.lastDirection = "RIGHT" | |
2286 dirty = true | |
2287 end | |
2288 if level.lastVDirection == "DOWN" then | |
2289 if sliderFrame:GetBottom() < 0 then | |
2290 level.lastVDirection = "UP" | |
2291 dirty = true | |
2292 end | |
2293 elseif sliderFrame:GetTop() > GetScreenWidth() then | |
2294 level.lastVDirection = "DOWN" | |
2295 dirty = true | |
2296 end | |
2297 if dirty then | |
2298 sliderFrame:ClearAllPoints() | |
2299 if level.lastDirection == "RIGHT" then | |
2300 if level.lastVDirection == "DOWN" then | |
2301 sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) | |
2302 else | |
2303 sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) | |
2304 end | |
2305 else | |
2306 if level.lastVDirection == "DOWN" then | |
2307 sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) | |
2308 else | |
2309 sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) | |
2310 end | |
2311 end | |
2312 end | |
2313 local left, bottom = sliderFrame:GetLeft(), sliderFrame:GetBottom() | |
2314 sliderFrame:ClearAllPoints() | |
2315 sliderFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) | |
2316 if mod(level.num, 5) == 0 then | |
2317 local left, bottom = level:GetLeft(), level:GetBottom() | |
2318 level:ClearAllPoints() | |
2319 level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) | |
2320 end | |
2321 sliderFrame:SetClampedToScreen(true) | |
2322 end | |
2323 | |
2324 function OpenEditBox(self, parent) | |
2325 if not editBoxFrame then | |
2326 editBoxFrame = CreateFrame("Frame", nil, nil) | |
2327 editBoxFrame:SetWidth(200) | |
2328 editBoxFrame:SetHeight(40) | |
2329 editBoxFrame:SetScale(UIParent:GetScale()) | |
2330 editBoxFrame:SetBackdrop(tmp( | |
2331 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", | |
2332 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", | |
2333 'tile', true, | |
2334 'insets', tmp2( | |
2335 'left', 5, | |
2336 'right', 5, | |
2337 'top', 5, | |
2338 'bottom', 5 | |
2339 ), | |
2340 'tileSize', 16, | |
2341 'edgeSize', 16 | |
2342 )) | |
2343 editBoxFrame:SetFrameStrata("FULLSCREEN_DIALOG") | |
2344 if editBoxFrame.SetTopLevel then | |
2345 editBoxFrame:SetTopLevel(true) | |
2346 end | |
2347 editBoxFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) | |
2348 editBoxFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) | |
2349 editBoxFrame:EnableMouse(true) | |
2350 editBoxFrame:EnableMouseWheel(true) | |
2351 editBoxFrame:Hide() | |
2352 editBoxFrame:SetPoint("CENTER", UIParent, "CENTER") | |
2353 | |
2354 local editBox = CreateFrame("EditBox", nil, editBoxFrame) | |
2355 editBoxFrame.editBox = editBox | |
2356 editBox:SetFontObject(ChatFontNormal) | |
2357 editBox:SetWidth(160) | |
2358 editBox:SetHeight(13) | |
2359 editBox:SetPoint("CENTER", editBoxFrame, "CENTER", 0, 0) | |
2360 | |
2361 local left = editBox:CreateTexture(nil, "BACKGROUND") | |
2362 left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left") | |
2363 left:SetTexCoord(0, 100 / 256, 0, 1) | |
2364 left:SetWidth(100) | |
2365 left:SetHeight(32) | |
2366 left:SetPoint("LEFT", editBox, "LEFT", -10, 0) | |
2367 local right = editBox:CreateTexture(nil, "BACKGROUND") | |
2368 right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right") | |
2369 right:SetTexCoord(156/256, 1, 0, 1) | |
2370 right:SetWidth(100) | |
2371 right:SetHeight(32) | |
2372 right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0) | |
2373 | |
2374 editBox:SetScript("OnEnterPressed", function() | |
2375 if editBoxFrame.parent and editBoxFrame.parent.editBoxValidateFunc then | |
2376 local t = editBox.realText or editBox:GetText() or "" | |
2377 local result = editBoxFrame.parent.editBoxValidateFunc(getArgs(editBoxFrame.parent, 'editBoxValidateArg', 1, t)) | |
2378 if not result then | |
2379 UIErrorsFrame:AddMessage(VALIDATION_ERROR, 1, 0, 0) | |
2380 return | |
2381 end | |
2382 end | |
2383 if editBoxFrame.parent and editBoxFrame.parent.editBoxFunc then | |
2384 local t | |
2385 if editBox.realText ~= "NONE" then | |
2386 t = editBox.realText or editBox:GetText() or "" | |
2387 end | |
2388 editBoxFrame.parent.editBoxFunc(getArgs(editBoxFrame.parent, 'editBoxArg', 1, t)) | |
2389 end | |
2390 self:Close(editBoxFrame.level) | |
2391 for i = 1, editBoxFrame.level - 1 do | |
2392 Refresh(self, levels[i]) | |
2393 end | |
2394 StartCounting(self, editBoxFrame.level-1) | |
2395 end) | |
2396 editBox:SetScript("OnEscapePressed", function() | |
2397 self:Close(editBoxFrame.level) | |
2398 StartCounting(self, editBoxFrame.level-1) | |
2399 end) | |
2400 editBox:SetScript("OnReceiveDrag", function(this) | |
2401 if GetCursorInfo then | |
2402 local type, alpha, bravo = GetCursorInfo() | |
2403 local text | |
2404 if type == "spell" then | |
2405 text = GetSpellName(alpha, bravo) | |
2406 elseif type == "item" then | |
2407 text = bravo | |
2408 end | |
2409 if not text then | |
2410 return | |
2411 end | |
2412 ClearCursor() | |
2413 editBox:SetText(text) | |
2414 end | |
2415 end) | |
2416 local changing = false | |
2417 local skipNext = false | |
2418 | |
2419 function editBox:SpecialSetText(text) | |
2420 local oldText = editBox:GetText() or "" | |
2421 if not text then | |
2422 text = "" | |
2423 end | |
2424 if text ~= oldText then | |
2425 changing = true | |
2426 self:SetText(tostring(text)) | |
2427 changing = false | |
2428 skipNext = true | |
2429 end | |
2430 end | |
2431 | |
2432 editBox:SetScript("OnTextChanged", function() | |
2433 if skipNext then | |
2434 skipNext = false | |
2435 elseif not changing and editBoxFrame.parent and editBoxFrame.parent.editBoxChangeFunc then | |
2436 local t | |
2437 if editBox.realText ~= "NONE" then | |
2438 t = editBox.realText or editBox:GetText() or "" | |
2439 end | |
2440 local text = editBoxFrame.parent.editBoxChangeFunc(getArgs(editBoxFrame.parent, 'editBoxChangeArg', 1, t)) | |
2441 if text then | |
2442 editBox:SpecialSetText(text) | |
2443 end | |
2444 end | |
2445 end) | |
2446 editBoxFrame:SetScript("OnEnter", function() | |
2447 StopCounting(self, editBoxFrame.level) | |
2448 showGameTooltip(editBoxFrame.parent) | |
2449 end) | |
2450 editBoxFrame:SetScript("OnLeave", function() | |
2451 GameTooltip:Hide() | |
2452 end) | |
2453 editBox:SetScript("OnEnter", function() | |
2454 StopCounting(self, editBoxFrame.level) | |
2455 showGameTooltip(editBoxFrame.parent) | |
2456 end) | |
2457 editBox:SetScript("OnLeave", function() | |
2458 GameTooltip:Hide() | |
2459 end) | |
2460 editBoxFrame:SetScript("OnKeyDown", function(this, a1) | |
2461 if not editBox.keybinding then | |
2462 return | |
2463 end | |
2464 local arg1 = a1 or arg1 | |
2465 local screenshotKey = GetBindingKey("SCREENSHOT") | |
2466 if screenshotKey and arg1 == screenshotKey then | |
2467 Screenshot() | |
2468 return | |
2469 end | |
2470 | |
2471 if arg1 == "LeftButton" then | |
2472 arg1 = "BUTTON1" | |
2473 elseif arg1 == "RightButton" then | |
2474 arg1 = "BUTTON2" | |
2475 elseif arg1 == "MiddleButton" then | |
2476 arg1 = "BUTTON3" | |
2477 elseif arg1 == "Button4" then | |
2478 arg1 = "BUTTON4" | |
2479 elseif arg1 == "Button5" then | |
2480 arg1 = "BUTTON5" | |
2481 end | |
2482 if arg1 == "UNKNOWN" then | |
2483 return | |
2484 elseif arg1 == "SHIFT" or arg1 == "CTRL" or arg1 == "ALT" then | |
2485 return | |
2486 elseif arg1 == "ENTER" then | |
2487 if editBox.keybindingOnly and not editBox.keybindingOnly[editBox.realText] then | |
2488 return editBox:GetScript("OnEscapePressed")() | |
2489 elseif editBox.keybindingExcept and editBox.keybindingExcept[editBox.realText] then | |
2490 return editBox:GetScript("OnEscapePressed")() | |
2491 else | |
2492 return editBox:GetScript("OnEnterPressed")() | |
2493 end | |
2494 elseif arg1 == "ESCAPE" then | |
2495 if editBox.realText == "NONE" then | |
2496 return editBox:GetScript("OnEscapePressed")() | |
2497 else | |
2498 editBox:SpecialSetText(NONE or "NONE") | |
2499 editBox.realText = "NONE" | |
2500 return | |
2501 end | |
2502 elseif editBox.keybindingOnly and not editBox.keybindingOnly[arg1] then | |
2503 return | |
2504 elseif editBox.keybindingExcept and editBox.keybindingExcept[arg1] then | |
2505 return | |
2506 end | |
2507 local s = GetBindingText(arg1, "KEY_") | |
2508 if s == "BUTTON1" then | |
2509 s = KEY_BUTTON1 | |
2510 elseif s == "BUTTON2" then | |
2511 s = KEY_BUTTON2 | |
2512 end | |
2513 local real = arg1 | |
2514 if IsShiftKeyDown() then | |
2515 s = "Shift-" .. s | |
2516 real = "SHIFT-" .. real | |
2517 end | |
2518 if IsControlKeyDown() then | |
2519 s = "Ctrl-" .. s | |
2520 real = "CTRL-" .. real | |
2521 end | |
2522 if IsAltKeyDown() then | |
2523 s = "Alt-" .. s | |
2524 real = "ALT-" .. real | |
2525 end | |
2526 if editBox:GetText() ~= s then | |
2527 editBox:SpecialSetText("-") | |
2528 editBox:SpecialSetText(s) | |
2529 editBox.realText = real | |
2530 return editBox:GetScript("OnTextChanged")() | |
2531 end | |
2532 end) | |
2533 editBoxFrame:SetScript("OnMouseDown", editBoxFrame:GetScript("OnKeyDown")) | |
2534 editBox:SetScript("OnMouseDown", function(this, ...) | |
2535 if GetCursorInfo and (CursorHasItem() or CursorHasSpell()) then | |
2536 return editBox:GetScript("OnReceiveDrag")(this, ...) | |
2537 end | |
2538 return editBoxFrame:GetScript("OnKeyDown")(this, ...) | |
2539 end) | |
2540 editBoxFrame:SetScript("OnMouseWheel", function(t, a1) | |
2541 local arg1 = a1 or arg1 | |
2542 local up = arg1 > 0 | |
2543 arg1 = up and "MOUSEWHEELUP" or "MOUSEWHEELDOWN" | |
2544 return editBoxFrame:GetScript("OnKeyDown")(t or this, arg1) | |
2545 end) | |
2546 editBox:SetScript("OnMouseWheel", editBoxFrame:GetScript("OnMouseWheel")) | |
2547 end | |
2548 editBoxFrame.parent = parent | |
2549 editBoxFrame.level = parent.level.num + 1 | |
2550 editBoxFrame.parentValue = parent.level.value | |
2551 editBoxFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3) | |
2552 editBoxFrame.editBox:SetFrameLevel(editBoxFrame:GetFrameLevel() + 1) | |
2553 editBoxFrame.editBox.realText = nil | |
2554 editBoxFrame:SetClampedToScreen(false) | |
2555 | |
2556 editBoxFrame.editBox:SpecialSetText("") | |
2557 if parent.editBoxIsKeybinding then | |
2558 local s = parent.editBoxText | |
2559 if s == "" then | |
2560 s = "NONE" | |
2561 end | |
2562 editBoxFrame.editBox.realText = s | |
2563 if s and s ~= "NONE" then | |
2564 local alpha,bravo = s:match("^(.+)%-(.+)$") | |
2565 if not bravo then | |
2566 alpha = nil | |
2567 bravo = s | |
2568 end | |
2569 bravo = GetBindingText(bravo, "KEY_") | |
2570 if alpha then | |
2571 editBoxFrame.editBox:SpecialSetText(alpha:upper() .. "-" .. bravo) | |
2572 else | |
2573 editBoxFrame.editBox:SpecialSetText(bravo) | |
2574 end | |
2575 else | |
2576 editBoxFrame.editBox:SpecialSetText(NONE or "NONE") | |
2577 end | |
2578 else | |
2579 editBoxFrame.editBox:SpecialSetText(parent.editBoxText) | |
2580 end | |
2581 | |
2582 editBoxFrame.editBox.keybinding = parent.editBoxIsKeybinding | |
2583 editBoxFrame.editBox.keybindingOnly = parent.editBoxKeybindingOnly | |
2584 editBoxFrame.editBox.keybindingExcept = parent.editBoxKeybindingExcept | |
2585 editBoxFrame.editBox:EnableKeyboard(not parent.editBoxIsKeybinding) | |
2586 editBoxFrame:EnableKeyboard(parent.editBoxIsKeybinding) | |
2587 | |
2588 if parent.arrow then | |
2589 -- parent.arrow:SetVertexColor(0.2, 0.6, 0) | |
2590 -- parent.arrow:SetHeight(24) | |
2591 -- parent.arrow:SetWidth(24) | |
2592 parent.selected = true | |
2593 parent.highlight:Show() | |
2594 end | |
2595 | |
2596 local level = parent.level | |
2597 editBoxFrame:Show() | |
2598 editBoxFrame:ClearAllPoints() | |
2599 if level.lastDirection == "RIGHT" then | |
2600 if level.lastVDirection == "DOWN" then | |
2601 editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) | |
2602 else | |
2603 editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) | |
2604 end | |
2605 else | |
2606 if level.lastVDirection == "DOWN" then | |
2607 editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) | |
2608 else | |
2609 editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) | |
2610 end | |
2611 end | |
2612 local dirty | |
2613 if level.lastDirection == "RIGHT" then | |
2614 if editBoxFrame:GetRight() > GetScreenWidth() then | |
2615 level.lastDirection = "LEFT" | |
2616 dirty = true | |
2617 end | |
2618 elseif editBoxFrame:GetLeft() < 0 then | |
2619 level.lastDirection = "RIGHT" | |
2620 dirty = true | |
2621 end | |
2622 if level.lastVDirection == "DOWN" then | |
2623 if editBoxFrame:GetBottom() < 0 then | |
2624 level.lastVDirection = "UP" | |
2625 dirty = true | |
2626 end | |
2627 elseif editBoxFrame:GetTop() > GetScreenWidth() then | |
2628 level.lastVDirection = "DOWN" | |
2629 dirty = true | |
2630 end | |
2631 if dirty then | |
2632 editBoxFrame:ClearAllPoints() | |
2633 if level.lastDirection == "RIGHT" then | |
2634 if level.lastVDirection == "DOWN" then | |
2635 editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) | |
2636 else | |
2637 editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) | |
2638 end | |
2639 else | |
2640 if level.lastVDirection == "DOWN" then | |
2641 editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) | |
2642 else | |
2643 editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) | |
2644 end | |
2645 end | |
2646 end | |
2647 local left, bottom = editBoxFrame:GetLeft(), editBoxFrame:GetBottom() | |
2648 editBoxFrame:ClearAllPoints() | |
2649 editBoxFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) | |
2650 if mod(level.num, 5) == 0 then | |
2651 local left, bottom = level:GetLeft(), level:GetBottom() | |
2652 level:ClearAllPoints() | |
2653 level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) | |
2654 end | |
2655 editBoxFrame:SetClampedToScreen(true) | |
2656 end | |
2657 | |
2658 function Dewdrop:EncodeKeybinding(text) | |
2659 if text == nil or text == "NONE" then | |
2660 return nil | |
2661 end | |
2662 text = tostring(text):upper() | |
2663 local shift, ctrl, alt | |
2664 local modifier | |
2665 while true do | |
2666 if text == "-" then | |
2667 break | |
2668 end | |
2669 modifier, text = strsplit('-', text, 2) | |
2670 if text then | |
2671 if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then | |
2672 return false | |
2673 end | |
2674 if modifier == "SHIFT" then | |
2675 if shift then | |
2676 return false | |
2677 end | |
2678 shift = true | |
2679 end | |
2680 if modifier == "CTRL" then | |
2681 if ctrl then | |
2682 return false | |
2683 end | |
2684 ctrl = true | |
2685 end | |
2686 if modifier == "ALT" then | |
2687 if alt then | |
2688 return false | |
2689 end | |
2690 alt = true | |
2691 end | |
2692 else | |
2693 text = modifier | |
2694 break | |
2695 end | |
2696 end | |
2697 if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:len() == 0 or text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] and text ~= "BUTTON1" and text ~= "BUTTON2" then | |
2698 return false | |
2699 end | |
2700 local s = GetBindingText(text, "KEY_") | |
2701 if s == "BUTTON1" then | |
2702 s = KEY_BUTTON1 | |
2703 elseif s == "BUTTON2" then | |
2704 s = KEY_BUTTON2 | |
2705 end | |
2706 if shift then | |
2707 s = "Shift-" .. s | |
2708 end | |
2709 if ctrl then | |
2710 s = "Ctrl-" .. s | |
2711 end | |
2712 if alt then | |
2713 s = "Alt-" .. s | |
2714 end | |
2715 return s | |
2716 end | |
2717 | |
2718 function Dewdrop:IsOpen(parent) | |
2719 self:argCheck(parent, 2, "table", "string", "nil") | |
2720 return levels[1] and levels[1]:IsShown() and (not parent or parent == levels[1].parent or parent == levels[1]:GetParent()) | |
2721 end | |
2722 | |
2723 function Dewdrop:GetOpenedParent() | |
2724 return (levels[1] and levels[1]:IsShown()) and (levels[1].parent or levels[1]:GetParent()) | |
2725 end | |
2726 | |
2727 function Open(self, parent, func, level, value, point, relativePoint, cursorX, cursorY) | |
2728 self:Close(level) | |
2729 if DewdropLib then | |
2730 local d = DewdropLib:GetInstance('1.0') | |
2731 local ret, val = pcall(d, IsOpen, d) | |
2732 if ret and val then | |
2733 DewdropLib:GetInstance('1.0'):Close() | |
2734 end | |
2735 end | |
2736 if type(parent) == "table" then | |
2737 parent:GetCenter() | |
2738 end | |
2739 local frame = AcquireLevel(self, level) | |
2740 if level == 1 then | |
2741 frame.lastDirection = "RIGHT" | |
2742 frame.lastVDirection = "DOWN" | |
2743 else | |
2744 frame.lastDirection = levels[level - 1].lastDirection | |
2745 frame.lastVDirection = levels[level - 1].lastVDirection | |
2746 end | |
2747 frame:SetFrameStrata("FULLSCREEN_DIALOG") | |
2748 frame:ClearAllPoints() | |
2749 frame.parent = parent | |
2750 frame:SetPoint("LEFT", UIParent, "RIGHT", 10000, 0) | |
2751 frame:Show() | |
2752 if level == 1 then | |
2753 baseFunc = func | |
2754 end | |
2755 levels[level].value = value | |
2756 -- levels[level].parentText = parent.text and parent.text:GetText() or nil | |
2757 -- levels[level].parentTooltipTitle = parent.tooltipTitle | |
2758 -- levels[level].parentTooltipText = parent.tooltipText | |
2759 -- levels[level].parentTooltipFunc = parent.tooltipFunc | |
2760 if type(parent) == "table" and parent.arrow then | |
2761 -- parent.arrow:SetVertexColor(0.2, 0.6, 0) | |
2762 -- parent.arrow:SetHeight(24) | |
2763 -- parent.arrow:SetWidth(24) | |
2764 parent.selected = true | |
2765 parent.highlight:Show() | |
2766 end | |
2767 relativePoint = relativePoint or point | |
2768 Refresh(self, levels[level]) | |
2769 if point or (cursorX and cursorY) then | |
2770 frame:ClearAllPoints() | |
2771 if cursorX and cursorY then | |
2772 local curX, curY = GetScaledCursorPosition() | |
2773 if curY < GetScreenHeight() / 2 then | |
2774 point, relativePoint = "BOTTOM", "BOTTOM" | |
2775 else | |
2776 point, relativePoint = "TOP", "TOP" | |
2777 end | |
2778 if curX < GetScreenWidth() / 2 then | |
2779 point, relativePoint = point .. "LEFT", relativePoint .. "RIGHT" | |
2780 else | |
2781 point, relativePoint = point .. "RIGHT", relativePoint .. "LEFT" | |
2782 end | |
2783 end | |
2784 frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint) | |
2785 if cursorX and cursorY then | |
2786 local left = frame:GetLeft() | |
2787 local width = frame:GetWidth() | |
2788 local bottom = frame:GetBottom() | |
2789 local height = frame:GetHeight() | |
2790 local curX, curY = GetScaledCursorPosition() | |
2791 frame:ClearAllPoints() | |
2792 relativePoint = relativePoint or point | |
2793 if point == "BOTTOM" or point == "TOP" then | |
2794 if curX < GetScreenWidth() / 2 then | |
2795 point = point .. "LEFT" | |
2796 else | |
2797 point = point .. "RIGHT" | |
2798 end | |
2799 elseif point == "CENTER" then | |
2800 if curX < GetScreenWidth() / 2 then | |
2801 point = "LEFT" | |
2802 else | |
2803 point = "RIGHT" | |
2804 end | |
2805 end | |
2806 local xOffset, yOffset = 0, 0 | |
2807 if curY > GetScreenHeight() / 2 then | |
2808 yOffset = -height | |
2809 end | |
2810 if curX > GetScreenWidth() / 2 then | |
2811 xOffset = -width | |
2812 end | |
2813 frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left + xOffset, curY - bottom + yOffset) | |
2814 if level == 1 then | |
2815 frame.lastDirection = "RIGHT" | |
2816 end | |
2817 elseif cursorX then | |
2818 local left = frame:GetLeft() | |
2819 local width = frame:GetWidth() | |
2820 local curX, curY = GetScaledCursorPosition() | |
2821 frame:ClearAllPoints() | |
2822 relativePoint = relativePoint or point | |
2823 if point == "BOTTOM" or point == "TOP" then | |
2824 if curX < GetScreenWidth() / 2 then | |
2825 point = point .. "LEFT" | |
2826 else | |
2827 point = point .. "RIGHT" | |
2828 end | |
2829 elseif point == "CENTER" then | |
2830 if curX < GetScreenWidth() / 2 then | |
2831 point = "LEFT" | |
2832 else | |
2833 point = "RIGHT" | |
2834 end | |
2835 end | |
2836 frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left - width / 2, 0) | |
2837 if level == 1 then | |
2838 frame.lastDirection = "RIGHT" | |
2839 end | |
2840 elseif cursorY then | |
2841 local bottom = frame:GetBottom() | |
2842 local height = frame:GetHeight() | |
2843 local curX, curY = GetScaledCursorPosition() | |
2844 frame:ClearAllPoints() | |
2845 relativePoint = relativePoint or point | |
2846 if point == "LEFT" or point == "RIGHT" then | |
2847 if curX < GetScreenHeight() / 2 then | |
2848 point = point .. "BOTTOM" | |
2849 else | |
2850 point = point .. "TOP" | |
2851 end | |
2852 elseif point == "CENTER" then | |
2853 if curX < GetScreenHeight() / 2 then | |
2854 point = "BOTTOM" | |
2855 else | |
2856 point = "TOP" | |
2857 end | |
2858 end | |
2859 frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, 0, curY - bottom - height / 2) | |
2860 if level == 1 then | |
2861 frame.lastDirection = "DOWN" | |
2862 end | |
2863 end | |
2864 if (strsub(point, 1, 3) ~= strsub(relativePoint, 1, 3)) then | |
2865 if frame:GetBottom() < 0 then | |
2866 local point, parent, relativePoint, x, y = frame:GetPoint(1) | |
2867 local change = GetScreenHeight() - frame:GetTop() | |
2868 local otherChange = -frame:GetBottom() | |
2869 if otherChange < change then | |
2870 change = otherChange | |
2871 end | |
2872 frame:SetPoint(point, parent, relativePoint, x, y + change) | |
2873 elseif frame:GetTop() > GetScreenHeight() then | |
2874 local point, parent, relativePoint, x, y = frame:GetPoint(1) | |
2875 local change = GetScreenHeight() - frame:GetTop() | |
2876 local otherChange = -frame:GetBottom() | |
2877 if otherChange < change then | |
2878 change = otherChange | |
2879 end | |
2880 frame:SetPoint(point, parent, relativePoint, x, y + change) | |
2881 end | |
2882 end | |
2883 end | |
2884 CheckDualMonitor(self, frame) | |
2885 frame:SetClampedToScreen(true) | |
2886 frame:SetClampedToScreen(false) | |
2887 StartCounting(self, level) | |
2888 end | |
2889 | |
2890 function Dewdrop:IsRegistered(parent) | |
2891 self:argCheck(parent, 2, "table", "string") | |
2892 return not not self.registry[parent] | |
2893 end | |
2894 | |
2895 function Dewdrop:Register(parent, ...) | |
2896 self:argCheck(parent, 2, "table", "string") | |
2897 if self.registry[parent] then | |
2898 self:Unregister(parent) | |
2899 end | |
2900 local info = new(...) | |
2901 if type(info.children) == "table" then | |
2902 local err, position = validateOptions(info.children) | |
2903 | |
2904 if err then | |
2905 if position then | |
2906 Dewdrop:error(position .. ": " .. err) | |
2907 else | |
2908 Dewdrop:error(err) | |
2909 end | |
2910 end | |
2911 end | |
2912 self.registry[parent] = info | |
2913 if not info.dontHook and not self.onceRegistered[parent] and type(parent) == "table" then | |
2914 if parent:HasScript("OnMouseUp") then | |
2915 local script = parent:GetScript("OnMouseUp") | |
2916 parent:SetScript("OnMouseUp", function(this, ...) | |
2917 if script then | |
2918 script(this, ...) | |
2919 end | |
2920 if arg1 == "RightButton" and self.registry[parent] then | |
2921 if self:IsOpen(parent) then | |
2922 self:Close() | |
2923 else | |
2924 self:Open(parent) | |
2925 end | |
2926 end | |
2927 end) | |
2928 end | |
2929 if parent:HasScript("OnMouseDown") then | |
2930 local script = parent:GetScript("OnMouseDown") | |
2931 parent:SetScript("OnMouseDown", function(this, ...) | |
2932 if script then | |
2933 script(this, ...) | |
2934 end | |
2935 if self.registry[parent] then | |
2936 self:Close() | |
2937 end | |
2938 end) | |
2939 end | |
2940 end | |
2941 self.onceRegistered[parent] = true | |
2942 end | |
2943 | |
2944 function Dewdrop:Unregister(parent) | |
2945 self:argCheck(parent, 2, "table", "string") | |
2946 self.registry[parent] = nil | |
2947 end | |
2948 | |
2949 function Dewdrop:Open(parent, ...) | |
2950 self:argCheck(parent, 2, "table", "string") | |
2951 local info | |
2952 local k1 = ... | |
2953 if type(k1) == "table" and k1[0] and k1.IsFrameType and self.registry[k1] then | |
2954 info = tmp(select(2, ...)) | |
2955 for k,v in pairs(self.registry[k1]) do | |
2956 if info[k] == nil then | |
2957 info[k] = v | |
2958 end | |
2959 end | |
2960 else | |
2961 info = tmp(...) | |
2962 if self.registry[parent] then | |
2963 for k,v in pairs(self.registry[parent]) do | |
2964 if info[k] == nil then | |
2965 info[k] = v | |
2966 end | |
2967 end | |
2968 end | |
2969 end | |
2970 local point = info.point | |
2971 local relativePoint = info.relativePoint | |
2972 local cursorX = info.cursorX | |
2973 local cursorY = info.cursorY | |
2974 if type(point) == "function" then | |
2975 local b | |
2976 point, b = point(parent) | |
2977 if b then | |
2978 relativePoint = b | |
2979 end | |
2980 end | |
2981 if type(relativePoint) == "function" then | |
2982 relativePoint = relativePoint(parent) | |
2983 end | |
2984 Open(self, parent, info.children, 1, nil, point, relativePoint, cursorX, cursorY) | |
2985 end | |
2986 | |
2987 function Clear(self, level) | |
2988 if level then | |
2989 if level.buttons then | |
2990 for i = #level.buttons, 1, -1 do | |
2991 ReleaseButton(self, level, i) | |
2992 end | |
2993 end | |
2994 end | |
2995 end | |
2996 | |
2997 function Dewdrop:Close(level) | |
2998 if DropDownList1:IsShown() then | |
2999 DropDownList1:Hide() | |
3000 end | |
3001 if DewdropLib then | |
3002 local d = DewdropLib:GetInstance('1.0') | |
3003 local ret, val = pcall(d, IsOpen, d) | |
3004 if ret and val then | |
3005 DewdropLib:GetInstance('1.0'):Close() | |
3006 end | |
3007 end | |
3008 self:argCheck(level, 2, "number", "nil") | |
3009 if not level then | |
3010 level = 1 | |
3011 end | |
3012 if level == 1 and levels[level] then | |
3013 levels[level].parented = false | |
3014 end | |
3015 if level > 1 and levels[level-1].buttons then | |
3016 local buttons = levels[level-1].buttons | |
3017 for _,button in ipairs(buttons) do | |
3018 -- button.arrow:SetWidth(16) | |
3019 -- button.arrow:SetHeight(16) | |
3020 button.selected = nil | |
3021 button.highlight:Hide() | |
3022 -- button.arrow:SetVertexColor(1, 1, 1) | |
3023 end | |
3024 end | |
3025 if sliderFrame and sliderFrame.level >= level then | |
3026 sliderFrame:Hide() | |
3027 end | |
3028 if editBoxFrame and editBoxFrame.level >= level then | |
3029 editBoxFrame:Hide() | |
3030 end | |
3031 for i = level, #levels do | |
3032 Clear(self, levels[level]) | |
3033 levels[i]:Hide() | |
3034 levels[i]:ClearAllPoints() | |
3035 levels[i]:SetPoint("CENTER", UIParent, "CENTER") | |
3036 levels[i].value = nil | |
3037 end | |
3038 end | |
3039 | |
3040 function Dewdrop:AddSeparator(level) | |
3041 level = levels[level or currentLevel] | |
3042 if not level or not level.buttons then return; end | |
3043 | |
3044 local prevbutton = level.buttons[#level.buttons] | |
3045 if not prevbutton then return; end | |
3046 | |
3047 if prevbutton.disabled and prevbutton.text:GetText() == "" then | |
3048 return | |
3049 end | |
3050 self:AddLine("text", "", "disabled", true) | |
3051 end | |
3052 | |
3053 function Dewdrop:AddLine(...) | |
3054 local info = tmp(...) | |
3055 local level = info.level or currentLevel | |
3056 info.level = nil | |
3057 local button = AcquireButton(self, level) | |
3058 if not next(info) then | |
3059 info.disabled = true | |
3060 end | |
3061 button.disabled = info.isTitle or info.notClickable or info.disabled or (self.combat and info.secure) | |
3062 button.isTitle = info.isTitle | |
3063 button.notClickable = info.notClickable | |
3064 if button.isTitle then | |
3065 button.text:SetFontObject(GameFontNormalSmall) | |
3066 elseif button.notClickable then | |
3067 button.text:SetFontObject(GameFontHighlightSmall) | |
3068 elseif button.disabled then | |
3069 button.text:SetFontObject(GameFontDisableSmall) | |
3070 else | |
3071 button.text:SetFontObject(GameFontHighlightSmall) | |
3072 end | |
3073 if info.disabled then | |
3074 button.arrow:SetDesaturated(true) | |
3075 button.check:SetDesaturated(true) | |
3076 else | |
3077 button.arrow:SetDesaturated(false) | |
3078 button.check:SetDesaturated(false) | |
3079 end | |
3080 if info.textR and info.textG and info.textB then | |
3081 button.textR = info.textR | |
3082 button.textG = info.textG | |
3083 button.textB = info.textB | |
3084 button.text:SetTextColor(button.textR, button.textG, button.textB) | |
3085 else | |
3086 button.text:SetTextColor(button.text:GetFontObject():GetTextColor()) | |
3087 end | |
3088 button.notCheckable = info.notCheckable | |
3089 button.text:SetPoint("LEFT", button, "LEFT", button.notCheckable and 0 or 24, 0) | |
3090 button.checked = not info.notCheckable and info.checked | |
3091 button.mouseoverUnderline = info.mouseoverUnderline | |
3092 button.isRadio = not info.notCheckable and info.isRadio | |
3093 if info.isRadio then | |
3094 button.check:Show() | |
3095 button.check:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") | |
3096 if button.checked then | |
3097 button.check:SetTexCoord(0.25, 0.5, 0, 1) | |
3098 button.check:SetVertexColor(1, 1, 1, 1) | |
3099 else | |
3100 button.check:SetTexCoord(0, 0.25, 0, 1) | |
3101 button.check:SetVertexColor(1, 1, 1, 0.5) | |
3102 end | |
3103 button.radioHighlight:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") | |
3104 button.check:SetWidth(16) | |
3105 button.check:SetHeight(16) | |
3106 elseif info.icon then | |
3107 button.check:Show() | |
3108 button.check:SetTexture(info.icon) | |
3109 if info.iconWidth and info.iconHeight then | |
3110 button.check:SetWidth(info.iconWidth) | |
3111 button.check:SetHeight(info.iconHeight) | |
3112 else | |
3113 button.check:SetWidth(16) | |
3114 button.check:SetHeight(16) | |
3115 end | |
3116 if info.iconCoordLeft and info.iconCoordRight and info.iconCoordTop and info.iconCoordBottom then | |
3117 button.check:SetTexCoord(info.iconCoordLeft, info.iconCoordRight, info.iconCoordTop, info.iconCoordBottom) | |
3118 elseif info.icon:find("^Interface\\Icons\\") then | |
3119 button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95) | |
3120 else | |
3121 button.check:SetTexCoord(0, 1, 0, 1) | |
3122 end | |
3123 button.check:SetVertexColor(1, 1, 1, 1) | |
3124 else | |
3125 if button.checked then | |
3126 if info.checkIcon then | |
3127 button.check:SetWidth(16) | |
3128 button.check:SetHeight(16) | |
3129 button.check:SetTexture(info.checkIcon) | |
3130 if info.checkIcon:find("^Interface\\Icons\\") then | |
3131 button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95) | |
3132 else | |
3133 button.check:SetTexCoord(0, 1, 0, 1) | |
3134 end | |
3135 else | |
3136 button.check:SetWidth(24) | |
3137 button.check:SetHeight(24) | |
3138 button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") | |
3139 button.check:SetTexCoord(0, 1, 0, 1) | |
3140 end | |
3141 button.check:SetVertexColor(1, 1, 1, 1) | |
3142 else | |
3143 button.check:SetVertexColor(1, 1, 1, 0) | |
3144 end | |
3145 end | |
3146 if not button.disabled then | |
3147 button.func = info.func | |
3148 button.secure = info.secure | |
3149 end | |
3150 button.hasColorSwatch = info.hasColorSwatch | |
3151 if button.hasColorSwatch then | |
3152 button.colorSwatch:Show() | |
3153 button.colorSwatch.texture:Show() | |
3154 button.r = info.r or 1 | |
3155 button.g = info.g or 1 | |
3156 button.b = info.b or 1 | |
3157 button.colorSwatch.texture:SetVertexColor(button.r, button.g, button.b) | |
3158 button.checked = false | |
3159 button.func = nil | |
3160 button.colorFunc = info.colorFunc | |
3161 local i = 1 | |
3162 while true do | |
3163 local k = "colorArg" .. i | |
3164 local x = info[k] | |
3165 if x == nil then | |
3166 break | |
3167 end | |
3168 button[k] = x | |
3169 i = i + 1 | |
3170 end | |
3171 button.hasOpacity = info.hasOpacity | |
3172 button.opacity = info.opacity or 1 | |
3173 else | |
3174 button.colorSwatch:Hide() | |
3175 button.colorSwatch.texture:Hide() | |
3176 end | |
3177 button.hasArrow = not button.hasColorSwatch and (info.value or info.hasSlider or info.hasEditBox) and info.hasArrow | |
3178 if button.hasArrow then | |
3179 button.arrow:SetAlpha(1) | |
3180 if info.hasSlider then | |
3181 button.hasSlider = true | |
3182 button.sliderMin = info.sliderMin or 0 | |
3183 button.sliderMax = info.sliderMax or 1 | |
3184 button.sliderStep = info.sliderStep or 0 | |
3185 button.sliderBigStep = info.sliderBigStep or button.sliderStep | |
3186 if button.sliderBigStep < button.sliderStep then | |
3187 button.sliderBigStep = button.sliderStep | |
3188 end | |
3189 button.sliderIsPercent = info.sliderIsPercent and true or false | |
3190 button.sliderMinText = info.sliderMinText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMin * 100) or button.sliderMin | |
3191 button.sliderMaxText = info.sliderMaxText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMax * 100) or button.sliderMax | |
3192 button.sliderFunc = info.sliderFunc | |
3193 button.sliderValue = info.sliderValue | |
3194 button.fromAceOptions = info.fromAceOptions | |
3195 local i = 1 | |
3196 while true do | |
3197 local k = "sliderArg" .. i | |
3198 local x = info[k] | |
3199 if x == nil then | |
3200 break | |
3201 end | |
3202 button[k] = x | |
3203 i = i + 1 | |
3204 end | |
3205 elseif info.hasEditBox then | |
3206 button.hasEditBox = true | |
3207 button.editBoxText = info.editBoxText or "" | |
3208 button.editBoxFunc = info.editBoxFunc | |
3209 local i = 1 | |
3210 while true do | |
3211 local k = "editBoxArg" .. i | |
3212 local x = info[k] | |
3213 if x == nil then | |
3214 break | |
3215 end | |
3216 button[k] = x | |
3217 i = i + 1 | |
3218 end | |
3219 button.editBoxChangeFunc = info.editBoxChangeFunc | |
3220 local i = 1 | |
3221 while true do | |
3222 local k = "editBoxChangeArg" .. i | |
3223 local x = info[k] | |
3224 if x == nil then | |
3225 break | |
3226 end | |
3227 button[k] = x | |
3228 i = i + 1 | |
3229 end | |
3230 button.editBoxValidateFunc = info.editBoxValidateFunc | |
3231 local i = 1 | |
3232 while true do | |
3233 local k = "editBoxValidateArg" .. i | |
3234 local x = info[k] | |
3235 if x == nil then | |
3236 break | |
3237 end | |
3238 button[k] = x | |
3239 i = i + 1 | |
3240 end | |
3241 button.editBoxIsKeybinding = info.editBoxIsKeybinding | |
3242 button.editBoxKeybindingOnly = info.editBoxKeybindingOnly | |
3243 button.editBoxKeybindingExcept = info.editBoxKeybindingExcept | |
3244 else | |
3245 button.value = info.value | |
3246 local l = levels[level+1] | |
3247 if l and info.value == l.value then | |
3248 -- button.arrow:SetWidth(24) | |
3249 -- button.arrow:SetHeight(24) | |
3250 button.selected = true | |
3251 button.highlight:Show() | |
3252 end | |
3253 end | |
3254 else | |
3255 button.arrow:SetAlpha(0) | |
3256 end | |
3257 local i = 1 | |
3258 while true do | |
3259 local k = "arg" .. i | |
3260 local x = info[k] | |
3261 if x == nil then | |
3262 break | |
3263 end | |
3264 button[k] = x | |
3265 i = i + 1 | |
3266 end | |
3267 button.closeWhenClicked = info.closeWhenClicked | |
3268 button.textHeight = info.textHeight or UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT or 10 | |
3269 local font,_ = button.text:GetFont() | |
3270 button.text:SetFont(STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF", button.textHeight) | |
3271 button:SetHeight(button.textHeight + 6) | |
3272 button.text:SetPoint("RIGHT", button.arrow, (button.hasColorSwatch or button.hasArrow) and "LEFT" or "RIGHT") | |
3273 button.text:SetJustifyH(info.justifyH or "LEFT") | |
3274 button.text:SetText(info.text) | |
3275 button.tooltipTitle = info.tooltipTitle | |
3276 button.tooltipText = info.tooltipText | |
3277 button.tooltipFunc = info.tooltipFunc | |
3278 local i = 1 | |
3279 while true do | |
3280 local k = "tooltipArg" .. i | |
3281 local x = info[k] | |
3282 if x == nil then | |
3283 break | |
3284 end | |
3285 button[k] = x | |
3286 i = i + 1 | |
3287 end | |
3288 if not button.tooltipTitle and not button.tooltipText and not button.tooltipFunc and not info.isTitle then | |
3289 button.tooltipTitle = info.text | |
3290 end | |
3291 if type(button.func) == "string" then | |
3292 if type(button.arg1) ~= "table" then | |
3293 self:error("Cannot call method %q on a non-table", button.func) | |
3294 end | |
3295 if type(button.arg1[button.func]) ~= "function" then | |
3296 self:error("Method %q nonexistant.", button.func) | |
3297 end | |
3298 end | |
3299 end | |
3300 | |
3301 function Dewdrop:InjectAceOptionsTable(handler, options) | |
3302 self:argCheck(handler, 2, "table") | |
3303 self:argCheck(options, 3, "table") | |
3304 if tostring(options.type):lower() ~= "group" then | |
3305 self:error('Cannot inject into options table argument #3 if its type is not "group"') | |
3306 end | |
3307 if options.handler ~= nil and options.handler ~= handler then | |
3308 self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2") | |
3309 end | |
3310 options.handler = handler | |
3311 local class = handler.class | |
3312 if not AceLibrary:HasInstance("AceOO-2.0") or not class then | |
3313 if Rock then | |
3314 -- possible Rock object | |
3315 for mixin in Rock:IterateObjectMixins(handler) do | |
3316 if type(mixin.GetAceOptionsDataTable) == "function" then | |
3317 local t = mixin:GetAceOptionsDataTable(handler) | |
3318 for k,v in pairs(t) do | |
3319 if type(options.args) ~= "table" then | |
3320 options.args = {} | |
3321 end | |
3322 if options.args[k] == nil then | |
3323 options.args[k] = v | |
3324 end | |
3325 end | |
3326 end | |
3327 end | |
3328 end | |
3329 else | |
3330 -- Ace2 object | |
3331 while class and class ~= AceLibrary("AceOO-2.0").Class do | |
3332 if type(class.GetAceOptionsDataTable) == "function" then | |
3333 local t = class:GetAceOptionsDataTable(handler) | |
3334 for k,v in pairs(t) do | |
3335 if type(options.args) ~= "table" then | |
3336 options.args = {} | |
3337 end | |
3338 if options.args[k] == nil then | |
3339 options.args[k] = v | |
3340 end | |
3341 end | |
3342 end | |
3343 local mixins = class.mixins | |
3344 if mixins then | |
3345 for mixin in pairs(mixins) do | |
3346 if type(mixin.GetAceOptionsDataTable) == "function" then | |
3347 local t = mixin:GetAceOptionsDataTable(handler) | |
3348 for k,v in pairs(t) do | |
3349 if type(options.args) ~= "table" then | |
3350 options.args = {} | |
3351 end | |
3352 if options.args[k] == nil then | |
3353 options.args[k] = v | |
3354 end | |
3355 end | |
3356 end | |
3357 end | |
3358 end | |
3359 class = class.super | |
3360 end | |
3361 end | |
3362 return options | |
3363 end | |
3364 | |
3365 function Dewdrop:OnTooltipHide() | |
3366 if lastSetFont then | |
3367 if lastSetFont == normalFont then | |
3368 lastSetFont = nil | |
3369 return | |
3370 end | |
3371 fillRegionTmp(GameTooltip:GetRegions()) | |
3372 for i,v in ipairs(regionTmp) do | |
3373 if v.GetFont then | |
3374 local font,size,outline = v:GetFont() | |
3375 if font == lastSetFont then | |
3376 v:SetFont(normalFont, size, outline) | |
3377 end | |
3378 end | |
3379 regionTmp[i] = nil | |
3380 end | |
3381 lastSetFont = nil | |
3382 end | |
3383 end | |
3384 | |
3385 local function activate(self, oldLib, oldDeactivate) | |
3386 Dewdrop = self | |
3387 if oldLib and oldLib.registry then | |
3388 self.registry = oldLib.registry | |
3389 self.onceRegistered = oldLib.onceRegistered | |
3390 else | |
3391 self.registry = {} | |
3392 self.onceRegistered = {} | |
3393 | |
3394 local WorldFrame_OnMouseDown = WorldFrame:GetScript("OnMouseDown") | |
3395 local WorldFrame_OnMouseUp = WorldFrame:GetScript("OnMouseUp") | |
3396 local oldX, oldY, clickTime | |
3397 WorldFrame:SetScript("OnMouseDown", function(this, ...) | |
3398 oldX,oldY = GetCursorPosition() | |
3399 clickTime = GetTime() | |
3400 if WorldFrame_OnMouseDown then | |
3401 WorldFrame_OnMouseDown(this, ...) | |
3402 end | |
3403 end) | |
3404 | |
3405 WorldFrame:SetScript("OnMouseUp", function(this, ...) | |
3406 local x,y = GetCursorPosition() | |
3407 if not oldX or not oldY or not x or not y or not clickTime then | |
3408 self:Close() | |
3409 if WorldFrame_OnMouseUp then | |
3410 WorldFrame_OnMouseUp(this, ...) | |
3411 end | |
3412 return | |
3413 end | |
3414 local d = math.abs(x - oldX) + math.abs(y - oldY) | |
3415 if d <= 5 and GetTime() - clickTime < 0.5 then | |
3416 self:Close() | |
3417 end | |
3418 if WorldFrame_OnMouseUp then | |
3419 WorldFrame_OnMouseUp(this, ...) | |
3420 end | |
3421 end) | |
3422 | |
3423 hooksecurefunc(DropDownList1, "Show", function() | |
3424 if levels[1] and levels[1]:IsVisible() then | |
3425 self:Close() | |
3426 end | |
3427 end) | |
3428 | |
3429 hooksecurefunc("HideDropDownMenu", function() | |
3430 if levels[1] and levels[1]:IsVisible() then | |
3431 self:Close() | |
3432 end | |
3433 end) | |
3434 | |
3435 hooksecurefunc("CloseDropDownMenus", function() | |
3436 if levels[1] and levels[1]:IsVisible() then | |
3437 local stack = debugstack() | |
3438 if not stack:find("`TargetFrame_OnHide'") then | |
3439 self:Close() | |
3440 end | |
3441 end | |
3442 end) | |
3443 end | |
3444 self.frame = oldLib and oldLib.frame or CreateFrame("Frame") | |
3445 self.frame:UnregisterAllEvents() | |
3446 self.frame:RegisterEvent("PLAYER_REGEN_ENABLED") | |
3447 self.frame:RegisterEvent("PLAYER_REGEN_DISABLED") | |
3448 self.frame:Hide() | |
3449 self.frame:SetScript("OnEvent", function(this, event) | |
3450 this:Show() | |
3451 if event=="PLAYER_REGEN_ENABLED" then -- track combat state for secure frame operations | |
3452 self.combat = false | |
3453 elseif event=="PLAYER_REGEN_DISABLED" then | |
3454 self.combat = true | |
3455 end | |
3456 end) | |
3457 self.frame:SetScript("OnUpdate", function(this) | |
3458 this:Hide() | |
3459 self:Refresh(1) | |
3460 end) | |
3461 self.hookedTooltip = true | |
3462 if not oldLib or not oldLib.hookedTooltip then | |
3463 local OnTooltipHide = GameTooltip:GetScript("OnHide") | |
3464 GameTooltip:SetScript("OnHide", function(this, ...) | |
3465 if OnTooltipHide then | |
3466 OnTooltipHide(this, ...) | |
3467 end | |
3468 if type(self.OnTooltipHide) == "function" then | |
3469 self:OnTooltipHide() | |
3470 end | |
3471 end) | |
3472 end | |
3473 levels = {} | |
3474 buttons = {} | |
3475 | |
3476 if oldDeactivate then | |
3477 oldDeactivate(oldLib) | |
3478 end | |
3479 end | |
3480 | |
3481 local function external(lib, major, instance) | |
3482 if major == "SharedMedia-1.0" then | |
3483 SharedMedia = instance | |
3484 end | |
3485 end | |
3486 | |
3487 AceLibrary:Register(Dewdrop, MAJOR_VERSION, MINOR_VERSION, activate, nil, external) |