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