TourGuide - Fix Issue #136
[WoW-TourGuide.git] / OptionHouse.lua
blob07161f522f45fcfa2aba0838749cb4723c9d11b7
1 -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
2 -- LibStub is hereby placed in the Public Domain
3 -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
4 local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
5 local LibStub = _G[LIBSTUB_MAJOR]
7 -- Check to see is this version of the stub is obsolete
8 if not LibStub or LibStub.minor < LIBSTUB_MINOR then
9 LibStub = LibStub or {libs = {}, minors = {} }
10 _G[LIBSTUB_MAJOR] = LibStub
11 LibStub.minor = LIBSTUB_MINOR
13 -- LibStub:NewLibrary(major, minor)
14 -- major (string) - the major version of the library
15 -- minor (string or number ) - the minor version of the library
16 --
17 -- returns nil if a newer or same version of the lib is already present
18 -- returns empty library object or old library object if upgrade is needed
19 function LibStub:NewLibrary(major, minor)
20 assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
21 minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
23 local oldminor = self.minors[major]
24 if oldminor and oldminor >= minor then return nil end
25 self.minors[major], self.libs[major] = minor, self.libs[major] or {}
26 return self.libs[major], oldminor
27 end
29 -- LibStub:GetLibrary(major, [silent])
30 -- major (string) - the major version of the library
31 -- silent (boolean) - if true, library is optional, silently return nil if its not found
33 -- throws an error if the library can not be found (except silent is set)
34 -- returns the library object if found
35 function LibStub:GetLibrary(major, silent)
36 if not self.libs[major] and not silent then
37 error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
38 end
39 return self.libs[major], self.minors[major]
40 end
42 -- LibStub:IterateLibraries()
43 --
44 -- Returns an iterator for the currently registered libraries
45 function LibStub:IterateLibraries()
46 return pairs(self.libs)
47 end
49 setmetatable(LibStub, { __call = LibStub.GetLibrary })
50 end
52 --[[-------------------------------------------------------------------------
53 Copyright (c) 2006-2007, Dongle Development Team
54 All rights reserved.
56 Redistribution and use in source and binary forms, with or without
57 modification, are permitted provided that the following conditions are
58 met:
60 * Redistributions of source code must retain the above copyright
61 notice, this list of conditions and the following disclaimer.
62 * Redistributions in binary form must reproduce the above
63 copyright notice, this list of conditions and the following
64 disclaimer in the documentation and/or other materials provided
65 with the distribution.
66 * Neither the name of the Dongle Development Team nor the names of
67 its contributors may be used to endorse or promote products derived
68 from this software without specific prior written permission.
70 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
71 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
72 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
73 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
74 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
75 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
76 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
77 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
78 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
79 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
80 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
81 ---------------------------------------------------------------------------]]
83 --[[-------------------------------------------------------------------------
84 Begin Library Implementation
85 ---------------------------------------------------------------------------]]
86 local major = "OptionHouse-1.1"
87 local minor = tonumber(string.match("$Revision: 619 $", "(%d+)") or 1)
89 assert(LibStub, string.format("%s requires LibStub.", major))
91 local OHInstance, oldRevision = LibStub:NewLibrary(major, minor)
92 if( not OHInstance ) then return end
94 local L = {
95 ["ERROR_NO_FRAME"] = "No frame returned for the addon \"%s\", category \"%s\", sub category \"%s\".",
96 ["NO_FUNC_PASSED"] = "You must associate a function with a category.",
97 ["BAD_ARGUMENT"] = "bad argument #%d to '%s' (%s expected, got %s)",
98 ["MUST_CALL"] = "You must call '%s' from an OptionHouse addon object.",
99 ["ADDON_ALREADYREG"] = "The addon '%s' is already registered with OptionHouse.",
100 ["UNKNOWN_TAB"] = "Cannot open tab #%d, only %d tabs are registered.",
101 ["CATEGORY_ALREADYREG"] = "The category '%s' already exists in '%s'",
102 ["NO_CATEGORYEXISTS"] = "No category named '%s' in '%s' exists.",
103 ["NO_SUBCATEXISTS"] = "No sub-category '%s' exists in '%s' for the addon '%s'.",
104 ["NO_PARENTCAT"] = "No parent category named '%s' exists in %s'",
105 ["SUBCATEGORY_ALREADYREG"] = "The sub-category named '%s' already exists in the category '%s' for '%s'",
106 ["UNKNOWN_FRAMETYPE"] = "Unknown frame type given '%s', only 'main', 'perf', 'addon', 'config' are supported.",
107 ["OPTION_HOUSE"] = "Option House",
108 ["ENTERED_COMBAT"] = "|cFF33FF99Option House|r: Configuration window closed due to entering combat.",
109 ["SEARCH"] = "Search...",
110 ["ADDON_OPTIONS"] = "Addons",
111 ["VERSION"] = "Version: %s",
112 ["AUTHOR"] = "Author: %s",
113 ["TOTAL_SUBCATEGORIES"] = "Sub Categories: %d",
114 ["TAB_MANAGEMENT"] = "Management",
115 ["TAB_PERFORMANCE"] = "Performance",
118 local function assert(level,condition,message)
119 if( not condition ) then
120 error(message,level)
124 local function argcheck(value, num, ...)
125 if( type(num) ~= "number" ) then
126 error(L["BAD_ARGUMENT"]:format(2, "argcheck", "number", type(num)), 1)
129 for i=1,select("#", ...) do
130 if( type(value) == select(i, ...) ) then return end
133 local types = string.join(", ", ...)
134 local name = string.match(debugstack(2,2,0), ": in function [`<](.-)['>]")
135 error(L["BAD_ARGUMENT"]:format(num, name, types, type(value)), 3)
138 -- OptionHouse
139 local OptionHouse = {}
140 local tabfunctions = {}
141 local methods = {"RegisterCategory", "RegisterSubCategory", "RemoveCategory", "RemoveSubCategory"}
142 local addons = {}
143 local regFrames = {}
144 local evtFrame
145 local frame
147 -- TABS
148 local function resizeTab(tab)
149 local textWidth = tab:GetFontString():GetWidth()
151 tab.middleActive:SetWidth(textWidth)
152 tab.middleInactive:SetWidth(textWidth)
154 tab:SetWidth((2 * tab.leftActive:GetWidth()) + textWidth)
155 tab.highlightTexture:SetWidth(textWidth + 20)
158 local function tabSelected(tab)
159 tab:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
160 tab.highlightTexture:Hide()
162 tab.leftActive:Show()
163 tab.middleActive:Show()
164 tab.rightActive:Show()
166 tab.leftInactive:Hide()
167 tab.middleInactive:Hide()
168 tab.rightInactive:Hide()
171 local function tabDeselected(tab)
172 tab:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
173 tab.highlightTexture:Show()
175 tab.leftInactive:Show()
176 tab.middleInactive:Show()
177 tab.rightInactive:Show()
179 tab.leftActive:Hide()
180 tab.middleActive:Hide()
181 tab.rightActive:Hide()
184 local function setTab(id)
185 if( frame.selectedTab ) then
186 tabDeselected(frame.tabs[frame.selectedTab])
189 frame.selectedTab = id
190 tabSelected(frame.tabs[id])
193 local function tabOnClick(self)
194 local id
195 if( type(self) ~= "number" ) then
196 id = self:GetID()
197 else
198 id = self
201 setTab(id)
203 for tabID, tab in pairs(tabfunctions) do
204 if( tabID == id ) then
205 if( type(tab.func) == "function" ) then
206 tab.func()
207 else
208 tab.handler[tab.func](tab.handler)
211 if( tab.type == "browse" ) then
212 frame.topLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-TopLeft")
213 frame.top:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-Top")
214 frame.topRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-TopRight")
215 frame.bottomLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-BotLeft")
216 frame.bottom:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-Bot")
217 frame.bottomRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-BotRight")
218 elseif( tab.type == "bid" ) then
219 frame.topLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-TopLeft")
220 frame.top:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-Top")
221 frame.topRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-TopRight")
222 frame.bottomLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-BotLeft")
223 frame.bottom:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-Bot")
224 frame.bottomRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-BotRight")
227 elseif( type(tab.func) == "function" ) then
228 tab.func(true)
229 else
230 tab.handler[tab.func](tab.handler, true)
235 local function createTab(text, id)
236 local tab = frame.tabs[id]
237 if( not tab ) then
238 tab = CreateFrame("Button", nil, frame)
239 tab:SetHighlightFontObject(GameFontHighlightSmall)
240 tab:SetTextFontObject(GameFontNormalSmall)
241 tab:SetHighlightTexture("Interface\\PaperDollInfoFrame\\UI-Character-Tab-Highlight")
242 tab:SetText(text)
243 tab:SetWidth(115)
244 tab:SetHeight(32)
245 tab:SetID(id)
246 tab:SetScript("OnClick", tabOnClick)
247 tab:GetFontString():SetPoint("CENTER", 0, 2)
249 tab.highlightTexture = tab:GetHighlightTexture()
250 tab.highlightTexture:ClearAllPoints()
251 tab.highlightTexture:SetPoint("CENTER", tab:GetFontString(), 0, 0)
252 tab.highlightTexture:SetBlendMode("ADD")
254 -- TAB SELECTED TEXTURES
255 tab.leftActive = tab:CreateTexture(nil, "ARTWORK")
256 tab.leftActive:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ActiveTab")
257 tab.leftActive:SetHeight(32)
258 tab.leftActive:SetWidth(20)
259 tab.leftActive:SetPoint("TOPLEFT", tab, "TOPLEFT")
260 tab.leftActive:SetTexCoord(0, 0.15625, 0, 1.0)
262 tab.middleActive = tab:CreateTexture(nil, "ARTWORK")
263 tab.middleActive:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ActiveTab")
264 tab.middleActive:SetHeight(32)
265 tab.middleActive:SetWidth(20)
266 tab.middleActive:SetPoint("LEFT", tab.leftActive, "RIGHT")
267 tab.middleActive:SetTexCoord(0.15625, 0.84375, 0, 1.0)
269 tab.rightActive = tab:CreateTexture(nil, "ARTWORK")
270 tab.rightActive:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ActiveTab")
271 tab.rightActive:SetHeight(32)
272 tab.rightActive:SetWidth(20)
273 tab.rightActive:SetPoint("LEFT", tab.middleActive, "RIGHT")
274 tab.rightActive:SetTexCoord(0.84375, 1.0, 0, 1.0)
276 -- TAB DESELECTED TEXTURES
277 tab.leftInactive = tab:CreateTexture(nil, "ARTWORK")
278 tab.leftInactive:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-InActiveTab")
279 tab.leftInactive:SetHeight(32)
280 tab.leftInactive:SetWidth(20)
281 tab.leftInactive:SetPoint("TOPLEFT", tab, "TOPLEFT")
282 tab.leftInactive:SetTexCoord(0, 0.15625, 0, 1.0)
284 tab.middleInactive = tab:CreateTexture(nil, "ARTWORK")
285 tab.middleInactive:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-InActiveTab")
286 tab.middleInactive:SetHeight(32)
287 tab.middleInactive:SetWidth(20)
288 tab.middleInactive:SetPoint("LEFT", tab.leftInactive, "RIGHT")
289 tab.middleInactive:SetTexCoord(0.15625, 0.84375, 0, 1.0)
291 tab.rightInactive = tab:CreateTexture(nil, "ARTWORK")
292 tab.rightInactive:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-InActiveTab")
293 tab.rightInactive:SetHeight(32)
294 tab.rightInactive:SetWidth(20)
295 tab.rightInactive:SetPoint("LEFT", tab.middleInactive, "RIGHT")
296 tab.rightInactive:SetTexCoord(0.84375, 1.0, 0, 1.0)
298 frame.totalTabs = frame.totalTabs + 1
299 frame.tabs[id] = tab
302 tab:SetText(text)
303 tab:Show()
305 tabDeselected(tab)
306 resizeTab(tab)
308 if( id == 1 ) then
309 tab:SetPoint("TOPLEFT", frame, "BOTTOMLEFT", 15, 11)
310 else
311 tab:SetPoint("TOPLEFT", frame.tabs[id - 1], "TOPRIGHT", -8, 0)
315 -- SCROLL FRAME
316 local function onVerticalScroll(self, offset)
317 offset = ceil(offset)
319 self.bar:SetValue(offset)
320 self.offset = ceil(offset / self.displayNum)
322 if( self.offset < 0 ) then
323 self.offset = 0
326 local min, max = self.bar:GetMinMaxValues()
328 if( min == offset ) then
329 self.up:Disable()
330 else
331 self.up:Enable()
334 if( max == offset ) then
335 self.down:Disable()
336 else
337 self.down:Enable()
340 self.updateFunc()
343 local function onMouseWheel(self, offset)
344 if( self.scroll ) then self = self.scroll end
345 if( offset > 0 ) then
346 self.bar:SetValue(self.bar:GetValue() - (self.bar:GetHeight() / 2))
347 else
348 self.bar:SetValue(self.bar:GetValue() + (self.bar:GetHeight() / 2))
352 local function onParentMouseWheel(self, offset)
353 onMouseWheel(self.scroll, offset)
356 local function updateScroll(scroll, totalRows)
357 local max = (totalRows - scroll.displayNum) * scroll.displayNum
359 -- Macs are unhappy if max is less then the min
360 if( max < 0 ) then
361 max = 0
364 scroll.bar:SetMinMaxValues(0, max)
366 if( totalRows > scroll.displayNum ) then
367 scroll:Show()
368 scroll.bar:Show()
369 scroll.up:Show()
370 scroll.down:Show()
371 scroll.bar:GetThumbTexture():Show()
372 else
373 scroll:Hide()
374 scroll.bar:Hide()
375 scroll.up:Hide()
376 scroll.down:Hide()
377 scroll.bar:GetThumbTexture():Hide()
381 local function onValueChanged(self, offset)
382 self:GetParent():SetVerticalScroll(offset)
385 local function scrollButtonUp(self)
386 local parent = self:GetParent()
387 parent:SetValue(parent:GetValue() - (parent:GetHeight() / 2))
388 PlaySound("UChatScrollButton")
391 local function scrollButtonDown(self)
392 local parent = self:GetParent()
393 parent:SetValue(parent:GetValue() + (parent:GetHeight() / 2))
394 PlaySound("UChatScrollButton")
397 local function createScrollFrame(frame, displayNum, onScroll)
398 frame:EnableMouseWheel(true)
399 frame:SetScript("OnMouseWheel", onParentMouseWheel)
401 frame.scroll = CreateFrame("ScrollFrame", nil, frame)
402 frame.scroll:EnableMouseWheel(true)
403 frame.scroll:SetWidth(16)
404 frame.scroll:SetHeight(270)
405 frame.scroll:SetScript("OnVerticalScroll", onVerticalScroll)
406 frame.scroll:SetScript("OnMouseWheel", onMouseWheel)
408 frame.scroll.offset = 0
409 frame.scroll.displayNum = displayNum
410 frame.scroll.updateFunc = onScroll
412 -- Actual bar for scrolling
413 frame.scroll.bar = CreateFrame("Slider", nil, frame.scroll)
414 frame.scroll.bar:SetValueStep(frame.scroll.displayNum)
415 frame.scroll.bar:SetMinMaxValues(0, 0)
416 frame.scroll.bar:SetValue(0)
417 frame.scroll.bar:SetWidth(16)
418 frame.scroll.bar:SetScript("OnValueChanged", onValueChanged)
419 frame.scroll.bar:SetPoint("TOPLEFT", frame.scroll, "TOPRIGHT", 6, -16)
420 frame.scroll.bar:SetPoint("BOTTOMLEFT", frame.scroll, "BOTTOMRIGHT", 6, -16)
422 -- Up/Down buttons
423 frame.scroll.up = CreateFrame("Button", nil, frame.scroll.bar, "UIPanelScrollUpButtonTemplate")
424 frame.scroll.up:ClearAllPoints()
425 frame.scroll.up:SetPoint( "BOTTOM", frame.scroll.bar, "TOP" )
426 frame.scroll.up:SetScript("OnClick", scrollButtonUp)
428 frame.scroll.down = CreateFrame("Button", nil, frame.scroll.bar, "UIPanelScrollDownButtonTemplate")
429 frame.scroll.down:ClearAllPoints()
430 frame.scroll.down:SetPoint( "TOP", frame.scroll.bar, "BOTTOM" )
431 frame.scroll.down:SetScript("OnClick", scrollButtonDown)
433 -- That square thingy that shows where the bar is
434 frame.scroll.bar:SetThumbTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
435 local thumb = frame.scroll.bar:GetThumbTexture()
437 thumb:SetHeight(16)
438 thumb:SetWidth(16)
439 thumb:SetTexCoord(0.25, 0.75, 0.25, 0.75)
441 -- Border graphic
442 frame.scroll.barUpTexture = frame.scroll:CreateTexture(nil, "BACKGROUND")
443 frame.scroll.barUpTexture:SetWidth(31)
444 frame.scroll.barUpTexture:SetHeight(256)
445 frame.scroll.barUpTexture:SetPoint("TOPLEFT", frame.scroll.up, "TOPLEFT", -7, 5)
446 frame.scroll.barUpTexture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ScrollBar")
447 frame.scroll.barUpTexture:SetTexCoord(0, 0.484375, 0, 1.0)
449 frame.scroll.barDownTexture = frame.scroll:CreateTexture(nil, "BACKGROUND")
450 frame.scroll.barDownTexture:SetWidth(31)
451 frame.scroll.barDownTexture:SetHeight(106)
452 frame.scroll.barDownTexture:SetPoint("BOTTOMLEFT", frame.scroll.down, "BOTTOMLEFT", -7, -3)
453 frame.scroll.barDownTexture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ScrollBar")
454 frame.scroll.barDownTexture:SetTexCoord(0.515625, 1.0, 0, 0.4140625)
457 -- SEARCH INPUT
458 local function focusGained(self)
459 if( self.searchText ) then
460 self.searchText = nil
461 self:SetText("")
462 self:SetTextColor(1, 1, 1, 1)
466 local function focusLost(self)
467 if( not self.searchText and string.trim(self:GetText()) == "" ) then
468 self.searchText = true
469 self:SetText(L["SEARCH"])
470 self:SetTextColor(0.90, 0.90, 0.90, 0.80)
474 local function createSearchInput(frame, onChange)
475 frame.search = CreateFrame("EditBox", nil, frame, "InputBoxTemplate")
476 frame.search:SetHeight(19)
477 frame.search:SetWidth(150)
478 frame.search:SetAutoFocus(false)
479 frame.search:ClearAllPoints()
480 frame.search:SetPoint("CENTER", frame, "BOTTOMLEFT", 100, 25)
482 frame.search.searchText = true
483 frame.search:SetText(L["SEARCH"])
484 frame.search:SetTextColor(0.90, 0.90, 0.90, 0.80)
485 frame.search:SetScript("OnTextChanged", onChange)
486 frame.search:SetScript("OnEditFocusGained", focusGained)
487 frame.search:SetScript("OnEditFocusLost", focusLost)
490 -- ADDON CONFIGURATION
491 local function showTooltip(self)
492 if( self.tooltip ) then
493 GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
494 GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1)
498 local function hideTooltip()
499 GameTooltip:Hide()
502 local function sortCategories(a, b)
503 if( not b ) then
504 return false
507 return ( a.name < b.name )
510 -- Adds the actual row, will attempt to reuse the current row if able to
511 local function addCategoryRow(type, name, tooltip, data, parent, addon)
512 local frame = regFrames.addon
513 for i=1, #(frame.categories) do
514 -- Match type/name first
515 if( frame.categories[i].type == type and frame.categories[i].name == name ) then
516 -- Then make sure it's correct addons parent, if it's a category
517 if( (parent and frame.categories[i].parent and frame.categories[i].parent == parent) or (not parent and not frame.categories[i].parent) ) then
518 -- Now make sure it's the correct addon if it's a sub category
519 if( (addon and frame.categories[i].addon and frame.categories[i].addon == addon) or (not addon and not frame.categories[i].addon) ) then
520 frame.categories[i].tooltip = tooltip
521 frame.categories[i].data = data
522 return
528 table.insert(frame.categories, {name = name, type = type, tooltip = tooltip, data = data, parent = parent, addon = addon} )
529 frame.resortList = true
532 -- This removes the entire addon, we don't use this unless
533 -- we're removing the last category
534 local function removeAddonListing(addon)
535 local frame = regFrames.addon
536 for i=#(frame.categories), 1, -1 do
537 if( frame.categories[i].addon == addon ) then
538 table.remove(frame.categories, i)
543 -- Remove a specific category and/or sub category listing
544 -- without needing to recreate the entire list
545 local function removeCategoryListing(addon, name)
546 local frame = regFrames.addon
547 for i=#(frame.categories), 1, -1 do
548 -- Remove the category requested
549 if( frame.categories[i].type == "category" and frame.categories[i].name == name and frame.categories[i].addon == addon ) then
550 table.remove(frame.categories, i)
552 -- Remove all of it's sub categories
553 elseif( frame.categories[i].type == "subcat" and frame.categories[i].parent == name and frame.categories[i].addon == addon ) then
554 table.remove(frame.categories, i)
559 local function removeSubCategoryListing(addon, parentCat, name)
560 local frame = regFrames.addon
561 for i=#(frame.categories), 1, -1 do
562 -- Remove the specific sub category
563 if( frame.categories[i].type == "subcat" and frame.categories[i].name == name and frame.categories[i].parent == parentCat and frame.categories[i].addon == addon ) then
564 table.remove(frame.categories, i)
569 -- We have a seperate function for adding addons
570 -- so we can update a single addon out of the entire list
571 -- if it's categories/sub categories get changed, or a new ones added
572 local function addCategoryListing(name, addon)
573 local tooltip = "|cffffffff" .. (addon.title or name) .. "|r"
574 local data
576 if( addon.version ) then
577 tooltip = tooltip .. "\n" .. string.format(L["VERSION"], addon.version)
580 if( addon.author ) then
581 tooltip = tooltip .. "\n" .. string.format(L["AUTHOR"], addon.author)
584 -- One category, make clicking the addon open that category
585 if( addon.totalCats == 1 and addon.totalSubs == 0 ) then
586 for catName, cat in pairs(addon.categories) do
587 data = cat
588 data.parentCat = catName
589 break
592 -- Multiple categories, or sub categories
593 else
594 for catName, cat in pairs(addon.categories) do
595 cat.parentCat = catName
596 addCategoryRow("category", catName, cat.totalSubs > 0 and string.format(L["TOTAL_SUBCATEGORIES"], cat.totalSubs), cat, name, name)
598 for subCatName, subCat in pairs(cat.sub) do
599 subCat.parentCat = catName
600 addCategoryRow("subcat", subCatName, nil, subCat, catName, name)
605 addCategoryRow("addon", name, (addon.version or addon.author) and tooltip, data, nil, name)
608 -- Recreates the entire listing
609 local function createCategoryListing()
610 regFrames.addon.categories = {}
612 for name, addon in pairs(addons) do
613 addCategoryListing(name, addon)
617 local function openConfigFrame(data)
618 local frame = regFrames.addon
620 -- Clicking on an addon with multiple categories or sub categories will cause no data
621 if( not data ) then
622 -- Make sure the frames hidden when only the addon button is selected
623 if( frame.shownFrame ) then
624 frame.shownFrame:Hide()
626 return
629 if( data.handler or data.func ) then
630 data.frame = nil
632 if( type(data.func) == "string" ) then
633 data.frame = data.handler[data.func](data.handler, data.parentCat or frame.selectedCategory, frame.selectedSubCat)
634 elseif( type(data.handler) == "function" ) then
635 data.frame = data.handler(data.parentCat or frame.selectedCategory, frame.selectedSubCat)
638 -- Mostly this is for authors, but it lets us clean up the logic a bit
639 if( not data.frame ) then
640 error(string.format(L["ERROR_NO_FRAME"], frame.selectedAddon, data.parentCat or frame.selectedCategory, frame.selectedSubCat), 3)
643 -- Validate location/width/height and force parent
644 if( not data.frame:GetPoint() ) then
645 data.frame:SetPoint("TOPLEFT", frame, "TOPLEFT", 190, -103)
648 if( data.frame:GetWidth() > 630 or data.frame:GetWidth() == 0 ) then
649 data.frame:SetWidth(630)
652 if( data.frame:GetHeight() > 305 or data.frame:GetHeight() == 0 ) then
653 data.frame:SetHeight(305)
656 data.frame:SetParent(frame)
657 data.frame:SetFrameStrata("DIALOG")
659 if( not data.noCache ) then
660 local category
662 -- Figure out which category we're modifying
663 if( frame.selectedSubCat ~= "" ) then
664 category = addons[frame.selectedAddon].categories[frame.selectedCategory].sub[frame.selectedSubCat]
665 elseif( frame.selectedCategory ~= "" ) then
666 category = addons[frame.selectedAddon].categories[frame.selectedCategory]
667 elseif( frame.selectedAddon ~= "" ) then
668 for catName, _ in pairs(addons[frame.selectedAddon].categories) do
669 category = addons[frame.selectedAddon].categories[catName]
673 -- Remove the handler/func and save the frame for next time
674 if( category ) then
675 category.handler = nil
676 category.func = nil
677 category.frame = data.frame
682 if( frame.shownFrame ) then
683 frame.shownFrame:Hide()
686 -- Now show the current one
687 if( data.frame and frame.selectedAddon ~= "" ) then
688 data.frame:Show()
689 frame.shownFrame = data.frame
693 -- Displays the actual button
694 local function displayCategoryRow(type, text, data, tooltip, highlighted)
695 local frame = regFrames.addon
697 -- We have to let this run completely
698 -- so we know how many rows we have total
699 frame.totalRows = frame.totalRows + 1
700 if( frame.totalRows <= frame.scroll.offset or frame.rowID >= 15 ) then
701 return
704 frame.rowID = frame.rowID + 1
706 local button = frame.buttons[frame.rowID]
707 local line = frame.lines[frame.rowID]
709 if( highlighted ) then
710 button:LockHighlight()
711 else
712 button:UnlockHighlight()
715 if( type == "addon" ) then
716 button:SetText(text)
717 button:GetFontString():SetPoint("LEFT", button, "LEFT", 4, 0)
718 button:GetNormalTexture():SetAlpha(1.0)
719 line:Hide()
721 elseif( type == "category" ) then
722 button:SetText(HIGHLIGHT_FONT_COLOR_CODE..text..FONT_COLOR_CODE_CLOSE)
723 button:GetFontString():SetPoint("LEFT", button, "LEFT", 12, 0)
724 button:GetNormalTexture():SetAlpha(0.4)
725 line:Hide()
727 elseif( type == "subcat" ) then
728 button:SetText(HIGHLIGHT_FONT_COLOR_CODE..text..FONT_COLOR_CODE_CLOSE)
729 button:GetFontString():SetPoint("LEFT", button, "LEFT", 20, 0)
730 button:GetNormalTexture():SetAlpha(0.0)
731 line:SetTexCoord(0, 0.4375, 0, 0.625)
732 line:Show()
735 button.fs = button:GetFontString()
736 button.tooltip = tooltip
737 button.data = data
738 button.type = type
739 button.catText = text
740 button:Show()
744 local function updateConfigList(openAlso)
745 local frame = regFrames.addon
746 frame.rowID = 0
747 frame.totalRows = 0
749 local lastID
750 local searchBy = string.trim(string.lower(frame.search:GetText()))
751 if( searchBy == "" or frame.search.searchText ) then
752 searchBy = nil
755 -- Make sure stuff matches our search results
756 for id, row in pairs(frame.categories) do
757 if( searchBy and not string.match(string.lower(row.name), searchBy) ) then
758 frame.categories[id].hide = true
759 else
760 frame.categories[id].hide = nil
764 -- Resort list if needed
765 if( frame.resortList ) then
766 table.sort(frame.categories, sortCategories)
767 frame.resortList = nil
770 -- Now display
771 local opened
772 for _, addon in pairs(frame.categories) do
773 if( not addon.hide and addon.type == "addon" ) then
774 -- Total addons
775 if( addon.name == frame.selectedAddon ) then
776 displayCategoryRow(addon.type, addon.name, addon.data, addon.tooltip, true)
777 for _, cat in pairs(frame.categories) do
778 -- Show all the categories with the addon as the parent
779 if( not cat.hide and cat.parent == addon.name and cat.type == "category" ) then
780 -- Total categories of the selected addon
781 if( cat.name == frame.selectedCategory ) then
782 displayCategoryRow(cat.type, cat.name, cat.data, cat.tooltip, true)
784 local rowID
785 for _, subCat in pairs(frame.categories) do
786 -- We don't have to check type, because it's the only one that has .addon set
787 if( not subCat.hide and subCat.parent == cat.name and subCat.addon == addon.name ) then
788 -- Total sub categories of the selected addons selected category
789 displayCategoryRow(subCat.type, subCat.name, subCat.data, subCat.tooltip, subCat.name == frame.selectedSubCat)
790 lastID = frame.rowID
792 if( openAlso ) then
793 opened = subCat.data
798 -- Turns the line from straight down to a curve at the end
799 if( lastID ) then
800 frame.lines[lastID]:SetTexCoord(0.4375, 0.875, 0, 0.625)
803 -- Okay open the category then
804 if( not opened and openAlso ) then
805 opened = cat.data
807 else
808 displayCategoryRow(cat.type, cat.name, cat.data, cat.tooltip)
813 if( not opened and openAlso ) then
814 opened = addon.data
816 else
817 displayCategoryRow(addon.type, addon.name, addon.data, addon.tooltip)
822 if( opened ) then
823 openConfigFrame(opened)
826 updateScroll(frame.scroll, frame.totalRows)
828 local wrapSize = 145
829 if( frame.totalRows > 15 ) then
830 wrapSize = 135
833 for i=1, 15 do
834 local button = frame.buttons[i]
835 if( frame.totalRows > 15 ) then
836 button:SetWidth(140)
837 else
838 button:SetWidth(156)
841 if( button.fs ) then
842 local wrapAt = wrapSize
843 if( button.type == "category" ) then
844 wrapAt = wrapAt - 5
845 elseif( frame.buttons[i].type == "subcat" ) then
846 wrapAt = wrapAt - 10
849 if( button.fs:GetStringWidth() > wrapAt ) then
850 button.fs:SetWidth(wrapAt)
851 else
852 button.fs:SetWidth(button.fs:GetStringWidth())
856 -- We have less then 15 rows used
857 -- and our index is equal or past our current
858 if( frame.rowID < 15 and i > frame.rowID ) then
859 button:Hide()
864 local function expandConfigList(self)
865 local frame = regFrames.addon
867 if( self.type == "addon" ) then
868 if( frame.selectedAddon == self.catText ) then
869 frame.selectedAddon = ""
870 else
871 frame.selectedAddon = self.catText
874 frame.selectedCategory = ""
875 frame.selectedSubCat = ""
877 elseif( self.type == "category" ) then
878 if( frame.selectedCategory == self.catText ) then
879 frame.selectedCategory = ""
880 self.data = nil
881 else
882 frame.selectedCategory = self.catText
885 frame.selectedSubCat = ""
887 elseif( self.type == "subcat" ) then
888 if( frame.selectedSubCat == self.catText ) then
889 frame.selectedSubCat = ""
891 -- Make sure the frame gets hidden when deselecting
892 self.data = addons[frame.selectedAddon].categories[frame.selectedCategory]
893 else
894 frame.selectedSubCat = self.catText
898 openConfigFrame(self.data)
899 updateConfigList()
903 local function createAddonFrame(hide)
904 local frame = regFrames.addon
906 if( frame and hide ) then
907 frame:Hide()
908 return
909 elseif( hide ) then
910 return
911 elseif( not frame ) then
912 frame = CreateFrame("Frame", nil, regFrames.main)
913 frame:SetFrameStrata("DIALOG")
914 frame:SetAllPoints(regFrames.main)
916 regFrames.addon = frame
917 OptionHouseFrames.addon = frame
919 frame.buttons = {}
920 frame.lines = {}
921 for i=1, 15 do
922 local button = CreateFrame("Button", nil, frame)
923 frame.buttons[i] = button
925 button:SetHighlightFontObject(GameFontHighlightSmall)
926 button:SetTextFontObject(GameFontNormalSmall)
927 button:SetScript("OnClick", expandConfigList)
928 button:SetScript("OnEnter", showTooltip)
929 button:SetScript("OnLeave", hideTooltip)
930 button:SetWidth(140)
931 button:SetHeight(20)
933 button:SetNormalTexture("Interface\\AuctionFrame\\UI-AuctionFrame-FilterBG")
934 button:GetNormalTexture():SetTexCoord(0, 0.53125, 0, 0.625)
936 button:SetHighlightTexture("Interface\\PaperDollInfoFrame\\UI-Character-Tab-Highlight")
937 button:GetHighlightTexture():SetBlendMode("ADD")
939 -- For sub categories only
940 local line = button:CreateTexture(nil, "BACKGROUND")
941 frame.lines[i] = line
943 line:SetWidth(7)
944 line:SetHeight(20)
945 line:SetPoint("LEFT", 13, 0)
946 line:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-FilterLines")
947 line:SetTexCoord(0, 0.4375, 0, 0.625)
949 if( i > 1 ) then
950 button:SetPoint("TOPLEFT", frame.buttons[i - 1], "BOTTOMLEFT", 0, 0)
951 else
952 button:SetPoint("TOPLEFT", 23, -105)
956 createScrollFrame(frame, 15, updateConfigList)
957 frame.scroll:SetPoint("TOPRIGHT", frame, "TOPLEFT", 158, -105)
959 createSearchInput(frame, updateConfigList)
960 createCategoryListing()
963 -- Reset selection
964 frame.selectedAddon = ""
965 frame.selectedCategory = ""
966 frame.selectedSubCat = ""
968 -- Hide the open config frame
969 if( frame.shownFrame ) then
970 frame.shownFrame:Hide()
973 updateConfigList()
974 ShowUIPanel(frame)
977 local function createOHFrame()
978 if( regFrames.main ) then
979 return
982 frame = CreateFrame("Frame", nil, UIParent)
983 frame:CreateTitleRegion()
984 frame:SetClampedToScreen(true)
985 frame:SetMovable(false)
986 frame:SetFrameStrata("DIALOG")
987 frame:SetWidth(832)
988 frame:SetHeight(447)
989 frame:SetPoint("TOPLEFT", 0, -104)
990 frame.totalTabs = 0
991 frame.tabs = {}
993 regFrames.main = frame
994 OptionHouseFrames.main = frame
996 -- If we don't hide it ourself, the panel layout becomes messed up
997 frame:Hide()
999 frame:SetAttribute("UIPanelLayout-defined", true)
1000 frame:SetAttribute("UIPanelLayout-enabled", true)
1001 --~ frame:SetAttribute("UIPanelLayout-area", "doublewide") -- This is broken in the Blizzy code >< Slouken's been sent a fix
1002 frame:SetAttribute("UIPanelLayout-area", "left")
1003 frame:SetAttribute("UIPanelLayout-whileDead", true)
1004 table.insert(UISpecialFrames, name)
1006 local title = frame:GetTitleRegion()
1007 title:SetWidth(757)
1008 title:SetHeight(20)
1009 title:SetPoint("TOPLEFT", 75, -15)
1011 -- Embedded version wont include the icon cause authors are more whiny then users
1012 if( not IsAddOnLoaded("OptionHouse") ) then
1013 local texture = frame:CreateTexture(nil, "OVERLAY")
1014 texture:SetWidth(57)
1015 texture:SetHeight(57)
1016 texture:SetPoint("TOPLEFT", 9, -7)
1017 SetPortraitTexture(texture, "player")
1018 else
1019 local texture = frame:CreateTexture(nil, "OVERLAY")
1020 texture:SetWidth(128)
1021 texture:SetHeight(128)
1022 texture:SetPoint("TOPLEFT", 9, -2)
1023 texture:SetTexture("Interface\\AddOns\\OptionHouse\\GnomePortrait")
1026 local title = frame:CreateFontString(nil, "OVERLAY")
1027 title:SetFontObject(GameFontNormal)
1028 title:SetPoint("TOP", 0, -18)
1029 title:SetText(L["OPTION_HOUSE"])
1031 frame.topLeft = frame:CreateTexture(nil, "ARTWORK")
1032 frame.topLeft:SetWidth(256)
1033 frame.topLeft:SetHeight(256)
1034 frame.topLeft:SetPoint("TOPLEFT", 0, 0)
1036 frame.top = frame:CreateTexture(nil, "ARTWORK")
1037 frame.top:SetWidth(320)
1038 frame.top:SetHeight(256)
1039 frame.top:SetPoint("TOPLEFT", 256, 0)
1041 frame.topRight = frame:CreateTexture(nil, "ARTWORK")
1042 frame.topRight:SetWidth(256)
1043 frame.topRight:SetHeight(256)
1044 frame.topRight:SetPoint("TOPLEFT", frame.top, "TOPRIGHT", 0, 0)
1046 frame.bottomLeft = frame:CreateTexture(nil, "ARTWORK")
1047 frame.bottomLeft:SetWidth(256)
1048 frame.bottomLeft:SetHeight(256)
1049 frame.bottomLeft:SetPoint("TOPLEFT", 0, -256)
1051 frame.bottom = frame:CreateTexture(nil, "ARTWORK")
1052 frame.bottom:SetWidth(320)
1053 frame.bottom:SetHeight(256)
1054 frame.bottom:SetPoint("TOPLEFT", 256, -256)
1056 frame.bottomRight = frame:CreateTexture(nil, "ARTWORK")
1057 frame.bottomRight:SetWidth(256)
1058 frame.bottomRight:SetHeight(256)
1059 frame.bottomRight:SetPoint("TOPLEFT", frame.bottom, "TOPRIGHT", 0, 0)
1061 -- Make sure the configuration tab is first
1062 local tabs = {{func = createAddonFrame, text = L["ADDON_OPTIONS"], type = "browse"}}
1063 createTab(L["ADDON_OPTIONS"], 1)
1065 for id, tab in pairs(tabfunctions) do
1066 table.insert(tabs, tab)
1067 createTab(tab.text, id + 1)
1070 tabfunctions = tabs
1072 local button = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
1073 button:SetPoint("TOPRIGHT", 3, -8)
1074 button:SetScript("OnClick", function()
1075 HideUIPanel(frame)
1076 end)
1079 -- PRIVATE API's
1080 -- While these aren't locked down to prevent being used
1081 -- You ARE using them are your own risk for future compatability
1082 function OptionHouse:CreateSearchInput(frame, onChange)
1083 createSearchInput(frame, onChange)
1086 function OptionHouse:UpdateScroll(scroll, totalRows)
1087 updateScroll(scroll, totalRows)
1090 function OptionHouse:CreateScrollFrame(frame, displayNum, onScroll)
1091 createScrollFrame(frame, displayNum, onScroll)
1094 function OptionHouse.RegisterTab(self, text, func, type)
1095 -- Simple, effective you can't register a tab unless we list it here
1096 -- I highly doubt will ever need to add another one
1097 if( text ~= L["TAB_MANAGEMENT"] and text ~= L["TAB_PERFORMANCE"] ) then return end
1099 table.insert(tabfunctions, {func = func, handler = self, text = text, type = type})
1101 -- Will create all of the tabs when the frame is created if needed
1102 if( not frame ) then
1103 return
1106 createTab(text, #(tabfunctions))
1109 function OptionHouse.UnregisterTab(self, text)
1110 for i=#(tabfunctions), 1, -1 do
1111 if( tabfunctions[i].text == text ) then
1112 table.remove(tabfunctions, i)
1116 for i=1, frame.totalTabs do
1117 if( tabfunctions[i] ) then
1118 createTab(tabfunctions[i].text, i)
1119 else
1120 frame.tabs[i]:Hide()
1125 function OptionHouse.GetAddOnData(self, name)
1126 if( not addons[name] ) then
1127 return nil, nil, nil
1130 return addons[name].title, addons[name].author, addons[name].version
1133 function OptionHouse.RegisterFrame(self, type, frame)
1134 if( type ~= "addon" and type ~= "manage" and type ~= "perf" and type ~= "main" ) then
1135 error(string.format(L["UNKNOWN_FRAMETYPE"], type), 3)
1138 regFrames[type] = frame
1139 OptionHouseFrames[type] = frame
1142 -- PUBLIC API's
1143 function OptionHouse:GetFrame(type)
1144 if( type ~= "addon" and type ~= "manage" and type ~= "perf" and type ~= "main" ) then
1145 error(string.format(L["UNKNOWN_FRAMETYPE"], type), 3)
1148 return regFrames[type]
1151 function OptionHouse:Open(addonName, parentCat, childCat)
1152 argcheck(addonName, 1, "string", "nil")
1153 argcheck(parentCat, 2, "string", "nil")
1154 argcheck(childCat, 3, "string", "nil")
1156 createOHFrame()
1157 tabOnClick(1)
1159 if( not addonName ) then
1160 ShowUIPanel(frame)
1161 return
1164 regFrames.addon.selectedAddon = addonName or ""
1165 regFrames.addon.selectedCategory = parentCat or ""
1166 regFrames.addon.selectedSubCat = childCat or ""
1168 updateConfigList(true)
1169 ShowUIPanel(frame)
1172 function OptionHouse:OpenTab(id)
1173 argcheck(id, 1, "number")
1174 assert(3, #(tabfunctions) > id, string.format(L["UNKNOWN_TAB"], id, #(tabfunctions)))
1176 createOHFrame()
1177 tabOnClick(id)
1178 ShowUIPanel(frame)
1181 function OptionHouse:RegisterAddOn(name, title, author, version)
1182 argcheck(name, 1, "string")
1183 argcheck(title, 2, "string", "nil")
1184 argcheck(author, 3, "string", "nil")
1185 argcheck(version, 4, "string", "number", "nil")
1186 assert(3, not addons[name], string.format(L["ADDON_ALREADYREG"], name))
1188 addons[name] = {title = title, author = author, version = version, totalCats = 0, totalSubs = 0, categories = {}}
1189 addons[name].obj = {name = name}
1191 -- So we can upgrade the function pointer if a newer rev is found
1192 for id, method in pairs(methods) do
1193 addons[name].obj[method] = OptionHouse[method]
1196 if( regFrames.addon ) then
1197 addCategoryListing(name, addons[name])
1198 updateConfigList()
1201 return addons[name].obj
1204 function OptionHouse.RegisterCategory(addon, name, handler, func, noCache)
1205 argcheck(name, 2, "string")
1206 argcheck(handler, 3, "string", "function", "table")
1207 argcheck(func, 4, "string", "function", "nil")
1208 argcheck(noCache, 5, "boolean", "number", "nil")
1209 assert(3, handler or func, L["NO_FUNC_PASSED"])
1210 assert(3, addons[addon.name], string.format(L["MUST_CALL"], "RegisterCategory"))
1211 assert(3, addons[addon.name].categories, string.format(L["CATEGORY_ALREADYREG"], name, addon.name))
1213 -- Category numbers are required so we know when to skip it because only one category/sub cat exists
1214 addons[addon.name].totalCats = addons[addon.name].totalCats + 1
1215 addons[addon.name].categories[name] = {func = func, handler = handler, noCache = noCache, sub = {}, totalSubs = 0}
1217 if( regFrames.addon ) then
1218 addCategoryListing(addon.name, addons[addon.name])
1219 updateConfigList()
1223 function OptionHouse.RegisterSubCategory(addon, parentCat, name, handler, func, noCache)
1224 argcheck(parentCat, 2, "string")
1225 argcheck(name, 3, "string")
1226 argcheck(handler, 4, "string", "function", "table")
1227 argcheck(func, 5, "string", "function", "nil")
1228 argcheck(noCache, 6, "boolean", "number", "nil")
1229 assert(3, handler or func, L["NO_FUNC_PASSED"])
1230 assert(3, addons[addon.name], string.format(L["MUST_CALL"], "RegisterSubCategory"))
1231 assert(3, addons[addon.name].categories[parentCat], string.format(L["NO_PARENTCAT"], parentCat, addon.name))
1232 assert(3, not addons[addon.name].categories[parentCat].sub[name], string.format(L["SUBCATEGORY_ALREADYREG"], name, parentCat, addon.name))
1234 addons[addon.name].totalSubs = addons[addon.name].totalSubs + 1
1235 addons[addon.name].categories[parentCat].totalSubs = addons[addon.name].categories[parentCat].totalSubs + 1
1236 addons[addon.name].categories[parentCat].sub[name] = {handler = handler, func = func, noCache = noCache}
1238 if( regFrames.addon ) then
1239 addCategoryListing(addon.name, addons[addon.name])
1240 updateConfigList()
1244 function OptionHouse.RemoveCategory(addon, name)
1245 argcheck(name, 2, "string")
1246 assert(3, addons[addon.name], string.format(L["MUST_CALL"], "RemoveCategory"))
1247 assert(3, addons[addon.name].categories[name], string.format(L["NO_CATEGORYEXISTS"], name, addon.name))
1249 addons[addon.name].totalCats = addons[addon.name].totalCats - 1
1250 addons[addon.name].totalSubs = addons[addon.name].totalSubs - addons[addon.name].categories[name].totalSubs
1251 addons[addon.name].categories[name] = nil
1253 if( regFrames.addon ) then
1254 if( addons[addon.name].totalCats == 0 ) then
1255 removeAddonListing(addon.name)
1256 else
1257 removeCategoryListing(addon.name, name)
1260 updateConfigList()
1264 function OptionHouse.RemoveSubCategory(addon, parentCat, name)
1265 argcheck(parentCat, 2, "string")
1266 argcheck(name, 2, "string")
1267 assert(3, addons[addon.name], string.format(L["MUST_CALL"], "RemoveSubCategory"))
1268 assert(3, addons[addon.name].categories[parentCat], string.format(L["NO_PARENTCAT"], name, addon.name))
1269 assert(3, addons[addon.name].categories[parentCat].sub[name], string.format(L["NO_SUBCATEXISTS"], name, parentCat, addon.name))
1271 addons[addon.name].totalSubs = addons[addon.name].totalSubs - 1
1272 addons[addon.name].categories[parentCat].totalSubs = addons[addon.name].categories[parentCat].totalSubs - 1
1273 addons[addon.name].categories[parentCat].sub[name] = nil
1275 if( regFrames.addon ) then
1276 -- If this means we only have no more sub categories
1277 -- and only one category we need to change how it works
1278 if( addons[addon.name].totalSubs == 0 and addons[addon.name].totalCats == 1 ) then
1279 removeAddonListing(addon.name)
1280 addCategoryListing(addon.name, addons[addon.name])
1281 else
1282 removeSubCategoryListing(addon.name, parentCat, name)
1285 updateConfigList()
1289 function OptionHouse:GetVersion() return major, minor end
1291 local function instanceLoaded()
1292 if( oldRevision ) then
1293 addons = OHInstance.addons or addons
1294 evtFrame = OHInstance.evtFrame or evtFrame
1295 tabfunctions = OHInstance.tabfunctions or tabfunctions
1296 else
1297 -- Secure headers are supported so don't want the window stuck open in combat
1298 evtFrame = CreateFrame("Frame")
1299 evtFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
1300 evtFrame:RegisterEvent("ADDON_LOADED")
1301 evtFrame:SetScript("OnEvent",function(self, event)
1302 if( event == "PLAYER_REGEN_DISABLED" and frame and frame:IsShown() ) then
1303 HideUIPanel(frame)
1304 DEFAULT_CHAT_FRAME:AddMessage(L["ENTERED_COMBAT"])
1306 end)
1308 -- Make sure it hasn't been created already.
1309 -- don't have to upgrade the referance because it just uses the slash command
1310 -- which will upgrade below to use the current version anyway
1311 if( not GameMenuButtonOptionHouse ) then
1312 local menubutton = CreateFrame("Button", "GameMenuButtonOptionHouse", GameMenuFrame, "GameMenuButtonTemplate")
1313 menubutton:SetText(L["OPTION_HOUSE"])
1314 menubutton:SetScript("OnClick", function()
1315 PlaySound("igMainMenuOption")
1316 HideUIPanel(GameMenuFrame)
1317 SlashCmdList["OPTHOUSE"]()
1318 end)
1320 -- Position below "Interface Options"
1321 local a1, fr, a2, x, y = GameMenuButtonKeybindings:GetPoint()
1322 menubutton:SetPoint(a1, fr, a2, x, y)
1324 GameMenuButtonKeybindings:SetPoint(a1, menubutton, a2, x, y)
1325 GameMenuFrame:SetHeight(GameMenuFrame:GetHeight() + 25)
1329 OptionHouseFrames = OptionHouseFrames or {}
1331 OptionHouse.addons = addons
1332 OptionHouse.evtFrame = evtFrame
1333 OptionHouse.tabfunctions = tabfunctions
1335 -- Upgrade functions to point towards the latest revision
1336 for name, addon in pairs(addons) do
1337 for _, method in pairs(methods) do
1338 addon.obj[method] = OptionHouse[method]
1342 SLASH_OPTHOUSE1 = "/opthouse"
1343 SLASH_OPTHOUSE2 = "/oh"
1344 SlashCmdList["OPTHOUSE"] = function(...)
1345 if( select(1, ...) == "" ) then
1346 OptionHouse:Open()
1347 else
1348 OptionHouse:Open(...)
1352 -- Now make it active
1353 for k, v in pairs(OptionHouse) do
1354 OHInstance[k] = v
1358 instanceLoaded()