vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 local MAJOR_VERSION = "1.2"
2 local MINOR_VERSION = tonumber(string.sub("$Revision: 8308 $", 12, -3))
3  
4 if FuBarPlugin and FuBarPlugin.versions[MAJOR_VERSION] and FuBarPlugin.versions[MAJOR_VERSION].minor >= MINOR_VERSION and FuBarPlugin.MinimapContainer and FuBarPlugin.MinimapContainer.versions[MAJOR_VERSION] and FuBarPlugin.MinimapContainer.versions[MAJOR_VERSION].minor >= MINOR_VERSION then
5 return
6 end
7  
8 local loc = {
9 ARGUMENT_VISIBLE = "visible",
10 ARGUMENT_COLOR = "color",
11 ARGUMENT_SHOWICON = "showIcon",
12 ARGUMENT_SHOWTEXT = "showText",
13 ARGUMENT_PROFILE = "profile",
14  
15 TEXT_TOGGLE_VISIBILITY = "Toggle Visibility.",
16 TEXT_TOGGLE_WHETHER_TO_SHOW_THE_ICON = "Toggle whether to show the icon.",
17 TEXT_TOGGLE_WHETHER_TO_SHOW_TEXT = "Toggle whether to show text.",
18 TEXT_LIST_PROFILING_INFO = "List profiling information",
19  
20 MENU_SHOW_ICON = "Show icon",
21 MENU_SHOW_TEXT = "Show text",
22 MENU_SHOW_COLORED_TEXT = "Show colored text",
23 MENU_DETACH_TOOLTIP = "Detach tooltip",
24 MENU_LOCK_TOOLTIP = "Lock tooltip",
25 MENU_ON_LEFT_SIDE = "On left side",
26 MENU_IN_CENTER = "In center",
27 MENU_ON_RIGHT_SIDE = "On right side",
28 MENU_ATTACH = "Attach to minimap",
29 MENU_HIDE = "Hide",
30 MENU_DISABLE = "Disable",
31 MENU_ABOUT = "About",
32  
33 MAP_ONOFF = {[0]="|cffff0000Off|r",[1]="|cff00ff00On|r"},
34  
35 PATTERN_MERGE_WITH_CHILD = "Merge with %s",
36 PATTERN_SWITCH_TO_CHILD = "Switch to %s",
37 }
38  
39 if GetLocale() == "deDE" then
40 loc.TEXT_TOGGLE_VISIBILITY = "Sichtbarkeit umschalten."
41 loc.TEXT_TOGGLE_WHETHER_TO_SHOW_THE_ICON = "Iconanzeige umschalten."
42 loc.TEXT_TOGGLE_WHETHER_TO_SHOW_TEXT = "Textanzeige umschalten."
43 loc.TEXT_LIST_PROFILING_INFO = "Liste Profilinformationen"
44  
45 loc.MENU_SHOW_ICON = "Zeige Icon"
46 loc.MENU_SHOW_TEXT = "Zeige Text"
47 loc.MENU_SHOW_COLORED_TEXT = "Farbigen Text anzeigen"
48 loc.MENU_DETACH_TOOLTIP = "Tooltip l\195\182sen"
49 loc.MENU_LOCK_TOOLTIP = "Tooltip verankern"
50 loc.MENU_ON_LEFT_SIDE = "Auf linker Seite anzeigen"
51 loc.MENU_IN_CENTER = "In der Mitte anzeigen"
52 loc.MENU_ON_RIGHT_SIDE = "Auf rechter Seite anzeigen"
53 loc.MENU_HIDE = "Ausblenden"
54 loc.MENU_DISABLE = "Deaktivieren"
55 loc.MENU_ABOUT = "\195\156ber"
56  
57 loc.MAP_ONOFF[0] = "|cffff0000Aus|r"
58 loc.MAP_ONOFF[1] = "|cff00ff00An|r"
59  
60 loc.PATTERN_MERGE_WITH_CHILD = "Mit %s verbinden"
61 loc.PATTERN_SWITCH_TO_CHILD = "Zu %s wechseln"
62  
63 elseif GetLocale() == "frFR" then
64 loc.TEXT_TOGGLE_VISIBILITY = "Bascule la visibilite."
65 loc.TEXT_TOGGLE_WHETHER_TO_SHOW_THE_ICON = "Bascule la dissimulation ou l'affichage de l'icone."
66 loc.TEXT_TOGGLE_WHETHER_TO_SHOW_TEXT = "Bascule la dissimulation ou l'affichage du text."
67 -- loc.TEXT_LIST_PROFILING_INFO = "List profiling information" -- CHECK
68  
69 loc.MENU_SHOW_ICON = "Afficher l'icon"
70 loc.MENU_SHOW_TEXT = "Afficher le text"
71 -- loc.MENU_SHOW_COLORED_TEXT = "Show colored text" -- CHECK
72 -- loc.MENU_DETACH_TOOLTIP = "Detach tooltip" -- CHECK
73 -- loc.MENU_LOCK_TOOLTIP = "Lock tooltip" -- CHECK
74 -- loc.MENU_ON_LEFT_SIDE = "On left side" -- CHECK
75 -- loc.MENU_IN_CENTER = "In center" -- CHECK
76 -- loc.MENU_ON_RIGHT_SIDE = "On right side" -- CHECK
77 loc.MENU_HIDE = "Dissimule"
78 loc.MENU_DISABLE = "Desactive"
79 loc.MENU_ABOUT = "A propos"
80  
81 -- loc.MAP_ONOFF[0] = "|cffff0000Off|r" -- CHECK
82 -- loc.MAP_ONOFF[1] = "|cff00ff00On|r" -- CHECK
83  
84 loc.PATTERN_MERGE_WITH_CHILD = "Fusione avec %s"
85 loc.PATTERN_SWITCH_TO_CHILD = "Echange avec %s"
86  
87 elseif ( GetLocale() == "zhCN" ) then
88 loc.TEXT_TOGGLE_VISIBILITY = "是否可见."
89 loc.TEXT_TOGGLE_WHETHER_TO_SHOW_THE_ICON = "是否显示图标."
90 loc.TEXT_TOGGLE_WHETHER_TO_SHOW_TEXT = "是否显示文本."
91 loc.TEXT_LIST_PROFILING_INFO = "显示配置文件信息"
92  
93 loc.MENU_SHOW_ICON = "显示图标"
94 loc.MENU_SHOW_TEXT = "显示文本"
95 loc.MENU_SHOW_COLORED_TEXT = "显示彩色文本"
96 loc.MENU_DETACH_TOOLTIP = "分离提示信息"
97 loc.MENU_LOCK_TOOLTIP = "锁定提示信息"
98 loc.MENU_ON_LEFT_SIDE = "靠左侧"
99 loc.MENU_IN_CENTER = "居中"
100 loc.MENU_ON_RIGHT_SIDE = "靠右侧"
101 loc.MENU_ATTACH = "吸附在小地图周围"
102 loc.MENU_HIDE = "隐藏"
103 loc.MENU_DISABLE = "禁用"
104 loc.MENU_ABOUT = "关于"
105  
106 loc.MAP_ONOFF = {[0]="|cffff0000关闭|r",[1]="|cff00ff00开启|r"}
107  
108 loc.PATTERN_MERGE_WITH_CHILD = "与 %s 合并"
109 loc.PATTERN_SWITCH_TO_CHILD = "切换至 %s"
110  
111 elseif ( GetLocale() == "koKR" ) then
112 loc.ARGUMENT_VISIBLE = "visible"
113 loc.ARGUMENT_COLOR = "color"
114 loc.ARGUMENT_SHOWICON = "showIcon"
115 loc.ARGUMENT_SHOWTEXT = "showText"
116 loc.ARGUMENT_PROFILE = "profile"
117  
118 loc.TEXT_TOGGLE_VISIBILITY = "Toggle Visibility."
119 loc.TEXT_TOGGLE_WHETHER_TO_SHOW_THE_ICON = "Toggle whether to show the icon."
120 loc.TEXT_TOGGLE_WHETHER_TO_SHOW_TEXT = "Toggle whether to show text."
121 loc.TEXT_LIST_PROFILING_INFO = "List profiling information"
122  
123 loc.MENU_SHOW_ICON = "아이콘 보이기"
124 loc.MENU_SHOW_TEXT = "Show text"
125 loc.MENU_SHOW_COLORED_TEXT = "Show colored text"
126 loc.MENU_DETACH_TOOLTIP = "툴팁 분리"
127 loc.MENU_LOCK_TOOLTIP = "툴팁 잠그기"
128 loc.MENU_ON_LEFT_SIDE = "왼쪽으로"
129 loc.MENU_IN_CENTER = "가운데로"
130 loc.MENU_ON_RIGHT_SIDE = "오른쪽으로"
131 loc.MENU_HIDE = "숨기기"
132 loc.MENU_DISABLE = "끄기"
133 loc.MENU_ABOUT = "About"
134  
135 loc.MAP_ONOFF[0]="|cffff0000꺼짐|r"
136 loc.MAP_ONOFF[1]="|cff00ff00켜짐|r"
137  
138 PATTERN_MERGE_WITH_CHILD = "Merge with %s"
139 PATTERN_SWITCH_TO_CHILD = "Switch to %s"
140  
141 end
142  
143 local dewdrop = DewdropLib:GetInstance('1.0')
144 local tablet = TabletLib:GetInstance('1.0')
145  
146 if FUBAR_REVISION and MINOR_VERSION > FUBAR_REVISION then
147 FUBAR_REVISION = MINOR_VERSION
148 end
149  
150 -------------IRIEL'S-STUB-CODE--------------
151 local stub = {};
152  
153 -- Instance replacement method, replace contents of old with that of new
154 function stub:ReplaceInstance(old, new)
155 for k,v in pairs(old) do old[k]=nil; end
156 for k,v in pairs(new) do old[k]=v; end
157 end
158  
159 -- Get a new copy of the stub
160 function stub:NewStub()
161 local newStub = {};
162 self:ReplaceInstance(newStub, self);
163 newStub.lastVersion = '';
164 newStub.versions = {};
165 return newStub;
166 end
167  
168 -- Get instance version
169 function stub:GetInstance(version)
170 if (not version) then version = self.lastVersion; end
171 local versionData = self.versions[version];
172 if (not versionData) then
173 message("Cannot find library instance with version '"
174 .. version .. "'");
175 return;
176 end
177 return versionData.instance;
178 end
179  
180 -- Register new instance
181 function stub:Register(newInstance)
182 local version,minor = newInstance:GetLibraryVersion();
183 self.lastVersion = version;
184 local versionData = self.versions[version];
185 if (not versionData) then
186 -- This one is new!
187 versionData = { instance = newInstance,
188 minor = minor,
189 old = {}
190 };
191 self.versions[version] = versionData;
192 newInstance:LibActivate(self);
193 return newInstance;
194 end
195 if (minor <= versionData.minor) then
196 -- This one is already obsolete
197 if (newInstance.LibDiscard) then
198 newInstance:LibDiscard();
199 end
200 return versionData.instance;
201 end
202 -- This is an update
203 local oldInstance = versionData.instance;
204 local oldList = versionData.old;
205 versionData.instance = newInstance;
206 versionData.minor = minor;
207 local skipCopy = newInstance:LibActivate(self, oldInstance, oldList);
208 table.insert(oldList, oldInstance);
209 if (not skipCopy) then
210 for i, old in ipairs(oldList) do
211 self:ReplaceInstance(old, newInstance);
212 end
213 end
214 return newInstance;
215 end
216  
217 -- Bind stub to global scope if it's not already there
218 if (not FuBarPlugin) then
219 FuBarPlugin = stub:NewStub();
220 end
221 if (not FuBarPlugin.MinimapContainer) then
222 FuBarPlugin.MinimapContainer = stub:NewStub();
223 end
224  
225 -- Nil stub for garbage collection
226 stub = nil;
227 -----------END-IRIEL'S-STUB-CODE------------
228  
229  
230  
231 local RegisterTablet
232 -- FuBarPlugin
233 do
234 local compost
235 if CompostLib then
236 compost = CompostLib:GetInstance('compost-1')
237 end
238  
239 local epsilon = 1e-5
240  
241 local lib = AceAddon:new()
242  
243 local function VersionToNumber(version)
244 if version == nil then
245 return 0
246 elseif type(version) == "number" then
247 return version
248 end
249 local num = 0
250 local place = 1
251 string.gsub(version, "(%d+)", function (w)
252 num = num + tonumber(w) * math.pow(10, place * 2)
253 if place > 0 then
254 place = place - 1
255 else
256 place = place - 2
257 end
258 end)
259 return num
260 end
261  
262 function lib:assert(condition, message)
263 if not condition then
264 local stack = debugstack()
265 local first = string.gsub(stack, "\n.*", "")
266 local file = string.gsub(first, "^(.*\\.*).lua:%d+: .*", "%1")
267 file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
268 if not message then
269 local _,_,second = string.find(stack, "\n(.-)\n")
270 message = "assertion failed! " .. second
271 end
272 if self.name then
273 local _,_,title = string.find(self.name, "FuBar %- (.+)")
274 if not title then
275 title = self.name
276 end
277 message = title .. ": " .. message
278 end
279 local i = 1
280 for s in string.gfind(stack, "\n([^\n]*)") do
281 i = i + 1
282 if not string.find(s, file .. "%.lua:%d+:") then
283 error(message, i)
284 return
285 end
286 end
287 error(message, 2)
288 return
289 end
290 return condition
291 end
292  
293 function lib:argCheck(arg, num, kind, kind2, kind3, kind4)
294 if tostring(type(arg)) ~= kind then
295 if kind2 then
296 if tostring(type(arg)) ~= kind2 then
297 if kind3 then
298 if tostring(type(arg)) ~= kind3 then
299 if kind4 then
300 if tostring(type(arg)) ~= kind4 then
301 local _,_,func = string.find(debugstack(), "\n.-`(.-)'\n")
302 self:assert(false, format("Bad argument #%s to `%s' (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind or "---", kind2 or "---", kind3 or "---", kind4 or "---", type(arg)))
303 end
304 else
305 local _,_,func = string.find(debugstack(), "\n.-`(.-)'\n")
306 self:assert(false, format("Bad argument #%s to `%s' (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind or "---", kind2 or "---", kind3 or "---", type(arg)))
307 end
308 end
309 else
310 local _,_,func = string.find(debugstack(), "\n.-`(.-)'\n")
311 self:assert(false, format("Bad argument #%s to `%s' (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind or "---", kind2 or "---", type(arg)))
312 end
313 end
314 else
315 local _,_,func = string.find(debugstack(), "\n.-`(.-)'\n")
316 self:assert(false, format("Bad argument #%s to `%s' (%s expected, got %s)", tonumber(num) or 0/0, func, kind or "---", type(arg)))
317 end
318 end
319 end
320  
321 function lib:GetTitle()
322 self:assert(self.name, "You must provide self.name")
323 local _,_,title = string.find(self.name, "FuBar %- (.+)")
324 if not title then
325 title = self.name
326 end
327 return title
328 end
329  
330 function lib:DisableHideWithoutStandby()
331 self.hideWithoutStandby = false
332 if not self._hideWithoutStandbyEnabled then
333 return
334 end
335 self._hideWithoutStandbyEnabled = false
336 for index, value in self.cmd.options do
337 if value.method == "_ToggleVisible" then
338 table.remove(self.cmd.options, index)
339 break
340 end
341 end
342  
343 self._ToggleVisible = nil
344  
345 self.Report = self._Report
346 self._Report = nil
347  
348 if self.data.hidden then
349 self:DisableAddon()
350 end
351 self.data.hidden = nil
352 end
353  
354 function lib:EnableHideWithoutStandby()
355 self.hideWithoutStandby = true
356 if self._hideWithoutStandbyEnabled then
357 return
358 end
359 self._hideWithoutStandbyEnabled = true
360 table.insert(self.cmd.options, {
361 option = loc.ARGUMENT_VISIBLE,
362 desc = loc.TEXT_TOGGLE_VISIBILITY,
363 method = "_ToggleVisible"
364 })
365  
366 function self:_ToggleVisible()
367 if self.data.hidden then
368 self:Show()
369 else
370 self:Hide()
371 end
372 self.cmd:status(loc.ARGUMENT_VISIBLE, not self.data.hidden and 1 or 0, loc.MAP_ONOFF)
373 end
374  
375 if self.Report then
376 self._Report = self.Report
377 function self:Report()
378 self:_Report()
379 ace:print(" - ", format(ACE_CMD_REPORT_LINE, loc.ARGUMENT_VISIBLE, loc.MAP_ONOFF[not self.data.hidden and 1 or 0]))
380 end
381 else
382 function self:Report()
383 local report = compost and compost:Acquire(
384 compost:AcquireHash(
385 'text', loc.ARGUMENT_VISIBLE,
386 'val', not self.data.hidden and 1 or 0,
387 'map', loc.MAP_ONOFF
388 )
389 ) or {{
390 text = loc.ARGUMENT_VISIBLE,
391 val = not self.data.hidden and 1 or 0,
392 map = loc.MAP_ONOFF
393 }}
394 self.cmd:report(report)
395 if compost then
396 compost:Reclaim(report, 1)
397 end
398 end
399 end
400 end
401  
402 function lib:IsTextColored()
403 if self.data then
404 return not self.data.uncolored
405 else
406 return true
407 end
408 end
409  
410 function lib:ToggleMinimapAttached()
411 if FuBar and not self.cannotAttachToMinimap then
412 local value = self:IsMinimapAttached()
413 if value then
414 self.panel:RemovePlugin(self)
415 FuBar:GetPanel(1):AddPlugin(self, nil, self.defaultPosition)
416 else
417 self.panel:RemovePlugin(self)
418 FuBarPlugin.MinimapContainer:GetInstance(MAJOR_VERSION):AddPlugin(self)
419 end
420 end
421 end
422  
423 function lib:IsMinimapAttached()
424 return self.panel == FuBarPlugin.MinimapContainer:GetInstance(MAJOR_VERSION)
425 end
426  
427 function lib:ToggleTextColored(loud)
428 self.data.uncolored = not self.data.uncolored or nil
429 if loud then
430 self.cmd:status(loc.ARGUMENT_COLOR, not self.data.uncolored and 1 or 0, loc.MAP_ONOFF)
431 end
432 self:UpdateText()
433 return not self.data.uncolored
434 end
435  
436 function lib:Update()
437 self:UpdateData()
438 self:UpdateText()
439 self:UpdateTooltip()
440 end
441  
442 function lib:UpdateDisplay()
443 self:UpdateText()
444 self:UpdateTooltip()
445 end
446  
447 local function inheritDefaults(t, defaults)
448 if not defaults then
449 return
450 end
451 for k,v in pairs(defaults) do
452 if type(v) == "table" then
453 if type(t[k]) ~= "table" then
454 t[k] = {}
455 end
456 inheritDefaults(t[k], v)
457 elseif t[k] == v then
458 t[k] = nil
459 end
460 end
461 for k,v in pairs(t) do
462 if v == 1 and defaults[k] == true then
463 t[k] = nil
464 elseif v == true and defaults[k] == 1 then
465 t[k] = nil
466 end
467 end
468 setmetatable(t, { __index = defaults })
469 end
470  
471 function lib:_OnAceProfileLoaded()
472 if self.db then
473 local t = self.db._table
474 if not t.profiles then
475 t.profiles = {}
476 end
477 if not t.profiles[self.profilePath[2]] then
478 t.profiles[self.profilePath[2]] = {}
479 end
480 if self.data ~= self.db._table.profiles[self.profilePath[2]] then
481 self.data = self.db._table.profiles[self.profilePath[2]]
482 else
483 return
484 end
485 elseif FuBar then
486 local FuBarDB = FuBar2DB or FuBarDB
487 if not FuBarDB.pluginDB[self:GetTitle()] then
488 FuBarDB.pluginDB[self:GetTitle()] = {}
489 end
490 if not FuBarDB.pluginDB[self:GetTitle()].profiles then
491 FuBarDB.pluginDB[self:GetTitle()].profiles = {}
492 end
493 if not FuBarDB.pluginDB[self:GetTitle()].profiles["default"] then
494 FuBarDB.pluginDB[self:GetTitle()].profiles["default"] = {}
495 end
496 if self.data ~= FuBarDB.pluginDB[self:GetTitle()].profiles["default"] then
497 self.data = FuBarDB.pluginDB[self:GetTitle()].profiles["default"]
498 else
499 return
500 end
501 end
502 inheritDefaults(self.data, self.defaults)
503  
504 if type(self.ACE_PROFILE_LOADED) == "function" then
505 self:ACE_PROFILE_LOADED()
506 end
507  
508 self.data.version = self.version
509  
510 self:Update()
511 end
512  
513 function lib:Show(panelId)
514 if self.frame:IsShown() or (self.minimapFrame and self.minimapFrame:IsShown()) then
515 return
516 end
517 if panelId ~= false then
518 self.data.hidden = nil
519 end
520 if self:IsLoadOnDemand() and FuBar then
521 local data = FuBar.db and FuBar.db.profile or FuBar.data
522 if not data.loadOnDemand then
523 data.loadOnDemand = {}
524 end
525 if not data.loadOnDemand[self.folderName] then
526 data.loadOnDemand[self.folderName] = {}
527 end
528 data.loadOnDemand[self.folderName].disabled = nil
529 end
530 if self.disabled then
531 self.panelIdTmp = panelId
532 self:EnableAddon()
533 self.panelIdTmp = nil
534 if not self.db then
535 self.data.disabled = nil
536 end
537 elseif self.data and not self.data.hidden then
538 if panelId == 0 or not FuBar then
539 FuBarPlugin.MinimapContainer:GetInstance(MAJOR_VERSION):AddPlugin(self)
540 else
541 FuBar:ShowPlugin(self, panelId or self.panelIdTmp)
542 end
543 self:Update()
544 end
545 end
546  
547 function lib:Hide()
548 if not self.frame:IsShown() and (not self.minimapFrame or not self.minimapFrame:IsShown()) then
549 return
550 end
551 if self.hideWithoutStandby then
552 self.data.hidden = true
553 end
554 if not self.hideWithoutStandby then
555 if not self.overrideTooltip and not self.cannotDetachTooltip and self:IsTooltipDetached() and self.data.detachedTooltip.detached then
556 self:ReattachTooltip()
557 self.data.detachedTooltip.detached = true
558 end
559 if not self.db then
560 self.data.disabled = true
561 end
562 if not FuBar or not FuBar:IsChangingProfile() then
563 self:DisableAddon()
564 if self:IsLoadOnDemand() and FuBar then
565 local data = FuBar.db and FuBar.db.profile or FuBar.data
566 if not data.loadOnDemand then
567 data.loadOnDemand = {}
568 end
569 if not data.loadOnDemand[self.folderName] then
570 data.loadOnDemand[self.folderName] = {}
571 end
572 data.loadOnDemand[self.folderName].disabled = true
573 end
574 end
575 end
576 if self.panel then
577 self.panel:RemovePlugin(self)
578 end
579 self.frame:Hide()
580 if self.minimapFrame then
581 self.minimapFrame:Hide()
582 end
583 end
584  
585 function lib:AddImpliedMenuOptions(level)
586 self:argCheck(level, 2, "number", "nil")
587 if self.hasIcon and not self.hasNoText then
588 dewdrop:AddLine(
589 'text', loc.MENU_SHOW_ICON,
590 'func', function()
591 self:ToggleIconShown()
592 end,
593 'checked', self:IsIconShown(),
594 'level', level
595 )
596 end
597  
598 if not self.cannotHideText and self.hasIcon and not self.hasNoText then
599 dewdrop:AddLine(
600 'text', loc.MENU_SHOW_TEXT,
601 'func', function()
602 self:ToggleTextShown()
603 end,
604 'checked', self:IsTextShown(),
605 'leve', level
606 )
607 end
608  
609 if not self.userDefinedFrame and not self.hasNoText and not self.hasNoColor then
610 dewdrop:AddLine(
611 'text', loc.MENU_SHOW_COLORED_TEXT,
612 'arg1', self,
613 'func', "ToggleTextColored",
614 'checked', self:IsTextColored(),
615 'level', level
616 )
617 end
618  
619 if not self.overrideTooltip and not self.cannotDetachTooltip then
620 dewdrop:AddLine(
621 'text', loc.MENU_DETACH_TOOLTIP,
622 'func', function()
623 if self:IsTooltipDetached() then
624 self:ReattachTooltip()
625 else
626 self:DetachTooltip()
627 end
628 end,
629 'checked', self:IsTooltipDetached(),
630 'level', level
631 )
632  
633 dewdrop:AddLine(
634 'text', loc.MENU_LOCK_TOOLTIP,
635 'arg1', tablet,
636 'func', "ToggleLocked",
637 'arg2', self.frame,
638 'checked', tablet:IsLocked(self.frame),
639 'disabled', not self:IsTooltipDetached(),
640 'level', level
641 )
642 end
643  
644 if not self:IsMinimapAttached() then
645 dewdrop:AddLine(
646 'text', loc.MENU_ON_LEFT_SIDE,
647 'arg1', self.panel,
648 'func', self.panel:GetPluginSide(self) ~= "LEFT" and "SetPluginSide",
649 'arg2', self,
650 'arg3', "LEFT",
651 'checked', self.panel:GetPluginSide(self) == "LEFT",
652 'level', level,
653 'closeWhenClicked', self.panel:GetPluginSide(self) ~= "LEFT",
654 'isRadio', true
655 )
656  
657 dewdrop:AddLine(
658 'text', loc.MENU_IN_CENTER,
659 'arg1', self.panel,
660 'func', self.panel:GetPluginSide(self) ~= "CENTER" and "SetPluginSide",
661 'arg2', self,
662 'arg3', "CENTER",
663 'checked', self.panel:GetPluginSide(self) == "CENTER",
664 'level', level,
665 'closeWhenClicked', self.panel:GetPluginSide(self) ~= "CENTER",
666 'isRadio', true
667 )
668  
669 dewdrop:AddLine(
670 'text', loc.MENU_ON_RIGHT_SIDE,
671 'arg1', self.panel,
672 'func', self.panel:GetPluginSide(self) ~= "RIGHT" and "SetPluginSide",
673 'arg2', self,
674 'arg3', "RIGHT",
675 'checked', self.panel:GetPluginSide(self) == "RIGHT",
676 'level', level,
677 'closeWhenClicked', self.panel:GetPluginSide(self) ~= "RIGHT",
678 'isRadio', true
679 )
680 end
681  
682 if not self.cannotAttachToMinimap or self:IsMinimapAttached() then
683 dewdrop:AddLine(
684 'text', loc.MENU_ATTACH,
685 'arg1', self,
686 'func', "ToggleMinimapAttached",
687 'checked', self:IsMinimapAttached(),
688 'level', level,
689 'closeWhenClicked', true
690 )
691 end
692  
693 if self.hideWithoutStandby then
694 dewdrop:AddLine(
695 'text', loc.MENU_HIDE,
696 'arg1', self,
697 'func', "Hide",
698 'level', level,
699 'closeWhenClicked', true
700 )
701 end
702  
703 dewdrop:AddLine(
704 'text', loc.MENU_DISABLE,
705 'arg1', self,
706 'func', "DisableAddon",
707 'level', level,
708 'closeWhenClicked', true
709 )
710  
711 dewdrop:AddLine(
712 'level', level
713 )
714  
715 dewdrop:AddLine(
716 'text', loc.MENU_ABOUT,
717 'arg1', self.cmd,
718 'func', "DisplayAddonInfo",
719 'level', level
720 )
721 end
722  
723 function lib:SetIcon(path)
724 if not path then
725 return
726 end
727 if path == 1 then
728 path = true
729 end
730 self:argCheck(path, 2, "string", "boolean")
731 self:assert(self.hasIcon, "Cannot set icon unless self.hasIcon is set. (" .. self:GetTitle() .. ")")
732 if not self.iconFrame then
733 return
734 end
735 if type(path) ~= "string" then
736 path = format("Interface\\AddOns\\%s\\icon", self.folderName)
737 elseif not string.find(path, '^Interface[\\/]') then
738 path = format("Interface\\AddOns\\%s\\%s", self.folderName, path)
739 end
740 if string.sub(path, 1, 16) == "Interface\\Icons\\" then
741 self.iconFrame:SetTexCoord(0.05, 0.95, 0.05, 0.95)
742 else
743 self.iconFrame:SetTexCoord(0, 1, 0, 1)
744 end
745 self.iconFrame:SetTexture(path)
746 if self.minimapIcon then
747 if string.sub(path, 1, 16) == "Interface\\Icons\\" then
748 self.minimapIcon:SetTexCoord(0.05, 0.95, 0.05, 0.95)
749 else
750 self.minimapIcon:SetTexCoord(0, 1, 0, 1)
751 end
752 self.minimapIcon:SetTexture(path)
753 end
754 end
755  
756 function lib:GetIcon()
757 if self.hasIcon then
758 return self.iconFrame:GetTexture()
759 end
760 end
761  
762 function lib:CheckWidth(force)
763 self:argCheck(force, 2, "boolean", "nil")
764 if (self.iconFrame and self.iconFrame:IsShown()) or (self.textFrame and self.textFrame:IsShown()) then
765 if self.data and not self:IsIconShown() then
766 self.iconFrame:SetWidth(epsilon)
767 end
768 local width
769 if not self.hasNoText then
770 self.textFrame:SetHeight(0)
771 self.textFrame:SetWidth(500)
772 width = self.textFrame:GetStringWidth() + 1
773 self.textFrame:SetWidth(width)
774 self.textFrame:SetHeight(self.textFrame:GetHeight())
775 end
776 if self.hasNoText or not self.textFrame:IsShown() then
777 self.frame:SetWidth(self.iconFrame:GetWidth())
778 if self.panel and self.panel:GetPluginSide(self) == "CENTER" then
779 self.panel:UpdateCenteredPosition()
780 end
781 elseif force or not self.textWidth or self.textWidth < width or self.textWidth - 8 > width then
782 self.textWidth = width
783 self.textFrame:SetWidth(width)
784 if self.iconFrame and self.iconFrame:IsShown() then
785 self.frame:SetWidth(width + self.iconFrame:GetWidth())
786 else
787 self.frame:SetWidth(width)
788 end
789 if self.panel and self.panel:GetPluginSide(self) == "CENTER" then
790 self.panel:UpdateCenteredPosition()
791 end
792 end
793 end
794 end
795  
796 function lib:SetText(text)
797 if not self.textFrame then
798 return
799 end
800 self:assert(not self.hasNoText, "Cannot set text if self.hasNoText has been set. (" .. self:GetTitle() .. ")")
801 self:argCheck(text, 2, "string", "number")
802 if text == "" then
803 if self.hasIcon then
804 self:ShowIcon()
805 else
806 text = self:GetTitle()
807 end
808 end
809 if not self:IsTextColored() then
810 text = string.gsub(text, "|c%x%x%x%x%x%x%x%x(.-)|r", "%1")
811 end
812 self.textFrame:SetText(text)
813 self:CheckWidth()
814 end
815  
816 function lib:GetText()
817 self:assert(self.textFrame, "Cannot get text without a self.textFrame (" .. self:GetTitle() .. ")")
818 if not self.hasNoText then
819 return self.textFrame:GetText() or ""
820 end
821 end
822  
823 function lib:IsIconShown()
824 if not self.hasIcon then
825 return false
826 elseif self.hasNoText then
827 return true
828 elseif not self.data then
829 return true
830 elseif not self.data.showIcon then
831 return true
832 else
833 return (self.data.showIcon == 1 or self.data.showIcon == true) and true or false
834 end
835 end
836  
837 function lib:ToggleIconShown(loud)
838 self:assert(self.iconFrame, "Cannot toggle icon without a self.iconFrame (" .. self:GetTitle() .. ")")
839 self:assert(self.hasIcon, "Cannot show icon unless self.hasIcon is set. (" .. self:GetTitle() .. ")")
840 self:assert(not self.hasNoText, "Cannot hide icon if self.hasNoText is set. (" .. self:GetTitle() .. ")")
841 self:assert(self.textFrame, "Cannot hide icon if self.textFrame is not set. (" .. self:GetTitle() .. ")")
842 self:assert(self.iconFrame, "Cannot hide icon if self.iconFrame is not set. (" .. self:GetTitle() .. ")")
843 local value = not self:IsIconShown()
844 self.data.showIcon = value and 1 or 0
845 if loud then
846 self.cmd:status(loc.ARGUMENT_SHOWICON, value and 1 or 0, loc.MAP_ONOFF)
847 end
848 if value then
849 if self.textFrame:IsShown() and self.textFrame:GetText() == self:GetTitle() then
850 self.textFrame:Hide()
851 self.textFrame:SetText("")
852 end
853 self.iconFrame:Show()
854 self.iconFrame:SetWidth(self.iconFrame:GetHeight())
855 else
856 if not self.textFrame:IsShown() or not self.textFrame:GetText() then
857 self.textFrame:Show()
858 self.textFrame:SetText(self:GetTitle())
859 end
860 self.iconFrame:Hide()
861 self.iconFrame:SetWidth(epsilon)
862 end
863 self:CheckWidth(true)
864 return value
865 end
866  
867 function lib:ShowIcon()
868 if not self:IsIconShown() then
869 self:ToggleIconShown()
870 end
871 end
872  
873 function lib:HideIcon()
874 if self:IsIconShown() then
875 self:ToggleIconShown()
876 end
877 end
878  
879 function lib:IsTextShown()
880 if not self.hasIcon then
881 return false
882 elseif self.hasNoText then
883 return false
884 elseif not self.data then
885 return true
886 elseif not self.data.showText then
887 return true
888 else
889 return (self.data.showText == 1 or self.data.showText == true) and true or false
890 end
891 end
892  
893 function lib:ToggleTextShown(loud)
894 self:assert(not self.cannotHideText, "Cannot hide text unless self.cannotHideText is unset. (" .. self:GetTitle() .. ")")
895 self:assert(self.hasIcon, "Cannot show text unless self.hasIcon is set. (" .. self:GetTitle() .. ")")
896 self:assert(not self.hasNoText, "Cannot hide text if self.hasNoText is set. (" .. self:GetTitle() .. ")")
897 self:assert(self.textFrame, "Cannot hide text if self.textFrame is not set. (" .. self:GetTitle() .. ")")
898 self:assert(self.iconFrame, "Cannot hide text if self.iconFrame is not set. (" .. self:GetTitle() .. ")")
899 local value = not self:IsTextShown()
900 self.data.showText = value and 1 or 0
901 if loud then
902 self.cmd:status(loc.ARGUMENT_SHOWTEXT, value and 1 or 0, loc.MAP_ONOFF)
903 end
904 if value then
905 self.textFrame:Show()
906 self:UpdateText()
907 else
908 self.textFrame:SetText("")
909 self.textFrame:SetWidth(epsilon)
910 self.textFrame:Hide()
911 if not self:IsIconShown() then
912 DropDownList1:Hide()
913 end
914 self:ShowIcon()
915 end
916 self:CheckWidth(true)
917 return value
918 end
919  
920 function lib:ShowText()
921 if not self:IsTextShown() then
922 self:ToggleTextShown()
923 end
924 end
925  
926 function lib:HideText()
927 if self:IsTextShown() then
928 self:ToggleTextShown()
929 end
930 end
931  
932 function lib:OpenChildFrame(child)
933 self:argCheck(child, 2, "table")
934 if FuBarPlugin.lastChildFrame then
935 FuBarPlugin.lastChildFrame:Hide()
936 end
937 FuBarPlugin.lastChildFrame = child
938 local frame = self.frame
939 local width, height = GetScreenWidth(), GetScreenHeight()
940 local anchor
941 if frame:GetLeft() <= width/2 then
942 anchor = "LEFT"
943 else
944 anchor = "RIGHT"
945 end
946 child:ClearAllPoints()
947 if frame:GetTop() <= height/2 then
948 child:SetPoint("BOTTOM" .. anchor, frame, "TOP" .. anchor)
949 local left = child:GetLeft()
950 child:ClearAllPoints()
951 child:SetPoint("LEFT", UIParent, "LEFT", left, 0)
952 child:SetPoint("BOTTOM", frame, "TOP")
953 else
954 child:SetPoint("TOP" .. anchor, frame, "BOTTOM" .. anchor)
955 local left = child:GetLeft()
956 child:ClearAllPoints()
957 child:SetPoint("LEFT", UIParent, "LEFT", left, 0)
958 child:SetPoint("TOP", frame, "BOTTOM")
959 end
960 child:Show()
961 end
962  
963 local onClickTypes = {"OnClick", "OnDoubleClick", "OnMouseDown", "OnMouseUp"}
964  
965 function lib:HookIntoPlugin(mother, style)
966 self:argCheck(mother, 2, "table", "nil")
967 self:argCheck(style, 3, "string", "nil")
968 if self.hookedPlugin then
969 ace:print(self:GetTitle() .. ": Cannot hook into a plugin while already hooked into another.")
970 return false
971 end
972 if not mother or type(mother) ~= "table" or getmetatable(self).__index ~= getmetatable(mother).__index then
973 ace:debug(self:GetTitle() .. ": Cannot hook into given plugin.")
974 return false
975 end
976 local showTitle = false
977 if style then
978 local a, b = string.find(style, "_TITLE")
979 if a and b then
980 showTitle = true
981 style = string.sub(style, 1, a - 1) .. string.sub(style, b + 1)
982 end
983 end
984 if style ~= "INLINE" and style ~= "SWITCH" and style ~= "SWITCHTEXT" then
985 style = "INLINE"
986 end
987 local child = self
988 local merged = false
989 local current = "MOTHER"
990 local mother__UpdateTooltip = mother._UpdateTooltip
991 local child_UpdateTooltip = child.UpdateTooltip
992 local mother_UpdateText = mother.UpdateText
993 local child_UpdateText = child.UpdateText
994 local child_Show = child.Show
995 local mother_funcs = {}
996 local mother_MenuSettings = mother.MenuSettings
997 local manualStandby = false
998 local motherIcon = mother:GetIcon()
999 local childIcon = child:GetIcon()
1000 local merge, unmerge, switch
1001 switch = function()
1002 if current == "MOTHER" then
1003 self.data["switch." .. mother:GetTitle()] = "CHILD"
1004 current = "CHILD"
1005 getmetatable(mother).__index.SetIcon(mother, childIcon)
1006 else
1007 self.data["switch." .. mother:GetTitle()] = "MOTHER"
1008 current = "MOTHER"
1009 getmetatable(mother).__index.SetIcon(mother, motherIcon)
1010 end
1011 mother:UpdateText()
1012 mother:UpdateTooltip()
1013 dewdrop:Close()
1014 end
1015 function self:SwitchPluginHook()
1016 switch()
1017 end
1018 function self:IsCurrentPluginHookSwitch()
1019 return current ~= "MOTHER"
1020 end
1021 merge = function()
1022 merged = true
1023 self.data["merge." .. mother:GetTitle()] = 1
1024 if style == "INLINE" or style == "SWITCHTEXT" then
1025 function mother:_UpdateTooltip()
1026 mother__UpdateTooltip(mother)
1027 if showTitle and not mother:IsTooltipDetached() then
1028 tablet:AddCategory(
1029 'text', child:GetTitle(),
1030 'font', tablet:GetHeaderFontObject(),
1031 'justify', "CENTER",
1032 'isTitle', true
1033 )
1034 end
1035 child:_UpdateTooltip()
1036 end
1037 elseif style == "SWITCH" then
1038 function mother:_UpdateTooltip()
1039 if current == "MOTHER" then
1040 mother__UpdateTooltip(mother)
1041 else
1042 mother.tooltip:SetTitle(child:GetTitle())
1043 child.tooltip = mother.tooltip
1044 child:_UpdateTooltip()
1045 end
1046 end
1047 end
1048 function child:UpdateTooltip()
1049 mother:UpdateTooltip()
1050 end
1051  
1052 local text
1053 if style == "INLINE" then
1054 function mother:SetText(t)
1055 text = t
1056 end
1057 function child:SetText(t)
1058 if text == "" or not text then
1059 text = t
1060 else
1061 text = text .. " " .. t
1062 end
1063 end
1064 elseif style == "SWITCH" or style == "SWITCHTEXT" then
1065 function mother:SetText(t)
1066 if current == "MOTHER" then
1067 text = t
1068 end
1069 end
1070 function child:SetText(t)
1071 if current ~= "MOTHER" then
1072 text = t
1073 end
1074 end
1075 end
1076  
1077 if style == "INLINE" then
1078 function mother:UpdateText()
1079 text = ""
1080 if mother_UpdateText then
1081 mother_UpdateText(mother)
1082 end
1083 if child_UpdateText then
1084 child_UpdateText(child)
1085 end
1086 getmetatable(mother).__index.SetText(mother, text)
1087 text = nil
1088 end
1089 elseif style == "SWITCH" or style == "SWITCHTEXT" then
1090 function mother:UpdateText()
1091 text = ""
1092 if current == "MOTHER" and mother_UpdateText then
1093 mother_UpdateText(mother)
1094 end
1095 if current ~= "MOTHER" and child_UpdateText then
1096 child_UpdateText(child)
1097 end
1098 getmetatable(mother).__index.SetText(mother, text)
1099 text = nil
1100 end
1101 end
1102 child.UpdateText = mother.UpdateText
1103  
1104 for _,name in onClickTypes do
1105 local name = name
1106 mother_funcs[name] = mother[name]
1107 local child_func = child[name]
1108 if style == "INLINE" then
1109 if mother_funcs[name] and child_func then
1110 mother[name] = function(self, alpha)
1111 mother_funcs[name](mother, alpha)
1112 child_func(child, alpha)
1113 end
1114 elseif child_func then
1115 mother[name] = child_func
1116 end
1117 elseif style == "SWITCH" or style == "SWITCHTEXT" then
1118 if mother_funcs[name] and child_func then
1119 mother[name] = function(self, alpha)
1120 if current == "MOTHER" and mother_funcs[name] ~= "nil" then
1121 mother_funcs[name](mother, alpha)
1122 elseif current ~= "MOTHER" and child_func then
1123 child_func(child, alpha)
1124 end
1125 end
1126 elseif child_func then
1127 mother[name] = function(self, alpha)
1128 if current ~= "MOTHER" and child_func then
1129 child_func(child, alpha)
1130 end
1131 end
1132 elseif mother_funcs[name] then
1133 mother[name] = function(self, alpha)
1134 if current == "MOTHER" and mother_funcs[name] ~= "nil" then
1135 mother_funcs[name](mother, alpha)
1136 end
1137 end
1138 end
1139 end
1140 if not mother_funcs[name] then
1141 mother_funcs[name] = "nil"
1142 end
1143 end
1144  
1145 if style == "SWITCH" or style == "SWITCHTEXT" then
1146 function mother:SetIcon(path)
1147 motherIcon = path
1148 getmetatable(mother).__index.SetIcon(mother, path)
1149 end
1150 function child:SetIcon(path)
1151 childIcon = path
1152 getmetatable(mother).__index.SetIcon(mother, path)
1153 end
1154 end
1155  
1156 function child:Show(panelId)
1157 if panelId and panelId ~= 0 then
1158 unmerge()
1159 end
1160  
1161 child_Show(self, panelId)
1162 end
1163  
1164 if not child.hideWithoutStandby then
1165 manualStandby = true
1166 child:EnableHideWithoutStandby()
1167 end
1168 child:Hide()
1169  
1170 mother:UpdateText()
1171 mother:UpdateTooltip()
1172 end
1173 unmerge = function()
1174 merged = false
1175 self.data["merge." .. mother:GetTitle()] = 0
1176 mother._UpdateTooltip = mother__UpdateTooltip
1177 child.UpdateTooltip = child_UpdateTooltip
1178 mother.SetText = nil
1179 child.SetText = nil
1180 mother.SetIcon = nil
1181 child.SetIcon = nil
1182 mother.UpdateText = mother_UpdateText
1183 child.UpdateText = child_UpdateText
1184 for name,func in pairs(mother_funcs) do
1185 if func == "nil" then
1186 mother[name] = nil
1187 else
1188 mother[name] = func
1189 end
1190 end
1191 child.Show = child_Show
1192 if manualStandby then
1193 child:DisableHideWithoutStandby()
1194 manualStandby = false
1195 end
1196 mother:SetIcon(motherIcon)
1197 mother:UpdateText()
1198 mother:UpdateTooltip()
1199 child:Show()
1200 end
1201  
1202 function mother:MenuSettings(level, value)
1203 if level == 1 then
1204 dewdrop:AddLine(
1205 'text', format(loc.PATTERN_MERGE_WITH_CHILD, child:GetTitle()),
1206 'func', function()
1207 if merged then
1208 unmerge()
1209 else
1210 if child.disabled then
1211 child:EnableAddon()
1212 end
1213 merge()
1214 end
1215 end,
1216 'checked', merged,
1217 'hasArrow', merged and (style == "SWITCH" or style == "SWITCHTEXT"),
1218 'value', child:GetTitle()
1219 )
1220 elseif level == 2 and value == child:GetTitle() then
1221 dewdrop:AddLine(
1222 'text', format(loc.PATTERN_SWITCH_TO_CHILD, child:GetTitle()),
1223 'func', switch,
1224 'checked', current ~= "MOTHER"
1225 )
1226 end
1227 if merged then
1228 if (style ~= "SWITCH" or (style == "SWITCH" and current == "MOTHER")) and mother_MenuSettings then
1229 if level == 1 then
1230 dewdrop:AddLine()
1231 end
1232 mother_MenuSettings(mother, level, value)
1233 end
1234 if (style ~= "SWITCH" or (style == "SWITCH" and current == "CHILD")) and child.MenuSettings then
1235 if level == 1 then
1236 dewdrop:AddLine()
1237 dewdrop:AddLine(
1238 'text', child:GetTitle(),
1239 'isTitle', true
1240 )
1241 end
1242 child:MenuSettings(level, value)
1243 end
1244 else
1245 if mother_MenuSettings then
1246 if level == 1 then
1247 dewdrop:AddLine()
1248 end
1249 mother_MenuSettings(mother, level, value)
1250 end
1251 end
1252 end
1253 if not self.data["merge." .. mother:GetTitle()] then
1254 self.data["merge." .. mother:GetTitle()] = 1
1255 end
1256 if (style == "SWITCH" or style == "SWITCHTEXT") and not self.data["switch." .. mother:GetTitle()] then
1257 self.data["switch." .. mother:GetTitle()] = "MOTHER"
1258 end
1259 if self.data["merge." .. mother:GetTitle()] == 1 then
1260 merge()
1261 end
1262 if style == "SWITCH" or style == "SWITCHTEXT" then
1263 if self.data["switch." .. mother:GetTitle()] == "MOTHER" then
1264 self.data["switch." .. mother:GetTitle()] = "CHILD"
1265 else
1266 self.data["switch." .. mother:GetTitle()] = "MOTHER"
1267 end
1268 current = self.data["switch." .. mother:GetTitle()]
1269 switch()
1270 end
1271 self.hookedPlugin = mother
1272 return true
1273 end
1274  
1275 function lib:IsTooltipDetached()
1276 if not tablet.registry[self.frame] then
1277 self:UpdateTooltip()
1278 end
1279 return not tablet:IsAttached(self.frame)
1280 end
1281  
1282 function lib:DetachTooltip()
1283 self:UpdateTooltip()
1284 tablet:Detach(self.frame)
1285 end
1286  
1287 function lib:ReattachTooltip()
1288 self:UpdateTooltip()
1289 tablet:Attach(self.frame)
1290 end
1291  
1292 function lib:GetName()
1293 return self.name
1294 end
1295  
1296 function lib:GetCategory()
1297 return self.category
1298 end
1299  
1300 function lib:GetFrame()
1301 return self.frame
1302 end
1303  
1304 function lib:GetPanel()
1305 return self.panel
1306 end
1307  
1308 function lib:GetDefaultPosition()
1309 return self.defaultPosition or "LEFT"
1310 end
1311  
1312 local function IsCorrectPanel(panel)
1313 if type(panel) ~= "table" then
1314 return false
1315 elseif type(panel.AddPlugin) ~= "function" then
1316 return false
1317 elseif type(panel.RemovePlugin) ~= "function" then
1318 return false
1319 elseif type(panel.GetNumPlugins) ~= "function" then
1320 return false
1321 elseif type(panel:GetNumPlugins()) ~= "number" then
1322 return false
1323 elseif type(panel.GetPlugin) ~= "function" then
1324 return false
1325 elseif type(panel.HasPlugin) ~= "function" then
1326 return false
1327 elseif type(panel.GetPluginSide) ~= "function" then
1328 return false
1329 end
1330 return true
1331 end
1332  
1333 function lib:SetPanel(panel)
1334 if panel then
1335 self:assert(IsCorrectPanel(panel), "Panel does not have the correct API.")
1336 end
1337 self.panel = panel
1338 end
1339  
1340 function lib:SetFontSize(size)
1341 self:assert(not self.userDefinedFrame, "You must provide a SetFontSize(size) method if you provide your own frame.")
1342 if self.hasIcon then
1343 self:assert(self.iconFrame, (self.name and self.name .. ": " or "") .. "No iconFrame found")
1344 self.iconFrame:SetWidth(size + 3)
1345 self.iconFrame:SetHeight(size + 3)
1346 end
1347 if not self.hasNoText then
1348 self:assert(self.textFrame, (self.name and self.name .. ": " or "") .. "No textFrame found")
1349 local font, _, flags = self.textFrame:GetFont()
1350 self.textFrame:SetFont(font, size, flags)
1351 end
1352 self:CheckWidth()
1353 end
1354  
1355 function lib:SetLoadOnDemand(lod)
1356 self:argCheck(lod, 2, "boolean")
1357 self._loadOnDemand = lod
1358 end
1359  
1360 function lib:IsLoadOnDemand()
1361 return self._loadOnDemand
1362 end
1363  
1364 function lib:IsDisabled()
1365 return self.disabled
1366 end
1367  
1368 local function cleanDefaults(t, defaults, notFirst)
1369 if defaults then
1370 for k,v in pairs(defaults) do
1371 if type(v) == "table" then
1372 if type(t[k]) == "table" then
1373 cleanDefaults(t[k], v, true)
1374 if next(t[k]) == nil then
1375 t[k] = nil
1376 end
1377 end
1378 elseif t[k] == v then
1379 t[k] = nil
1380 elseif t[k] == true and v == TRUE then
1381 t[k] = nil
1382 elseif t[k] == TRUE and v == true then
1383 t[k] = nil
1384 end
1385 end
1386 for k,v in pairs(t) do
1387 if v == false and not defaults[k] then
1388 t[k] = nil
1389 end
1390 end
1391 end
1392 if not notFirst then
1393 if next(t) == "version" and next(t, "version") == nil then
1394 t.version = nil
1395 return true
1396 end
1397 end
1398 return false
1399 end
1400  
1401 function RegisterTablet(self)
1402 if not tablet:IsRegistered(self.frame) then
1403 local FuBar_data = FuBar and (FuBar.db and FuBar.db.profile or FuBar.data)
1404 tablet:Register(self.frame,
1405 'children', function()
1406 tablet:SetTitle(self:GetTitle())
1407 self:_UpdateTooltip()
1408 end,
1409 'clickable', self.clickableTooltip,
1410 'data', FuBar and FuBar_data.tooltip or self.data.detachedTooltip,
1411 'detachedData', self.data.detachedTooltip,
1412 'point', function(frame)
1413 if frame:GetTop() > GetScreenHeight() / 2 then
1414 local x = frame:GetCenter()
1415 if x < GetScreenWidth() / 3 then
1416 return "TOPLEFT", "BOTTOMLEFT"
1417 elseif x < GetScreenWidth() * 2 / 3 then
1418 return "TOP", "BOTTOM"
1419 else
1420 return "TOPRIGHT", "BOTTOMRIGHT"
1421 end
1422 else
1423 local x = frame:GetCenter()
1424 if x < GetScreenWidth() / 3 then
1425 return "BOTTOMLEFT", "TOPLEFT"
1426 elseif x < GetScreenWidth() * 2 / 3 then
1427 return "BOTTOM", "TOP"
1428 else
1429 return "BOTTOMRIGHT", "TOPRIGHT"
1430 end
1431 end
1432 end,
1433 'menu', function(level, value, valueN_1, valueN_2, valueN_3, valueN_4)
1434 if self.MenuSettings then
1435 self:MenuSettings(level, value, true, valueN_1, valueN_2, valueN_3, valueN_4)
1436 end
1437 end
1438 )
1439 end
1440 end
1441  
1442 function lib:RegisterForLoad()
1443 if not self.defaults then
1444 self.defaults = {}
1445 end
1446 if not self.defaults.detachedTooltip then
1447 self.defaults.detachedTooltip = {}
1448 end
1449  
1450 if not self.cmd then
1451 local title = string.lower(self:GetTitle())
1452 self.cmd = AceChatCmd:new({"/" .. string.gsub(title, " ", "_"), "/" .. string.gsub(title, " ", "")}, {})
1453 end
1454  
1455 _,_,self.folderName = string.find(debugstack(2, 1, 0), "\\AddOns\\(.*)\\")
1456  
1457 self.versionNumber = VersionToNumber(self.version)
1458  
1459 if not self.frame then
1460 local name = "FuBarPlugin" .. self:GetTitle() .. "Frame"
1461 local frame = getglobal(name)
1462 if not frame or not getglobal(name .. "Text") or not getglobal(name .. "Icon") then
1463 frame = getmetatable(self).__index.CreateBasicPluginFrame(self, name)
1464  
1465 local icon = frame:CreateTexture(name .. "Icon", "ARTWORK")
1466 icon:SetWidth(16)
1467 icon:SetHeight(16)
1468 icon:SetPoint("LEFT", frame, "LEFT")
1469  
1470 local text = frame:CreateFontString(name .. "Text", "ARTWORK")
1471 text:SetWidth(134)
1472 text:SetHeight(24)
1473 text:SetPoint("LEFT", icon, "RIGHT", 0, 1)
1474 text:SetFontObject(GameFontNormal)
1475 end
1476 self.frame = frame
1477 self.textFrame = getglobal(self.frame:GetName() .. "Text")
1478 self.iconFrame = getglobal(self.frame:GetName() .. "Icon")
1479 else
1480 self.userDefinedFrame = true
1481 end
1482  
1483 self.frame.plugin = self
1484 self.frame:SetParent(UIParent)
1485 self.frame:SetPoint("RIGHT", UIParent, "LEFT", -5, 0)
1486 self.frame:Hide()
1487  
1488 if not self.UpdateData then
1489 self.UpdateData = function(self) end
1490 end
1491 if not self.UpdateText then
1492 if self.hasNoText then
1493 self.UpdateText = function(self) end
1494 else
1495 self.UpdateText = function(self)
1496 self:SetText(self:GetTitle())
1497 end
1498 end
1499 end
1500 if not self.UpdateTooltip then
1501 self.UpdateTooltip = function(self) end
1502 end
1503  
1504 if self.hasIcon then
1505 self:SetIcon(self.hasIcon)
1506  
1507 if not self.cmd.options then
1508 self.cmd.options = {}
1509 end
1510  
1511 table.insert(self.cmd.options, {
1512 option = loc.ARGUMENT_SHOWICON,
1513 desc = loc.TEXT_TOGGLE_WHETHER_TO_SHOW_THE_ICON,
1514 method = "ToggleIconShown"
1515 })
1516  
1517 local old_Enable = self.Enable
1518 function self:Enable()
1519 if old_Enable then
1520 old_Enable(self)
1521 end
1522 if self:IsIconShown() then
1523 self.iconFrame:Show()
1524 else
1525 self.iconFrame:Hide()
1526 end
1527 self:CheckWidth(true)
1528 end
1529  
1530 local old_Report = self.Report
1531 if old_Report then
1532 function self:Report()
1533 old_Report(self)
1534 ace:print(" - ", format(ACE_CMD_REPORT_LINE, loc.ARGUMENT_SHOWICON, loc.MAP_ONOFF[self:IsIconShown() and 1 or 0]))
1535 end
1536 else
1537 function self:Report()
1538 local report = compost and compost:Acquire(
1539 compost:AcquireHash(
1540 'text', loc.ARGUMENT_SHOWICON,
1541 'val', self:IsIconShown() and 1 or 0,
1542 'map', loc.MAP_ONOFF
1543 )
1544 ) or {{
1545 text = loc.ARGUMENT_SHOWICON,
1546 val = self:IsIconShown() and 1 or 0,
1547 map = loc.MAP_ONOFF
1548 }}
1549 self.cmd:report(report)
1550 if compost then
1551 compost:Reclaim(report, 1)
1552 end
1553 end
1554 end
1555 end
1556  
1557 if not self.textFrame or not self.hasIcon then
1558 self.cannotHideText = true
1559 end
1560 if not self.cannotHideText then
1561 table.insert(self.cmd.options, {
1562 option = loc.ARGUMENT_SHOWTEXT,
1563 desc = loc.TEXT_TOGGLE_WHETHER_TO_SHOW_TEXT,
1564 method = "ToggleTextShown"
1565 })
1566  
1567 local old_Enable = self.Enable
1568 function self:Enable()
1569 if old_Enable then
1570 old_Enable(self)
1571 end
1572 if self:IsTextShown() then
1573 self.textFrame:Show()
1574 else
1575 self.textFrame:Hide()
1576 end
1577 self:CheckWidth(true)
1578 end
1579  
1580 local old_Report = self.Report
1581 if old_Report then
1582 function self:Report()
1583 old_Report(self)
1584 ace:print(" - ", format(ACE_CMD_REPORT_LINE, loc.ARGUMENT_SHOWTEXT, loc.MAP_ONOFF[self:IsTextShown() and 1 or 0]))
1585 end
1586 else
1587 function self:Report()
1588 local report = compost and compost:Acquire(
1589 compost:AcquireHash(
1590 'text', loc.ARGUMENT_SHOWTEXT,
1591 'val', self:IsTextShown() and 1 or 0,
1592 'map', loc.MAP_ONOFF
1593 )
1594 ) or {{
1595 text = loc.ARGUMENT_SHOWTEXT,
1596 val = self:IsTextShown() and 1 or 0,
1597 map = loc.MAP_ONOFF
1598 }}
1599 self.cmd:report(report)
1600 compost:Reclaim(report, 1)
1601 end
1602 end
1603 end
1604  
1605 if self.hideWithoutStandby then
1606 self:EnableHideWithoutStandby()
1607 end
1608  
1609 local old_Enable = self.Enable
1610 function self:Enable()
1611 if old_Enable then
1612 old_Enable(self)
1613 end
1614 if not self.hideWithoutStandby or not self.data.hidden then
1615 self:Show()
1616 end
1617 self:RegisterEvent("ACE_PROFILE_LOADED", "_OnAceProfileLoaded")
1618  
1619 if not self.overrideTooltip and not self.cannotDetachTooltip and self.data.detachedTooltip and self.data.detachedTooltip.detached then
1620 self:DetachTooltip()
1621 end
1622 end
1623  
1624 if self.db then
1625 local old_Initialize = self.Initialize
1626 function self:Initialize()
1627 local t = self.db._table
1628 if not t.profiles then
1629 t.profiles = {}
1630 end
1631 if not t.profiles[self.profilePath[2]] then
1632 t.profiles[self.profilePath[2]] = {}
1633 end
1634  
1635 if not t.realms then
1636 t.realms = {}
1637 end
1638 if not t.realms[GetRealmName() .. UnitFactionGroup("player")] then
1639 t.realms[GetRealmName() .. UnitFactionGroup("player")] = {}
1640 end
1641 if type(self.chardb) ~= "string" then
1642 if not t.chars then
1643 t.chars = {}
1644 end
1645 if not t.chars[GetRealmName() .. UnitName("player")] then
1646 t.chars[GetRealmName() .. UnitName("player")] = {}
1647 end
1648 self.charData = t.chars[GetRealmName() .. UnitName("player")]
1649 else
1650 local c = getglobal(self.chardb)
1651 if type(c) ~= "table" then
1652 setglobal(self.chardb, {})
1653 c = getglobal(self.chardb)
1654 end
1655 self.charData = c
1656 end
1657 if not t.classes then
1658 t.classes = {}
1659 end
1660 if not t.classes[UnitClass("player")] then
1661 t.classes[UnitClass("player")] = {}
1662 end
1663 if not t.full then
1664 t.full = {}
1665 end
1666 self.data = t.profiles[self.profilePath[2]]
1667 inheritDefaults(self.data, self.defaults)
1668 self.realmData = t.realms[GetRealmName() .. UnitFactionGroup("player")]
1669 inheritDefaults(self.realmData, self.realmDefaults)
1670 inheritDefaults(self.charData, self.charDefaults)
1671 self.classData = t.classes[UnitClass("player")]
1672 inheritDefaults(self.classData, self.classDefaults)
1673 self.fullData = t.full
1674 inheritDefaults(self.fullData, self.fullDefaults)
1675  
1676 self.data.version = VersionToNumber(self.data.version)
1677 self.charData.version = VersionToNumber(self.charData.version)
1678 self.classData.version = VersionToNumber(self.classData.version)
1679 self.realmData.version = VersionToNumber(self.realmData.version)
1680 self.fullData.version = VersionToNumber(self.fullData.version)
1681 if self.data.version >= 500 then
1682 self.data.version = self.data.version / 100
1683 self.charData.version = self.charData.version / 100
1684 self.classData.version = self.classData.version / 100
1685 self.realmData.version = self.realmData.version / 100
1686 self.fullData.version = self.fullData.version / 100
1687 end
1688  
1689 if old_Initialize then
1690 old_Initialize(self)
1691 end
1692  
1693 self.data.version = VersionToNumber(self.version)
1694 self.charData.version = VersionToNumber(self.version)
1695 self.classData.version = VersionToNumber(self.version)
1696 self.realmData.version = VersionToNumber(self.version)
1697 self.fullData.version = VersionToNumber(self.version)
1698 end
1699 elseif FuBar then
1700 local old_Initialize = self.Initialize
1701 function self:Initialize()
1702 local FuBarDB = FuBar2DB or FuBarDB
1703 if not FuBarDB.pluginDB then
1704 FuBarDB.pluginDB = {}
1705 end
1706  
1707 if not FuBarDB.pluginDB[self:GetTitle()] then
1708 FuBarDB.pluginDB[self:GetTitle()] = {}
1709 end
1710  
1711 local t = FuBarDB.pluginDB[self:GetTitle()]
1712  
1713 if not t.profiles then
1714 t.profiles = {}
1715 end
1716 if not t.profiles.default then
1717 t.profiles.default = {}
1718 end
1719 if not t.realms then
1720 t.realms = {}
1721 end
1722 if not t.realms[GetRealmName() .. UnitFactionGroup("player")] then
1723 t.realms[GetRealmName() .. UnitFactionGroup("player")] = {}
1724 end
1725 if type(self.chardb) ~= "string" then
1726 if not t.chars then
1727 t.chars = {}
1728 end
1729 if not t.chars[GetRealmName() .. UnitName("player")] then
1730 t.chars[GetRealmName() .. UnitName("player")] = {}
1731 end
1732 self.charData = t.chars[GetRealmName() .. UnitName("player")]
1733 else
1734 local c = getglobal(self.chardb)
1735 if type(c) ~= "table" then
1736 setglobal(self.chardb, {})
1737 c = getglobal(self.chardb)
1738 end
1739 self.charData = c
1740 end
1741 if not t.classes then
1742 t.classes = {}
1743 end
1744 if not t.classes[UnitClass("player")] then
1745 t.classes[UnitClass("player")] = {}
1746 end
1747 if not t.full then
1748 t.full = {}
1749 end
1750 self.data = t.profiles["default"]
1751 inheritDefaults(self.data, self.defaults)
1752 self.realmData = t.realms[GetRealmName() .. UnitFactionGroup("player")]
1753 inheritDefaults(self.realmData, self.realmDefaults)
1754 inheritDefaults(self.charData, self.charDefaults)
1755 self.classData = t.classes[UnitClass("player")]
1756 inheritDefaults(self.classData, self.classDefaults)
1757 self.fullData = t.full
1758 inheritDefaults(self.fullData, self.fullDefaults)
1759  
1760 if old_Initialize then
1761 old_Initialize(self)
1762 end
1763  
1764 self.data.version = VersionToNumber(self.version)
1765 self.charData.version = VersionToNumber(self.version)
1766 self.classData.version = VersionToNumber(self.version)
1767 self.realmData.version = VersionToNumber(self.version)
1768 self.fullData.version = VersionToNumber(self.version)
1769  
1770 if self.data.disabled then
1771 self:DisableAddon()
1772 end
1773 end
1774 else
1775 local old_Initialize = self.Initialize
1776 function self:Initialize()
1777 self.data = {}
1778 self.charData = {}
1779 self.classData = {}
1780 self.realmData = {}
1781 self.fullData = {}
1782  
1783 if old_Initialize then
1784 old_Initialize(self)
1785 end
1786  
1787 self.data.version = VersionToNumber(self.version)
1788 self.charData.version = VersionToNumber(self.version)
1789 self.classData.version = VersionToNumber(self.version)
1790 self.realmData.version = VersionToNumber(self.version)
1791 self.fullData.version = VersionToNumber(self.version)
1792 end
1793 end
1794  
1795 local old_Disable = self.Disable
1796 function self:Disable()
1797 if old_Disable then
1798 old_Disable(self)
1799 end
1800 self:Hide()
1801 end
1802  
1803 if not self.overrideTooltip then
1804 self._UpdateTooltip = self.UpdateTooltip
1805 function self:UpdateTooltip()
1806 RegisterTablet(self)
1807 tablet:Refresh(self.frame)
1808 end
1809 end
1810  
1811 local self_Initialize = self.Initialize
1812 function self:Initialize()
1813 self_Initialize(self)
1814  
1815 local profilePlugin = FuBar and FuBar:GetPluginProfiling()
1816  
1817 if self == profilePlugin then
1818 local start = GetTime()
1819 local tree = {}
1820 local treeMemories = {}
1821 local treeTimes = {}
1822 local memories = {}
1823 local times = {}
1824 local aname = self.name
1825 for name,value in pairs(self) do
1826 if type(value) == "function" and name ~= "Initialize" then
1827 local oldFunction = value
1828 local name = name
1829 local rName = name
1830 if name == "UpdateTooltip" then
1831 name = "tablet:Refresh"
1832 elseif name == "_UpdateTooltip" then
1833 name = "UpdateTooltip"
1834 end
1835 if strsub(name, 1, 1) ~= "_" then
1836 memories[name] = 0
1837 times[name] = 0
1838 self[rName] = function(self, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
1839 local pos = table.getn(tree)
1840 table.insert(tree, name)
1841 table.insert(treeMemories, 0)
1842 table.insert(treeTimes, 0)
1843 local t, mem = GetTime(), gcinfo()
1844 local r1, r2, r3, r4, r5, r6, r7, r8 = oldFunction(self, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
1845 mem, t = gcinfo() - mem, GetTime() - t
1846 if pos > 0 then
1847 treeMemories[pos] = treeMemories[pos] + mem
1848 treeTimes[pos] = treeTimes[pos] + t
1849 end
1850 local otherMem = table.remove(treeMemories)
1851 if mem - otherMem > 0 then
1852 memories[name] = memories[name] + mem - otherMem
1853 end
1854 times[name] = times[name] + t - table.remove(treeTimes)
1855 table.remove(tree)
1856 return r1, r2, r3, r4, r5, r6, r7, r8
1857 end
1858 end
1859 end
1860 end
1861  
1862 if not self.cmd.options then
1863 self.cmd.options = {}
1864 end
1865  
1866 table.insert(self.cmd.options, {
1867 option = loc.ARGUMENT_PROFILE,
1868 desc = loc.TEXT_LIST_PROFILING_INFO,
1869 method = "_ListProfileInfo"
1870 })
1871  
1872 function self:_ListProfileInfo()
1873 local duration = GetTime() - start
1874 for name in pairs(memories) do
1875 local mem = memories[name]
1876 local time = times[name]
1877 DEFAULT_CHAT_FRAME:AddMessage(string.format("%.3fs / %.3fs (%.3f%%) || %s (%d KiB)", times[name], duration, times[name] / duration * 100, name, memories[name]))
1878 end
1879 end
1880  
1881 function self:GetProfileInfo()
1882 return GetTime() - start, times, memories
1883 end
1884 end
1885 end
1886  
1887 if self.defaultPosition ~= "LEFT" and self.defaultPosition ~= "CENTER" and self.defaultPosition ~= "RIGHT" and self.defaultPosition ~= "MINIMAP" then
1888 self.defaultPosition = "LEFT"
1889 end
1890 if type(self.defaultMinimapPosition) ~= "number" then
1891 self.defaultMinimapPosition = math.random(1, 360)
1892 end
1893  
1894 self.frame:RegisterEvent("PLAYER_LOGOUT")
1895 local OnEvent = self.frame:GetScript("OnEvent")
1896 self.frame:SetScript("OnEvent", function()
1897 if OnEvent then
1898 OnEvent()
1899 end
1900 if event == "PLAYER_LOGOUT" then
1901 local t
1902 if self.db then
1903 t = self.db._table
1904 elseif FuBar then
1905 local FuBarDB = FuBar2DB or FuBarDB
1906 t = FuBarDB.pluginDB[self:GetTitle()]
1907 else
1908 return
1909 end
1910 if cleanDefaults(self.data, self.defaults) then
1911 if self.db then
1912 t.profiles[self.profilePath[2]] = nil
1913 else
1914 t.profiles["default"] = nil
1915 end
1916 if not next(t.profiles) then
1917 t.profiles = nil
1918 end
1919 end
1920 if cleanDefaults(self.charData, self.charDefaults) then
1921 if type(self.chardb) ~= "string" then
1922 t.chars[ace.char.realm .. ace.char.name] = nil
1923 if not next(t.chars) then
1924 t.chars = nil
1925 end
1926 else
1927 setglobal(self.chardb, nil)
1928 end
1929 end
1930 if cleanDefaults(self.fullData, self.fullDefaults) then
1931 t.full = nil
1932 end
1933 if cleanDefaults(self.realmData, self.realmDefaults) then
1934 t.realms[ace.char.realm .. ace.char.faction] = nil
1935 if not next(t.realms) then
1936 t.realms = nil
1937 end
1938 end
1939 if cleanDefaults(self.classData, self.classDefaults) then
1940 t.classes[ace.char.class] = nil
1941 if not next(t.classes) then
1942 t.classes = nil
1943 end
1944 end
1945 if not next(t) then
1946 if self.db then
1947 setglobal(self.db.name, nil)
1948 else
1949 local FuBarDB = FuBar2DB or FuBarDB
1950 FuBarDB.pluginDB[self:GetTitle()] = nil
1951 end
1952 end
1953 end
1954 end)
1955  
1956 local old_Initialize = self.Initialize
1957 local initialized = false
1958 function self:Initialize()
1959 if initialized then
1960 return
1961 end
1962 initialized = true
1963 if old_Initialize then
1964 old_Initialize(self)
1965 end
1966 end
1967  
1968 local enabled = false
1969 local old_Enable = self.Enable
1970 function self:Enable()
1971 if not enabled and old_Enable then
1972 enabled = true
1973 old_Enable(self)
1974 elseif not old_Enable then
1975 enabled = true
1976 end
1977 end
1978  
1979 local old_Disable = self.Disable
1980 function self:Disable()
1981 if enabled and old_Disable then
1982 enabled = false
1983 old_Disable(self)
1984 elseif not old_Disable then
1985 enabled = false
1986 end
1987 end
1988  
1989 AceAddon.RegisterForLoad(self)
1990 if FuBar then
1991 FuBar:RegisterPlugin(self)
1992 end
1993 end
1994  
1995 function lib:GetLibraryVersion()
1996 return MAJOR_VERSION, MINOR_VERSION
1997 end
1998  
1999 function lib:LibActivate(stub, oldLib, oldList)
2000 end
2001  
2002 function lib:LibDeactivate()
2003 end
2004  
2005 function lib:new(o)
2006 local mt = { __index = self }
2007 if type(o) ~= "table" then
2008 o = {}
2009 end
2010 return setmetatable(o, mt)
2011 end
2012  
2013 function lib:CreateBasicPluginFrame(name)
2014 local frame = CreateFrame("Button", name, UIParent)
2015 frame:SetFrameStrata("HIGH")
2016 frame:EnableMouse(true)
2017 frame:EnableMouseWheel(true)
2018 frame:SetMovable(true)
2019 frame:SetWidth(150)
2020 frame:SetHeight(24)
2021 frame:SetPoint("CENTER", UIParent, "CENTER")
2022  
2023 frame:SetScript("OnClick", function()
2024 if type(self.OnClick) == "function" then
2025 self:OnClick()
2026 end
2027 end)
2028 frame:SetScript("OnDoubleClick", function()
2029 if type(self.OnDoubleClick) == "function" then
2030 self:OnDoubleClick()
2031 end
2032 end)
2033 frame:SetScript("OnMouseDown", function()
2034 if arg1 == "RightButton" and not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() then
2035 self:OpenMenu()
2036 return
2037 else
2038 HideDropDownMenu(1)
2039 if type(self.OnMouseDown) == "function" then
2040 self:OnMouseDown(arg1)
2041 end
2042 end
2043 end)
2044 frame:SetScript("OnMouseUp", function()
2045 if type(self.OnMouseUp) == "function" then
2046 self:OnMouseUp(arg1)
2047 end
2048 end)
2049 return frame
2050 end
2051  
2052 function lib:CreatePluginChildFrame(frameType, name, parent)
2053 assert(self.frame, "You must have self.frame declared in order to add child frames")
2054 self:argCheck(frameType, 1, "string")
2055 local child = CreateFrame(frameType, name, parent)
2056 if parent then
2057 child:SetFrameLevel(parent:GetFrameLevel() + 2)
2058 end
2059 child:SetScript("OnEnter", function()
2060 if self.frame:GetScript("OnEnter") then
2061 self.frame:GetScript("OnEnter")()
2062 end
2063 end)
2064 child:SetScript("OnLeave", function()
2065 if self.frame:GetScript("OnLeave") then
2066 self.frame:GetScript("OnLeave")()
2067 end
2068 end)
2069 if child:HasScript("OnClick") then
2070 child:SetScript("OnClick", function()
2071 if self.frame:HasScript("OnClick") and self.frame:GetScript("OnClick") then
2072 self.frame:GetScript("OnClick")()
2073 end
2074 end)
2075 end
2076 if child:HasScript("OnDoubleClick") then
2077 child:SetScript("OnDoubleClick", function()
2078 if self.frame:HasScript("OnDoubleClick") and self.frame:GetScript("OnDoubleClick") then
2079 self.frame:GetScript("OnDoubleClick")()
2080 end
2081 end)
2082 end
2083 child:SetScript("OnMouseDown", function()
2084 if self.frame:GetScript("OnMouseDown") then
2085 self.frame:GetScript("OnMouseDown")()
2086 end
2087 end)
2088 child:SetScript("OnMouseUp", function()
2089 if self.frame:GetScript("OnMouseUp") then
2090 self.frame:GetScript("OnMouseUp")()
2091 end
2092 end)
2093 return child
2094 end
2095  
2096 function lib:OpenMenu(frame)
2097 if not frame then
2098 frame = self:GetFrame()
2099 end
2100 if not frame or not self:GetFrame() or dewdrop:IsOpen(frame) then
2101 dewdrop:Close()
2102 return
2103 end
2104 tablet:Close()
2105  
2106 if not dewdrop:IsRegistered(self:GetFrame()) then
2107 dewdrop:Register(self:GetFrame(),
2108 'children', function(level, value, valueN_1, valueN_2, valueN_3, valueN_4)
2109 if level == 1 then
2110 dewdrop:AddLine(
2111 'text', self:GetTitle(),
2112 'isTitle', true
2113 )
2114 end
2115  
2116 if self.MenuSettings then
2117 self:MenuSettings(level, value, false, valueN_1, valueN_2, valueN_3, valueN_4)
2118 end
2119  
2120 if level == 1 and not self.overrideMenu then
2121 if self.MenuSettings then
2122 dewdrop:AddLine()
2123 end
2124 self:AddImpliedMenuOptions()
2125 end
2126 if level == 1 then
2127 dewdrop:AddLine(
2128 'text', CLOSE,
2129 'func', dewdrop.Close,
2130 'arg1', dewdrop
2131 )
2132 end
2133 end,
2134 'point', function(frame)
2135 local x, y = frame:GetCenter()
2136 local leftRight
2137 if x < GetScreenWidth() / 2 then
2138 leftRight = "LEFT"
2139 else
2140 leftRight = "RIGHT"
2141 end
2142 if y < GetScreenHeight() / 2 then
2143 return "BOTTOM" .. leftRight, "TOP" .. leftRight
2144 else
2145 return "TOP" .. leftRight, "BOTTOM" .. leftRight
2146 end
2147 end,
2148 'dontHook', true
2149 )
2150 end
2151 if frame == self:GetFrame() then
2152 dewdrop:Open(self:GetFrame())
2153 else
2154 dewdrop:Open(frame, self:GetFrame())
2155 end
2156 end
2157  
2158 FuBarPlugin:Register(lib)
2159 lib = nil
2160  
2161 if not FuBarPlugin.new then
2162 function FuBarPlugin:new(o)
2163 self:GetInstance(MAJOR_VERSION):assert(type(o) == "table", "You must provide a table to register")
2164 local name
2165 if o.name then
2166 name = o.name .. ": "
2167 else
2168 name = ""
2169 end
2170 self:GetInstance(MAJOR_VERSION):assert(o.fuCompatible, name .. "You must provide a fuCompatible field.")
2171 local compatNumber = VersionToNumber(o.fuCompatible)
2172 if compatNumber >= 500 then
2173 compatNumber = compatNumber / 100
2174 end
2175 if compatNumber < 101 then
2176 return self.versions["1.0"] and self:GetInstance("1.0"):new(o)
2177 elseif compatNumber < 103 then
2178 return self.versions["1.2"] and self:GetInstance("1.2"):new(o)
2179 end
2180 end
2181 end
2182 end
2183  
2184 -- MinimapContainer
2185 do
2186 local lib = {}
2187  
2188 local initialized = false
2189 function lib:Initialize()
2190 if initialized then
2191 return
2192 end
2193 initialized = true
2194  
2195 self.plugins = {}
2196 end
2197  
2198 function lib:AddPlugin(plugin)
2199 if FuBar and FuBar:IsChangingProfile() then
2200 return
2201 end
2202 self:Initialize()
2203 if plugin.panel ~= nil then
2204 plugin.panel:RemovePlugin(plugin)
2205 end
2206 plugin.panel = self
2207 if not plugin.minimapFrame then
2208 local frame = CreateFrame("Button", plugin.frame:GetName() .. "MinimapButton", Minimap)
2209 plugin.minimapFrame = frame
2210 RegisterTablet(plugin)
2211 tablet:Register(frame, plugin.frame)
2212 frame.plugin = plugin
2213 frame:SetWidth(31)
2214 frame:SetHeight(31)
2215 frame:SetFrameStrata("LOW")
2216 frame:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight")
2217 local icon = frame:CreateTexture(frame:GetName() .. "Icon", "BACKGROUND")
2218 plugin.minimapIcon = icon
2219 local path = plugin:GetIcon() or (plugin.iconFrame and plugin.iconFrame:GetTexture()) or "Interface\\Icons\\INV_Misc_QuestionMark"
2220 icon:SetTexture(path)
2221 if string.sub(path, 1, 16) == "Interface\\Icons\\" then
2222 icon:SetTexCoord(0.05, 0.95, 0.05, 0.95)
2223 else
2224 icon:SetTexCoord(0, 1, 0, 1)
2225 end
2226 icon:SetWidth(20)
2227 icon:SetHeight(20)
2228 icon:SetPoint("TOPLEFT", frame, "TOPLEFT", 7, -5)
2229 local overlay = frame:CreateTexture(frame:GetName() .. "Overlay","OVERLAY")
2230 overlay:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
2231 overlay:SetWidth(53)
2232 overlay:SetHeight(53)
2233 overlay:SetPoint("TOPLEFT",frame,"TOPLEFT")
2234 frame:EnableMouse(true)
2235 frame:RegisterForClicks("LeftButtonUp")
2236 frame.plugin = plugin
2237 if type(plugin.OnClick) == "function" then
2238 frame:SetScript("OnClick", function()
2239 if not this.dragged then
2240 plugin:OnClick(arg1)
2241 end
2242 end)
2243 end
2244 if type(plugin.OnDoubleClick) == "function" then
2245 frame:SetScript("OnDoubleClick", function()
2246 plugin:OnDoubleClick(arg1)
2247 end)
2248 end
2249 frame:SetScript("OnMouseDown", function()
2250 this.dragged = false
2251 if arg1 == "LeftButton" and not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() then
2252 HideDropDownMenu(1)
2253 if type(plugin.OnMouseDown) == "function" then
2254 plugin:OnMouseDown(arg1)
2255 end
2256 elseif arg1 == "RightButton" and not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() then
2257 plugin:OpenMenu(frame)
2258 else
2259 HideDropDownMenu(1)
2260 if type(plugin.OnMouseDown) == "function" then
2261 plugin:OnMouseDown(arg1)
2262 end
2263 end
2264 if plugin.OnClick or plugin.OnMouseDown or plugin.OnMouseUp or plugin.OnDoubleClick then
2265 if string.sub(this.plugin.minimapIcon:GetTexture(), 1, 16) == "Interface\\Icons\\" then
2266 plugin.minimapIcon:SetTexCoord(0.14, 0.86, 0.14, 0.86)
2267 else
2268 plugin.minimapIcon:SetTexCoord(0.1, 0.9, 0.1, 0.9)
2269 end
2270 end
2271 end)
2272 frame:SetScript("OnMouseUp", function()
2273 if not this.dragged and type(plugin.OnMouseUp) == "function" then
2274 plugin:OnMouseUp(arg1)
2275 end
2276 if string.sub(this.plugin.minimapIcon:GetTexture(), 1, 16) == "Interface\\Icons\\" then
2277 plugin.minimapIcon:SetTexCoord(0.05, 0.95, 0.05, 0.95)
2278 else
2279 plugin.minimapIcon:SetTexCoord(0, 1, 0, 1)
2280 end
2281 end)
2282 frame:RegisterForDrag("LeftButton")
2283 frame:SetScript("OnDragStart", self.OnDragStart)
2284 frame:SetScript("OnDragStop", self.OnDragStop)
2285 end
2286 plugin.frame:Hide()
2287 plugin.minimapFrame:Show()
2288 self:ReadjustLocation(plugin)
2289 table.insert(self.plugins, plugin)
2290 local exists = false
2291 return true
2292 end
2293  
2294 function lib:RemovePlugin(index)
2295 if FuBar and FuBar:IsChangingProfile() then
2296 return
2297 end
2298 self:Initialize()
2299 if type(index) == "table" then
2300 index = self:IndexOfPlugin(index)
2301 if not index then
2302 return
2303 end
2304 end
2305 local t = self.plugins
2306 local plugin = t[index]
2307 assert(plugin.panel == self, "Plugin has improper panel field")
2308 plugin:SetPanel(nil)
2309 table.remove(t, index)
2310 return true
2311 end
2312  
2313 function lib:ReadjustLocation(plugin)
2314 local frame = plugin.minimapFrame
2315 if not plugin.data.minimapPositionWild then
2316 local position = plugin.data.minimapPosition or plugin.defaultMinimapPosition or math.random(1, 360)
2317 local angle = math.rad(position or 0)
2318 local x = math.cos(angle) * 80
2319 local y = math.sin(angle) * 80
2320 frame:SetPoint("CENTER", Minimap, "CENTER", x, y)
2321 else
2322 frame:SetPoint("CENTER", UIParent, "BOTTOMLEFT", plugin.data.minimapPositionX, plugin.data.minimapPositionY)
2323 end
2324 end
2325  
2326 function lib:GetPlugin(index)
2327 return self.plugins[index]
2328 end
2329  
2330 function lib:GetNumPlugins()
2331 return table.getn(self.plugins)
2332 end
2333  
2334 function lib:IndexOfPlugin(plugin)
2335 for i,p in ipairs(self.plugins) do
2336 if p == plugin then
2337 return i, "MINIMAP"
2338 end
2339 end
2340 end
2341  
2342 function lib:HasPlugin(plugin)
2343 return self:IndexOfPlugin(plugin) ~= nil
2344 end
2345  
2346 function lib:GetPluginSide(plugin)
2347 local index = self:IndexOfPlugin(plugin)
2348 assert(index, "Plugin not in panel")
2349 return "MINIMAP"
2350 end
2351  
2352 function lib.OnDragStart()
2353 this.dragged = true
2354 this:LockHighlight()
2355 this:SetScript("OnUpdate", FuBarPlugin.MinimapContainer:GetInstance(MAJOR_VERSION).OnUpdate)
2356 if string.sub(this.plugin.minimapIcon:GetTexture(), 1, 16) == "Interface\\Icons\\" then
2357 this.plugin.minimapIcon:SetTexCoord(0.05, 0.95, 0.05, 0.95)
2358 else
2359 this.plugin.minimapIcon:SetTexCoord(0, 1, 0, 1)
2360 end
2361 end
2362  
2363 function lib.OnDragStop()
2364 this:SetScript("OnUpdate", nil)
2365 this:UnlockHighlight()
2366 end
2367  
2368 function lib.OnUpdate()
2369 if not IsAltKeyDown() then
2370 local mx, my = Minimap:GetCenter()
2371 local px, py = GetCursorPosition()
2372 local scale = UIParent:GetEffectiveScale()
2373 px, py = px / scale, py / scale
2374 local lastPosition = this.plugin.data.minimapPosition
2375 local position = math.deg(math.atan2(py - my, px - mx))
2376 if position <= 0 then
2377 position = position + 360
2378 elseif position > 360 then
2379 position = position - 360
2380 end
2381 this.plugin.data.minimapPosition = position
2382 this.plugin.data.minimapPositionX = nil
2383 this.plugin.data.minimapPositionY = nil
2384 this.plugin.data.minimapPositionWild = nil
2385 else
2386 local px, py = GetCursorPosition()
2387 local scale = UIParent:GetEffectiveScale()
2388 px, py = px / scale, py / scale
2389 this.plugin.data.minimapPositionX = px
2390 this.plugin.data.minimapPositionY = py
2391 this.plugin.data.minimapPosition = nil
2392 this.plugin.data.minimapPositionWild = true
2393 end
2394 FuBarPlugin.MinimapContainer:GetInstance(MAJOR_VERSION):ReadjustLocation(this.plugin)
2395 end
2396  
2397 function lib:GetLibraryVersion()
2398 return MAJOR_VERSION, MINOR_VERSION
2399 end
2400  
2401 function lib:LibActivate(stub, oldLib, oldList)
2402 end
2403  
2404 function lib:LibDeactivate()
2405 end
2406  
2407 FuBarPlugin.MinimapContainer:Register(lib)
2408 lib = nil
2409 end