local MAJOR_VERSION = "2.0" local MINOR_VERSION = tonumber((string.gsub("$Revision: 9980 $", "^.-(%d+).-$", "%1"))) if FUBAR_REVISION and FUBAR_REVISION > MINOR_VERSION then MINOR_VERSION = FUBAR_REVISION end FUBAR_REVISION = nil local Compost = AceLibrary("Compost-2.0") local Dewdrop = AceLibrary("Dewdrop-2.0") local Tablet = AceLibrary:HasInstance("Tablet-2.0") and AceLibrary("Tablet-2.0") local Jostle = AceLibrary("Jostle-2.0") local L = AceLibrary("AceLocale-2.0"):new("FuBar") FuBar = AceLibrary("AceAddon-2.0"):new("AceDB-2.0", "AceConsole-2.0", "AceEvent-2.0", "AceHook-2.0") local FuBar = FuBar FuBar.title = "FuBar" FuBar.version = MAJOR_VERSION .. "." .. MINOR_VERSION FuBar.date = string.gsub("$Date: 2006-09-03 12:10:31 -1000 (Sun, 03 Sep 2006) $", "^.-(%d%d%d%d%-%d%d%-%d%d).-$", "%1") FuBar:RegisterDB("FuBar2DB") local charID = AceLibrary("AceDB-2.0").CHAR_ID local realmID = AceLibrary("AceDB-2.0").REALM_ID local classID = AceLibrary("AceDB-2.0").CLASS_ID local _G = getfenv(0) local plugins = {} local FuBar_Panel = FuBar_Panel _G.FuBar_Panel = nil if not FUBAR_DEFAULTS then FUBAR_DEFAULTS = function() return { fontSize = 12, adjust = true, panels = { [1] = { attachPoint = "TOP", plugins = { left = { "LocationFu", "ExperienceFu", "PerformanceFu", }, center = {}, right = { "ClockFu", "VolumeFu", } } }, [2] = { attachPoint = "BOTTOM" } } } end end local CATEGORIES = { ["Action Bars"] = L["Action Bars"], ["Auction"] = L["Auction"], ["Audio"] = L["Audio"], ["Battlegrounds/PvP"] = L["Battlegrounds/PvP"], ["Buffs"] = L["Buffs"], ["Chat/Communication"] = L["Chat/Communication"], ["Druid"] = L["Druid"], ["Hunter"] = L["Hunter"], ["Mage"] = L["Mage"], ["Paladin"] = L["Paladin"], ["Priest"] = L["Priest"], ["Rogue"] = L["Rogue"], ["Shaman"] = L["Shaman"], ["Warlock"] = L["Warlock"], ["Warrior"] = L["Warrior"], ["Healer"] = L["Healer"], ["Tank"] = L["Tank"], ["Caster"] = L["Caster"], ["Combat"] = L["Combat"], ["Compilations"] = L["Compilations"], ["Data Export"] = L["Data Export"], ["Development Tools"] = L["Development Tools"], ["Guild"] = L["Guild"], ["Frame Modification"] = L["Frame Modification"], ["Interface Enhancements"] = L["Interface Enhancements"], ["Inventory"] = L["Inventory"], ["Library"] = L["Library"], ["Map"] = L["Map"], ["Mail"] = L["Mail"], ["Miscellaneous"] = L["Miscellaneous"], ["Quest"] = L["Quest"], ["Raid"] = L["Raid"], ["Tradeskill"] = L["Tradeskill"], ["UnitFrame"] = L["UnitFrame"], ["Others"] = L["Others"], } local basePluginFrame local alreadyEnabled = false local backgrounds = {["Interface\\AddOns\\FuBar\\background"] = L["Default"]} function FuBar:RegisterSkin(name, bgFile) assert(type(name) == "string", "You must provide a name for your skin") assert(type(bgFile) == "string", "You must provide a file for your skin") if not backgrounds[bgFile] then backgrounds[bgFile] = name end end local function SetBackground(bgFile) if backgrounds[bgFile] then FuBar.db.profile.skin = bgFile FuBar_Panel:SetBackground(bgFile) end end local function GetBackground() return backgrounds[FuBar.db.profile.skin] and FuBar.db.profile.skin or "Interface\\AddOns\\FuBar\\background" end local function background_sort(alpha, bravo) return backgrounds[alpha] < backgrounds[bravo] end local optionsTable = { handler = FuBar, type = "group", args = { overflow = { type = "toggle", name = L["Overflow plugins"], desc = L["Let plugins overflow onto another panel"], get = "IsOverflowing", set = "ToggleOverflowing", }, create = { type = "execute", name = L["Create new panel"], desc = L["Create new panel"], func = "new", handler = FuBar_Panel }, adjust = { type = "toggle", name = L["Auto-adjust frames"], desc = L["Toggle auto-adjustment of blizzard's frames"], get = "IsAdjust", set = "ToggleAdjust", }, autohideTop = { type = "toggle", name = L["Auto-hide top panels"], desc = L["Toggle auto-hiding of the top panels"], get = "IsAutoHidingTop", set = "ToggleAutoHidingTop", }, autohideBottom = { type = "toggle", name = L["Auto-hide bottom panels"], desc = L["Toggle auto-hiding of the bottom panels"], get = "IsAutoHidingBottom", set = "ToggleAutoHidingBottom", }, texture = { type = "text", name = L["Texture"], desc = L["Change the texture of the panels"], get = GetBackground, set = SetBackground, validate = backgrounds }, spacing = { type = "group", name = L["Spacing"], desc = L["Spacing between plugins"], args = { left = { type = "range", name = L["Left-aligned spacing"], desc = L["Set spacing between left-aligned plugins"], max = 40, min = 0, step = 1, get = "GetLeftSpacing", set = "SetLeftSpacing", }, center = { type = "range", name = L["Center-aligned spacing"], desc = L["Set spacing between center-aligned plugins"], max = 40, min = 0, step = 1, get = "GetCenterSpacing", set = "SetCenterSpacing", }, right = { type = "range", name = L["Right-aligned spacing"], desc = L["Set spacing between right-aligned plugins"], max = 40, min = 0, step = 1, get = "GetRightSpacing", set = "SetRightSpacing", }, } }, fontsize = { type = "group", name = L["Font size"], desc = L["Font size"], args = { panel = { type = "range", name = L["Panel font size"], desc = L["Set font size for the plugins on the panel"], max = 24, min = 7, step = 1, get = "GetFontSize", set = "SetFontSize", }, tooltip = { type = "range", name = L["Tooltip font size"], desc = L["Set font size for the tooltip"], max = 2, min = 0.5, isPercent = true, get = function() return Tablet:GetFontSizePercent(FuBar.db.profile.tooltip) end, set = function(value) return Tablet:SetFontSizePercent(FuBar.db.profile.tooltip, value) end, hidden = function() return not Tablet end } } }, transparency = { type = "group", name = L["Transparency"], desc = L["Transparency"], args = { panel = { type = "range", name = L["Panel transparency"], desc = L["Set transparency of the panels"], max = 1, min = 0, step = 0.05, isPercent = true, get = "GetTransparency", set = "SetTransparency", }, tooltip = { type = "range", name = L["Tooltip transparency"], desc = L["Set transparency of the tooltip"], max = 1, min = 0, step = 0.05, isPercent = true, get = function() return Tablet:GetTransparency(FuBar.db.profile.tooltip) end, set = function(value) return Tablet:SetTransparency(FuBar.db.profile.tooltip, value) end, hidden = function() return not Tablet end } } }, thickness = { type = "range", name = L["Thickness"], desc = L["Set thickness between the panels"], max = 20, min = 0, step = 1, get = "GetThickness", set = "SetThickness", }, } } FuBar:RegisterChatCommand(L:GetTable("ChatCommands"), optionsTable) optionsTable.args.standby = nil function FuBar:GetScaledCursorPosition() local x, y = GetCursorPosition() local scale = GetScreenHeight() / 768 return x * scale, y * scale end function FuBar:Reset() self:UnregisterEvent("PLAYER_LOGOUT") FuBar2DB = {} ReloadUI() end function FuBar:GetPanel(panelId) return FuBar_Panel.instances[panelId] end function FuBar:GetNumPanels() return table.getn(FuBar_Panel.instances) end function FuBar:GetBottommostTopPanel() local bottom = GetScreenHeight() local best for i = 1, self:GetNumPanels() do local panel = self:GetPanel(i) if panel:GetAttachPoint() == "TOP" and panel.frame:GetBottom() < bottom then bottom = panel.frame:GetBottom() best = panel end end return best end function FuBar:GetTopmostBottomPanel() local top = 0 local best for i = 1, self:GetNumPanels() do local panel = self:GetPanel(i) if panel:GetAttachPoint() == "BOTTOM" and panel.frame:GetTop() > top then top = panel.frame:GetTop() best = panel end end return best end local isChangingProfile, previousProfile function FuBar:IsChangingProfile() return isChangingProfile end function FuBar:GetPluginProfiling() for _,p in ipairs(plugins) do if p:GetTitle() == self.db.profile.profilePlugin then return p, p:GetTitle() end end end function FuBar:SetPluginProfiling(plugin) self.db.profile.profilePlugin = plugin:GetTitle() end function FuBar:IsAdjust() return self.db.profile.adjust end function FuBar:ToggleAdjust() self.db.profile.adjust = not self.db.profile.adjust self:UpdateJostleAdjustments() return self.db.profile.adjust end function FuBar:IsOverflowing() return not self.db.profile.overflow end function FuBar:ToggleOverflowing() self.db.profile.overflow = not self.db.profile.overflow for i = 1, self:GetNumPanels() do self:GetPanel(i):CheckForOverlap() end return not self.db.profile.overflow end function FuBar:UpdateJostleAdjustments() if not self.db.profile.adjust then Jostle:DisableTopAdjusting() Jostle:DisableBottomAdjusting() else if self:IsAutoHidingTop() then Jostle:DisableTopAdjusting() else Jostle:EnableTopAdjusting() end if self:IsAutoHidingBottom() then Jostle:DisableBottomAdjusting() else Jostle:EnableBottomAdjusting() end end end function FuBar:IsAutoHidingTop() return self.db.profile.autohideTop end local autohideTopTime, autohideBottomTime function FuBar:ToggleAutoHidingTop() self.db.profile.autohideTop = not self.db.profile.autohideTop self:UpdateJostleAdjustments() if not self.db.profile.autohideTop then for i = 1, self:GetNumPanels() do if self:GetPanel(i):GetAttachPoint() == "TOP" then local frame = getglobal("FuBarFrame" .. i) frame:SetAlpha(1) frame:SetFrameStrata("HIGH") end end else self:ScheduleEvent("FuBar_AutoHideTop", self.OnUpdate_AutoHideTop, 1, self) end autohideTopTime = GetTime() return self.db.profile.autohideTop end function FuBar:IsAutoHidingBottom() return self.db.profile.autohideBottom end function FuBar:ToggleAutoHidingBottom() self.db.profile.autohideBottom = not self.db.profile.autohideBottom self:UpdateJostleAdjustments() if not self.db.profile.autohideBottom then for i = 1, self:GetNumPanels() do if self:GetPanel(i):GetAttachPoint() == "BOTTOM" then local frame = getglobal("FuBarFrame" .. i) frame:SetAlpha(1) frame:SetFrameStrata("HIGH") end end else self:ScheduleEvent("FuBar_AutoHideBottom", self.OnUpdate_AutoHideBottom, 1, self) end autohideBottomTime = GetTime() return self.db.profile.autohideBottom end function FuBar:GetFontSize() if not self.db.profile then return 12 end return self.db.profile.fontSize or 12 end function FuBar:SetFontSize(size) size = size or 12 self.db.profile.fontSize = size for i,plugin in ipairs(plugins) do if type(plugin.SetFontSize) ~= "function" then table.remove(plugins, i) i = i - 1 else plugin:SetFontSize(size) end end for i = 1, self:GetNumPanels() do self:GetPanel(i):UpdateTexture() end self:Update() Jostle:Refresh() end function FuBar:GetLeftSpacing() if not self.db.profile then return 20 end return self.db.profile.leftSpacing or 20 end function FuBar:SetLeftSpacing(size) self.db.profile.leftSpacing = size self:Update() end function FuBar:GetCenterSpacing() if not self.db.profile then return 20 end return self.db.profile.centerSpacing or 20 end function FuBar:SetCenterSpacing(size) self.db.profile.centerSpacing = size self:Update() end function FuBar:GetRightSpacing() if not self.db.profile then return 20 end return self.db.profile.rightSpacing or 20 end function FuBar:SetRightSpacing(size) self.db.profile.rightSpacing = size self:Update() end function FuBar:SetThickness(size) self.db.profile.thickness = size for i = 1, self:GetNumPanels() do self:GetPanel(i):UpdateTexture() end self:Update() Jostle:Refresh() end function FuBar:GetThickness(size) if not self.db.profile then return 5 end return self.db.profile.thickness or 5 end function FuBar:GetTransparency() return self.db.profile.transparency or 0.8 end function FuBar:SetTransparency(value) self.db.profile.transparency = value for i = 1, self:GetNumPanels() do self:GetPanel(i):UpdateTexture() end end local function CheckLoadCondition(loadCondition) return RunScript("(function()"..loadCondition.." end)()") end local function _IsCorrectPlugin(plugin) if type(plugin) ~= "table" then return false elseif type(plugin.GetName) ~= "function" then return false elseif type(plugin.GetTitle) ~= "function" then return false elseif type(plugin.GetCategory) ~= "function" then return false elseif type(plugin.SetFontSize) ~= "function" then return false elseif type(plugin.GetFrame) ~= "function" then return false elseif type(plugin.Show) ~= "function" then return false elseif type(plugin.Hide) ~= "function" then return false elseif type(plugin.GetPanel) ~= "function" then return false elseif type(plugin:GetName()) ~= "string" then return false elseif type(plugin:GetTitle()) ~= "string" then return false elseif type(plugin:GetCategory()) ~= "string" then return false end local frame = plugin:GetFrame() if type(frame) ~= "table" then return false elseif type(frame[0]) ~= "userdata" then return false elseif type(frame.GetFrameType) ~= "function" then return false elseif type(frame:GetFrameType()) ~= "string" then return false end return true end local donothing = function() end local function IsCorrectPlugin(plugin) local add = DEFAULT_CHAT_FRAME.AddMessage DEFAULT_CHAT_FRAME.AddMessage = donothing local ret, msg = pcall(_IsCorrectPlugin, plugin) DEFAULT_CHAT_FRAME.AddMessage = add if ret then return msg end end local function _IsCorrectPanel(panel) if type(panel) ~= "table" then return false elseif type(panel.AddPlugin) ~= "function" then return false elseif type(panel.RemovePlugin) ~= "function" then return false elseif type(panel.GetNumPlugins) ~= "function" then return false elseif type(panel:GetNumPlugins()) ~= "number" then return false elseif type(panel.GetPlugin) ~= "function" then return false elseif type(panel.HasPlugin) ~= "function" then return false elseif type(panel.GetPluginSide) ~= "function" then return false end return true end local function IsCorrectPanel(panel) local add = DEFAULT_CHAT_FRAME.AddMessage DEFAULT_CHAT_FRAME.AddMessage = donothing local ret, msg = pcall(_IsCorrectPanel, panel) DEFAULT_CHAT_FRAME.AddMessage = add if ret then return msg end end local n local mt = { __newindex = function(self, k, v) rawset(self, k, v) n[k] = v end, } local function IsAceAddon(addon) if type(addon) ~= "table" then return false elseif addon == AceAddon then return true elseif not getmetatable(addon) then return false else return IsAceAddon(getmetatable(addon).__index) end end local blank = {} local function LoadAddOnWrapper(addon) local o = getfenv(0) n = {} setmetatable(o, mt) local success, ret = pcall(LoadAddOn, addon) setmetatable(o, blank) if not ret then FuBar:Print("Error loading LoadOnDemand plugin " .. addon) return elseif not success then FuBar:Print("Error loading LoadOnDemand plugin " .. addon .. ": " .. ret) return end local dependencies local plugin for k,v in pairs(n) do if IsCorrectPlugin(v) then if plugin then if not dependencies then dependencies = {} end table.insert(dependencies, plugin) end plugin = v if IsAceAddon(plugin) then if not plugin._initialized then if not AceData.profileBasePath then --plugin._initialized = true --plugin:Initialize() --ace1ToBeInitialized[plugin] = true else plugin._initialized = true ace:InitializeApp(plugin) end end else if not plugin._initialized then plugin._initialized = true if type(plugin.Initialize) == "function" then plugin:Initialize() end end end end end if not plugin then FuBar:Print("Error loading LoadOnDemand plugin " .. addon) return end return ret, plugin, dependencies end local toBeLoaded local function CleanDB() local self = FuBar local t = Compost:Acquire() for _,panel in ipairs(self.db.profile.panels) do if panel and panel.plugins then for _,part in pairs(panel.plugins) do if part then for i,plugin in ipairs(part) do if t[plugin] then i = i - 1 table.remove(part, i) else t[plugin] = true end end end end end end t = Compost:Reclaim(t) end function FuBar:OnInitialize() toBeLoaded = {} if not next(FuBar.db.profile) then local def local profile = self:GetProfile() if string.find(profile, "^char/") or string.find(profile, "^class/") then local _,class = UnitClass("player") def = _G["FUBAR_DEFAULTS_" .. class] or FUBAR_DEFAULTS else def = FUBAR_DEFAULTS end if type(def) == "function" then def = def() end for k,v in pairs(def) do FuBar.db.profile[k] = v end end if not self.db.profile.loadOnDemand then self.db.profile.loadOnDemand = {} end if not self.db.profile.tooltip then self.db.profile.tooltip = {} end self:SetFontSize(self:GetFontSize()) self.menu = function(level, value) local panelId = FuBar_Panel.selectedPanel or 1 local panel = self:GetPanel(panelId) if not panel then Dewdrop:Close() return end if level == 1 then Dewdrop:AddLine( 'text', self.name, 'isTitle', true ) local menuTitles = Compost:Acquire() for _,plugin in ipairs(plugins) do local alreadyExists = false local category = plugin:GetCategory() if not CATEGORIES[category] then category = L["Others"] end menuTitles[category] = true end for _,name in ipairs(toBeLoaded) do local category = self.db.profile.loadOnDemand[name].category if not CATEGORIES[category] then category = L["Others"] end menuTitles[category] = true end local titles = Compost:Acquire() for name in menuTitles do table.insert(titles, name) end Compost:Reclaim(menuTitles) table.sort(titles) for _,category in ipairs(titles) do Dewdrop:AddLine( 'text', CATEGORIES[category], 'value', category, 'hasArrow', true ) end Compost:Reclaim(titles) Dewdrop:AddLine() Dewdrop:AddLine( 'text', L["Attach"], 'hasArrow', true, 'value', "attach" ) Dewdrop:AddLine( 'text', L["Lock panel"], 'arg1', panel, 'func', "ToggleLocked", 'checked', panel:IsLocked() ) Dewdrop:AddLine( 'text', L["Remove panel"], 'arg1', panel, 'func', "WarnDestroy", 'disabled', panelId == 1 and not self:GetPanel(2), 'closeWhenClicked', true ) Dewdrop:AddLine() Dewdrop:FeedAceOptionsTable(optionsTable) Dewdrop:AddLine( 'text', CLOSE, 'arg1', Dewdrop, 'func', "Close" ) elseif Dewdrop:FeedAceOptionsTable(optionsTable) then elseif level == 2 then if value == "attach" then Dewdrop:AddLine( 'text', L["Attach to top"], 'arg1', panel, 'func', panel:GetAttachPoint() ~= "TOP" and "SetAttachPoint", 'arg2', "TOP", 'checked', panel:GetAttachPoint() == "TOP", 'closeWhenClicked', true, 'isRadio', true ) Dewdrop:AddLine( 'text', L["Attach to bottom"], 'arg1', panel, 'func', panel:GetAttachPoint() ~= "BOTTOM" and "SetAttachPoint", 'arg2', "BOTTOM", 'checked', panel:GetAttachPoint() == "BOTTOM", 'closeWhenClicked', true, 'isRadio', true ) Dewdrop:AddLine( 'text', L["Detach panel"], 'arg1', panel, 'func', panel:GetAttachPoint() ~= "NONE" and "SetAttachPoint", 'arg2', "NONE", 'checked', panel:GetAttachPoint() == "NONE", 'closeWhenClicked', true, 'isRadio', true ) else for _,plugin in ipairs(plugins) do local category = plugin:GetCategory() if not CATEGORIES[category] then category = L["Others"] end if category == value then Dewdrop:AddLine( 'text', plugin:GetTitle(), 'arg1', plugin, 'func', plugin:GetPanel() and "Hide" or "Show", 'arg2', FuBar_Panel.selectedPanel or 1, 'checked', plugin:GetPanel() ) end end for i,name in ipairs(toBeLoaded) do local i, name = i, name local lod = self.db.profile.loadOnDemand[name] local category = lod.category if not CATEGORIES[category] then category = L["Others"] end if category == value then Dewdrop:AddLine( 'text', lod.title, 'arg1', self, 'func', "LoadPlugin", 'arg2', name ) end end end end end self:ScheduleEvent(self.LoadLoadOnDemandPlugins, 0, self) CleanDB() end function FuBar:LoadPlugin(name) if not alreadyEnabled then local dep1,dep2,dep3,dep4 = GetAddOnDependencies(name) if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then if not self.acePluginToLoad then self.acePluginToLoad = {} end self.acePluginToLoad[name] = true return end end local loaded, plugin, dependencies = LoadAddOnWrapper(name) if loaded then if type(plugin.SetLoadOnDemand) == "function" then plugin:SetLoadOnDemand(true) end self.db.profile.loadOnDemand[name] = { title = plugin:GetTitle(), category = plugin:GetCategory(), disabled = nil, condition = type(plugin.GetLoadCondition) == "function" and plugin:GetLoadCondition() or nil, } plugin:Show(FuBar_Panel.selectedPanel or false) if dependencies then for _,v in ipairs(dependencies) do if type(v.SetLoadOnDemand) == "function" then v:SetLoadOnDemand(true) end self.db.profile.loadOnDemand[name].disabled = nil for j,u in ipairs(toBeLoaded) do if u == v:GetTitle() then table.remove(toBeLoaded, j) break end end if v.hideWithoutStandby then v:EnableApp() else v:Show(panelId or false) end end end self:SetFontSize(self:GetFontSize()) for i,n in ipairs(toBeLoaded) do if n == name then table.remove(toBeLoaded, i) break end end self.db.profile.loadOnDemand[name].disabled = nil end end function FuBar:OnEnable() if alreadyEnabled then ReloadUI() return end alreadyEnabled = true if AceLibrary:HasInstance("Tablet-2.0") then Tablet = AceLibrary("Tablet-2.0") end if not self.db.profile.panels then self.db.profile.panels = {} end if not self.db.profile.minimap then self.db.profile.minimap = {} end for i = table.getn(self.db.profile.panels), 1, -1 do if self.db.profile.panels[i] then FuBar_Panel:new() end end self:CheckResolution() if self:GetNumPanels() == 0 then FuBar_Panel:new() end if FuBar.db.profile.skin then SetBackground(FuBar.db.profile.skin) end self:RegisterEvent("AceLibrary_Register") -- self:RegisterEvent("DISPLAY_SIZE_CHANGED", "OnDisplaySizeChanged") self:RegisterEvent("CVAR_UPDATE", "OnCVarUpdate") self:Hook("RestartGx") local function func() if not self:SetupPlugins() then self:ScheduleEvent(func, 0) return end self:Update() self:ScheduleEvent("FuBar_AutoHideTop", self.OnUpdate_AutoHideTop, 1, self) self:ScheduleEvent("FuBar_AutoHideBottom", self.OnUpdate_AutoHideBottom, 1, self) end self:RegisterEvent("AceEvent_FullyInitialized", func, true) self:UpdateJostleAdjustments() if self.db.profile.skin and backgrounds[self.db.profile.skin] then FuBar_Panel:SetBackground(self.db.profile.skin) end self:RegisterEvent("PLAYER_ENTERING_WORLD", "PLAYER_ENTERING_WORLD", true) end function FuBar:LoadLoadOnDemandPlugins() for i = 1, GetNumAddOns() do local name, title, notes, enabled, loadable, reason, security = GetAddOnInfo(i) if IsAddOnLoadOnDemand(i) and enabled and loadable and not IsAddOnLoaded(i) then local deps = Compost:Acquire(GetAddOnDependencies(name)) local good = false for _,dep in ipairs(deps) do if dep == "FuBar" then good = true break end end if good then if not self.db.profile.loadOnDemand[name] then self:LoadPlugin(name) elseif not self.db.profile.loadOnDemand[name].disabled and (not self.db.profile.loadOnDemand[name].condition or CheckLoadCondition(self.db.profile.loadOnDemand[name].condition)) then self:LoadPlugin(name) else table.insert(toBeLoaded, name) end end Compost:Reclaim(deps) end end end function FuBar:AceLibrary_Register(major, instance) if major == "Tablet-2.0" then Tablet = instance end end function FuBar:PLAYER_ENTERING_WORLD() if self.acePluginToLoad then for name in pairs(self.acePluginToLoad) do self:LoadPlugin(name) end Compost:Reclaim(self.acePluginToLoad) self.acePluginToLoad = nil end end function FuBar:RestartGx() self.hooks.RestartGx.orig() self:ScheduleEvent(self.Update, 0, self) end function FuBar:OnCVarUpdate() if arg1 == "USE_UISCALE" then self:ScheduleEvent(self.CheckResolution, 0, self) end end local lastScreenWidth = GetScreenWidth() function FuBar:CheckResolution() local screenWidth = GetScreenWidth() if lastScreenWidth ~= screenWidth then for i = 1, self:GetNumPanels() do self:GetPanel(i):Update() end lastScreenWidth = screenWidth Jostle:Refresh() end end local inTopPanel, inBottomPanel function FuBar:OnUpdate_AutoHideTop() if not inTopPanel and self:IsAutoHidingTop() then for i = 1, self:GetNumPanels() do if self:GetPanel(i):GetAttachPoint() == "TOP" then local frame = getglobal("FuBarFrame" .. i) frame:SetAlpha(0) frame:SetFrameStrata("BACKGROUND") end end end end function FuBar:OnUpdate_AutoHideBottom() if not inBottomPanel and self:IsAutoHidingBottom() then for i = 1, self:GetNumPanels() do if self:GetPanel(i):GetAttachPoint() == "BOTTOM" then local frame = getglobal("FuBarFrame" .. i) frame:SetAlpha(0) frame:SetFrameStrata("BACKGROUND") end end end end local doneSetupPlugins, pluginsToSetup function FuBar:OnDisable() for i = 1, self:GetNumPanels() do self:GetPanel(i).frame:Hide() end end function FuBar:Report() local report = Compost:Acquire( Compost:AcquireHash( 'text', self.loc.ARGUMENT_ADJUST, 'val', self:IsAdjust() and 1 or 0, 'map', self.loc.MAP_ONOFF ) ) self.cmd:report(report) Compost:Reclaim(report, 1) end function FuBar:GetNumPlugins() return table.getn(plugins) end function FuBar:GetPlugin(i) return plugins[i] end function FuBar:RegisterPlugin(plugin) if not IsCorrectPlugin(plugin) then return end table.insert(plugins, plugin) local frame = plugin:GetFrame() local downTime if frame:HasScript("OnClick") then local OnClick = frame:GetScript("OnClick") frame:SetScript("OnClick", function() if OnClick and (not downTime or GetTime() < downTime + 0.5) and (not this.stopClick or GetTime() > this.stopClick) then OnClick() end downTime = nil end) end local OnMouseDown = frame:GetScript("OnMouseDown") frame:SetScript("OnMouseDown", function() if arg1 == "LeftButton" and not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() then downTime = GetTime() FuBar:Plugin_StartDrag(plugin) end if OnMouseDown then OnMouseDown() end end) local OnMouseUp = frame:GetScript("OnMouseUp") frame:SetScript("OnMouseUp", function() if arg1 == "LeftButton" then if not FuBar:Plugin_StopDrag(plugin) then if OnMouseUp then OnMouseUp() end else this.stopClick = GetTime() + 0.05 end elseif OnMouseUp then OnMouseUp() end end) local OnEnter = frame:GetScript("OnEnter") frame:SetScript("OnEnter", function() FuBar:Panel_OnEnter(plugin) if OnEnter then OnEnter() end end) local OnLeave = frame:GetScript("OnLeave") frame:SetScript("OnLeave", function() FuBar:Panel_OnLeave(this.plugin) if OnLeave then OnLeave() end end) end function FuBar:Update() for panelId = 1, self:GetNumPanels() do self:GetPanel(panelId):Update() end end function FuBar:SetupPlugins() doneSetupPlugins = true if pluginsToSetup then for i = 1, self:GetNumPanels() do local panel = self:GetPanel(i) for h = 1, 3 do local side if h == 1 then side = "LEFT" elseif h == 2 then side = "CENTER" else side = "RIGHT" end local order = panel:GetSavedOrder(side) for _,name in ipairs(order) do for plugin in pairs(pluginsToSetup) do if not plugin:IsDisabled() and plugin:GetTitle() == name then if not panel:AddPlugin(plugin, nil, side) then doneSetupPlugins = false return end pluginsToSetup[plugin] = nil break end end end end end local order = self.db.profile.detached if order then for name in pairs(order) do for plugin in pairs(pluginsToSetup) do if not plugin:IsDisabled() and plugin:GetTitle() == name then pluginsToSetup[plugin] = nil plugin:Show(0) break end end end else self.db.profile.detached = {} end for plugin in pairs(pluginsToSetup) do if type(plugin.GetDefaultPosition) == "function" and plugin:GetDefaultPosition() == "MINIMAP" then plugin:Show(0) else self.lastPanelId = (self.lastPanelId or 0) + 1 if self.lastPanelId > self:GetNumPanels() then self.lastPanelId = 1 end self:GetPanel(self.lastPanelId):AddPlugin(plugin, nil, type(plugin.GetDefaultPosition) == "function" and plugin:GetDefaultPosition() or "LEFT", true) end end pluginsToSetup = nil end return true end function FuBar:ShowPlugin(plugin, panelId) if doneSetupPlugins then if not panelId then doneSetupPlugins = false pluginsToSetup = Compost:Acquire() pluginsToSetup[plugin] = true local function func() if not self:SetupPlugins() then self:ScheduleEvent(func, 0) return end self:Update() end func() else self:GetPanel(panelId):AddPlugin(plugin, nil, type(plugin.GetDefaultPosition) == "function" and plugin:GetDefaultPosition() or "LEFT", true) end else if not pluginsToSetup then pluginsToSetup = {} end pluginsToSetup[plugin] = true end end local previousPosition_panel, previousPosition_index, previousPosition_side, previousPosition_x, previousPosition_y function FuBar:Plugin_StartDrag(plugin) local panel = plugin:GetPanel() assert(panel, plugin:GetTitle() .. ": You must be attached to a panel.") self:Panel_OnLeave() local index, side = panel:IndexOfPlugin(plugin) if index then if not panel:IsLocked() then if index < panel:GetNumPlugins(side) then local frame = panel:GetPlugin(index + 1, side).frame local x, y = frame:GetLeft(), frame:GetBottom() frame:ClearAllPoints() frame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", x, y) end previousPosition_panel = panel previousPosition_index = index previousPosition_side = side previousPosition_x, previousPosition_y = self:GetScaledCursorPosition() FuBar_Panel:PreventUpdate() panel:RemovePlugin(index, side) plugin:GetFrame():StartMoving() end end end function FuBar:Plugin_StopDrag(plugin) plugin:GetFrame():StopMovingOrSizing() if previousPosition_panel and not previousPosition_panel:IsLocked() then local insertAt local panel = previousPosition_panel local side = previousPosition_side local x, y = self:GetScaledCursorPosition() local px, py = previousPosition_x, previousPosition_y for panelId = 1, self:GetNumPanels() do local p = self:GetPanel(panelId) local frame = p.frame local x1, x2, y1, y2 = frame:GetLeft(), frame:GetRight(), frame:GetBottom(), frame:GetTop() if x1 <= x and x <= x2 and y1 <= y and y <= y2 then panel = p break end end if panel:GetNumPlugins(side) == 0 then insertAt = 1 else for i = 1, panel:GetNumPlugins(side) + 1 do local left, right local leftPlugin local rightPlugin leftPlugin = panel:GetPlugin(i - 1, side) rightPlugin = panel:GetPlugin(i, side) if side == "RIGHT" then leftPlugin, rightPlugin = rightPlugin, leftPlugin end left = leftPlugin and leftPlugin:GetFrame():GetCenter() or 0 right = rightPlugin and rightPlugin:GetFrame():GetCenter() or GetScreenWidth() if left <= x and x <= right then insertAt = i break end end end if not insertAt then insertAt = panel:GetNumPlugins(side) + 1 end panel:AddPlugin(plugin, insertAt, side) FuBar_Panel:StopPreventUpdate() previousPosition_panel:Update() panel:Update() previousPosition_panel = nil previousPosition_index = nil previousPosition_side = nil previousPosition_x = nil previousPosition_y = nil if math.abs(px - x) <= 5 and math.abs(py - y) <= 5 then return false else return true end end end function FuBar:Panel_OnEnter(plugin) local point = plugin if type(plugin) == "table" then point = plugin:GetPanel():GetAttachPoint() end if point == "TOP" then inTopPanel = true self:CancelScheduledEvent("FuBar_AutoHideTop") elseif point == "BOTTOM" then inBottomPanel = true self:CancelScheduledEvent("FuBar_AutoHideBottom") end for i = 1, self:GetNumPanels() do local panel = self:GetPanel(i) if panel:GetAttachPoint() == point then panel.frame:SetAlpha(1) panel.frame:SetFrameStrata("HIGH") end end end function FuBar:Panel_OnLeave(plugin) local point = plugin if type(plugin) == "table" then if not plugin:GetPanel() then return end point = plugin:GetPanel():GetAttachPoint() end if point == "TOP" then inTopPanel = false self:ScheduleEvent("FuBar_AutoHideTop", self.OnUpdate_AutoHideTop, 1, self) elseif point == "BOTTOM" then inBottomPanel = false self:ScheduleEvent("FuBar_AutoHideBottom", self.OnUpdate_AutoHideBottom, 1, self) end end function FuBar:OnProfileEnable(oldName, _, copyFrom) isChangingProfile = true if not next(FuBar.db.profile) then local def local profile = self:GetProfile() if string.find(profile, "^char/") or string.find(profile, "^class/") then local _,class = UnitClass("player") def = _G["FUBAR_DEFAULTS_" .. class] or FUBAR_DEFAULTS else def = FUBAR_DEFAULTS end if type(def) == "function" then def = def() end for k,v in pairs(def) do FuBar.db.profile[k] = v end end if not self.db.profile.loadOnDemand then self.db.profile.loadOnDemand = {} end if not self.db.profile.tooltip then self.db.profile.tooltip = {} end if not self.db.profile.panels then self.db.profile.panels = {} end CleanDB() doneSetupPlugins = false pluginsToSetup = {} for i,plugin in ipairs(plugins) do pluginsToSetup[plugin] = true local frame = plugin:GetFrame() frame:Hide() frame:ClearAllPoints() plugin:SetPanel(nil) end for i = self:GetNumPanels(), 1, -1 do self:GetPanel(i):del(true) end for i = table.getn(self.db.profile.panels), 1, -1 do if self.db.profile.panels[i] then FuBar_Panel:new() end end if self:GetNumPanels() == 0 then FuBar_Panel:new() end self:CheckResolution() for i = 1, GetNumAddOns() do local name, title, notes, enabled, loadable, reason, security = GetAddOnInfo(i) if IsAddOnLoadOnDemand(i) and enabled and loadable and not IsAddOnLoaded(i) then local good = false for _,dep in ipairs({GetAddOnDependencies(name)}) do if dep == "FuBar" then good = true end end if good then if not self.db.profile.loadOnDemand[name] then self:LoadPlugin(name) elseif not self.db.profile.loadOnDemand[name].disabled and (not self.db.profile.loadOnDemand[name].condition or CheckLoadCondition(self.db.profile.loadOnDemand[name].condition)) then self:LoadPlugin(name) else local exists = false for _,n in ipairs(toBeLoaded) do if n == name then exists = true break end end if not exists then table.insert(toBeLoaded, name) end end end end end for i,plugin in ipairs(plugins) do if plugin.IsDisabled and plugin:IsDisabled() and plugin:GetPanel() then plugin:GetPanel():RemovePlugin(plugin) end end local name = self:GetProfile() for _,plugin in ipairs(plugins) do if type(plugin.SetProfile) == "function" and not plugin.independentProfile then plugin:SetProfile(name, copyFrom) end end self:SetFontSize(self:GetFontSize()) local function func() if not self:SetupPlugins() then self:ScheduleEvent(func, 0) return end self:Update() end self:ScheduleEvent(func, 0.01) isChangingProfile = false end